PageRenderTime 68ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/v5_6_1/sys/win32/msdev/jim/jim.c

#
C | 2239 lines | 1883 code | 143 blank | 213 comment | 378 complexity | efc0cf12e7ce9d30ea957191a3b7614c MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, Apache-2.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* Jim - A small embeddable Tcl interpreter
  2. * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
  3. * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
  4. *
  5. * $Id: jim.c 6455 2006-04-13 19:06:27Z arjenmarkus $
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * A copy of the license is also included in the source distribution
  14. * of Jim, as a TXT file name called LICENSE.
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. */
  22. #define __JIM_CORE__
  23. #define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */
  24. #ifndef JIM_ANSIC
  25. #define JIM_DYNLIB /* Dynamic library support for UNIX and WIN32 */
  26. #endif /* JIM_ANSIC */
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <stdarg.h>
  31. #include <ctype.h>
  32. #include <limits.h>
  33. #include <assert.h>
  34. #include <errno.h>
  35. #include <time.h>
  36. /* Include the platform dependent libraries for
  37. * dynamic loading of libraries. */
  38. #ifdef JIM_DYNLIB
  39. #if defined(_WIN32) || defined(WIN32)
  40. #ifndef WIN32
  41. #define WIN32 1
  42. #endif
  43. #define STRICT
  44. #define WIN32_LEAN_AND_MEAN
  45. #include <windows.h>
  46. #if _MSC_VER >= 1000
  47. #pragma warning(disable:4146)
  48. #endif /* _MSC_VER */
  49. #else
  50. #include <dlfcn.h>
  51. #endif /* WIN32 */
  52. #endif /* JIM_DYNLIB */
  53. #include "jim.h"
  54. #ifdef HAVE_BACKTRACE
  55. #include <execinfo.h>
  56. #endif
  57. /* -----------------------------------------------------------------------------
  58. * Global variables
  59. * ---------------------------------------------------------------------------*/
  60. /* A shared empty string for the objects string representation.
  61. * Jim_InvalidateStringRep knows about it and don't try to free. */
  62. static char *JimEmptyStringRep = (char*) "";
  63. /* -----------------------------------------------------------------------------
  64. * Required prototypes of not exported functions
  65. * ---------------------------------------------------------------------------*/
  66. static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
  67. static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
  68. static void JimRegisterCoreApi(Jim_Interp *interp);
  69. extern Jim_HashTableType JimVariablesHashTableType;
  70. /* -----------------------------------------------------------------------------
  71. * Utility functions
  72. * ---------------------------------------------------------------------------*/
  73. /*
  74. * Convert a string to a jim_wide INTEGER.
  75. * This function originates from BSD.
  76. *
  77. * Ignores `locale' stuff. Assumes that the upper and lower case
  78. * alphabets and digits are each contiguous.
  79. */
  80. #ifdef HAVE_LONG_LONG
  81. #define JimIsAscii(c) (((c) & ~0x7f) == 0)
  82. static jim_wide JimStrtoll(const char *nptr, char **endptr, register int base)
  83. {
  84. register const char *s;
  85. register unsigned jim_wide acc;
  86. register unsigned char c;
  87. register unsigned jim_wide qbase, cutoff;
  88. register int neg, any, cutlim;
  89. /*
  90. * Skip white space and pick up leading +/- sign if any.
  91. * If base is 0, allow 0x for hex and 0 for octal, else
  92. * assume decimal; if base is already 16, allow 0x.
  93. */
  94. s = nptr;
  95. do {
  96. c = *s++;
  97. } while (isspace(c));
  98. if (c == '-') {
  99. neg = 1;
  100. c = *s++;
  101. } else {
  102. neg = 0;
  103. if (c == '+')
  104. c = *s++;
  105. }
  106. if ((base == 0 || base == 16) &&
  107. c == '0' && (*s == 'x' || *s == 'X')) {
  108. c = s[1];
  109. s += 2;
  110. base = 16;
  111. }
  112. if (base == 0)
  113. base = c == '0' ? 8 : 10;
  114. /*
  115. * Compute the cutoff value between legal numbers and illegal
  116. * numbers. That is the largest legal value, divided by the
  117. * base. An input number that is greater than this value, if
  118. * followed by a legal input character, is too big. One that
  119. * is equal to this value may be valid or not; the limit
  120. * between valid and invalid numbers is then based on the last
  121. * digit. For instance, if the range for quads is
  122. * [-9223372036854775808..9223372036854775807] and the input base
  123. * is 10, cutoff will be set to 922337203685477580 and cutlim to
  124. * either 7 (neg==0) or 8 (neg==1), meaning that if we have
  125. * accumulated a value > 922337203685477580, or equal but the
  126. * next digit is > 7 (or 8), the number is too big, and we will
  127. * return a range error.
  128. *
  129. * Set any if any `digits' consumed; make it negative to indicate
  130. * overflow.
  131. */
  132. qbase = (unsigned)base;
  133. cutoff = neg ? (unsigned jim_wide)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
  134. : LLONG_MAX;
  135. cutlim = (int)(cutoff % qbase);
  136. cutoff /= qbase;
  137. for (acc = 0, any = 0;; c = *s++) {
  138. if (!JimIsAscii(c))
  139. break;
  140. if (isdigit(c))
  141. c -= '0';
  142. else if (isalpha(c))
  143. c -= isupper(c) ? 'A' - 10 : 'a' - 10;
  144. else
  145. break;
  146. if (c >= base)
  147. break;
  148. if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
  149. any = -1;
  150. else {
  151. any = 1;
  152. acc *= qbase;
  153. acc += c;
  154. }
  155. }
  156. if (any < 0) {
  157. acc = neg ? LLONG_MIN : LLONG_MAX;
  158. errno = ERANGE;
  159. } else if (neg)
  160. acc = -acc;
  161. if (endptr != 0)
  162. *endptr = (char *)(any ? s - 1 : nptr);
  163. return (acc);
  164. }
  165. #endif
  166. /* Glob-style pattern matching. */
  167. static int JimStringMatch(const char *pattern, int patternLen,
  168. const char *string, int stringLen, int nocase)
  169. {
  170. while(patternLen) {
  171. switch(pattern[0]) {
  172. case '*':
  173. while (pattern[1] == '*') {
  174. pattern++;
  175. patternLen--;
  176. }
  177. if (patternLen == 1)
  178. return 1; /* match */
  179. while(stringLen) {
  180. if (JimStringMatch(pattern+1, patternLen-1,
  181. string, stringLen, nocase))
  182. return 1; /* match */
  183. string++;
  184. stringLen--;
  185. }
  186. return 0; /* no match */
  187. break;
  188. case '?':
  189. if (stringLen == 0)
  190. return 0; /* no match */
  191. string++;
  192. stringLen--;
  193. break;
  194. case '[':
  195. {
  196. int not, match;
  197. pattern++;
  198. patternLen--;
  199. not = pattern[0] == '^';
  200. if (not) {
  201. pattern++;
  202. patternLen--;
  203. }
  204. match = 0;
  205. while(1) {
  206. if (pattern[0] == '\\') {
  207. pattern++;
  208. patternLen--;
  209. if (pattern[0] == string[0])
  210. match = 1;
  211. } else if (pattern[0] == ']') {
  212. break;
  213. } else if (patternLen == 0) {
  214. pattern--;
  215. patternLen++;
  216. break;
  217. } else if (pattern[1] == '-' && patternLen >= 3) {
  218. int start = pattern[0];
  219. int end = pattern[2];
  220. int c = string[0];
  221. if (start > end) {
  222. int t = start;
  223. start = end;
  224. end = t;
  225. }
  226. if (nocase) {
  227. start = tolower(start);
  228. end = tolower(end);
  229. c = tolower(c);
  230. }
  231. pattern += 2;
  232. patternLen -= 2;
  233. if (c >= start && c <= end)
  234. match = 1;
  235. } else {
  236. if (!nocase) {
  237. if (pattern[0] == string[0])
  238. match = 1;
  239. } else {
  240. if (tolower((int)pattern[0]) == tolower((int)string[0]))
  241. match = 1;
  242. }
  243. }
  244. pattern++;
  245. patternLen--;
  246. }
  247. if (not)
  248. match = !match;
  249. if (!match)
  250. return 0; /* no match */
  251. string++;
  252. stringLen--;
  253. break;
  254. }
  255. case '\\':
  256. if (patternLen >= 2) {
  257. pattern++;
  258. patternLen--;
  259. }
  260. /* fall through */
  261. default:
  262. if (!nocase) {
  263. if (pattern[0] != string[0])
  264. return 0; /* no match */
  265. } else {
  266. if (tolower((int)pattern[0]) != tolower((int)string[0]))
  267. return 0; /* no match */
  268. }
  269. string++;
  270. stringLen--;
  271. break;
  272. }
  273. pattern++;
  274. patternLen--;
  275. if (stringLen == 0) {
  276. while(*pattern == '*') {
  277. pattern++;
  278. patternLen--;
  279. }
  280. break;
  281. }
  282. }
  283. if (patternLen == 0 && stringLen == 0)
  284. return 1;
  285. return 0;
  286. }
  287. int JimStringCompare(const char *s1, int l1, const char *s2, int l2,
  288. int nocase)
  289. {
  290. unsigned char *u1 = (unsigned char*) s1, *u2 = (unsigned char*) s2;
  291. if (nocase == 0) {
  292. while(l1 && l2) {
  293. if (*u1 != *u2)
  294. return (int)*u1-*u2;
  295. u1++; u2++; l1--; l2--;
  296. }
  297. if (!l1 && !l2) return 0;
  298. return l1-l2;
  299. } else {
  300. while(l1 && l2) {
  301. if (tolower((int)*u1) != tolower((int)*u2))
  302. return tolower((int)*u1)-tolower((int)*u2);
  303. u1++; u2++; l1--; l2--;
  304. }
  305. if (!l1 && !l2) return 0;
  306. return l1-l2;
  307. }
  308. }
  309. /* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
  310. * The index of the first occurrence of s1 in s2 is returned.
  311. * If s1 is not found inside s2, -1 is returned. */
  312. int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int index)
  313. {
  314. int i;
  315. if (!l1 || !l2 || l1 > l2) return -1;
  316. if (index < 0) index = 0;
  317. s2 += index;
  318. for (i = index; i <= l2-l1; i++) {
  319. if (memcmp(s2, s1, l1) == 0)
  320. return i;
  321. s2++;
  322. }
  323. return -1;
  324. }
  325. int Jim_WideToString(char *buf, jim_wide wideValue)
  326. {
  327. const char *fmt = "%" JIM_WIDE_MODIFIER;
  328. return sprintf(buf, fmt, wideValue);
  329. }
  330. int Jim_StringToWide(const char *str, jim_wide *widePtr, int base)
  331. {
  332. char *endptr;
  333. #ifdef HAVE_LONG_LONG
  334. *widePtr = JimStrtoll(str, &endptr, base);
  335. #else
  336. *widePtr = strtol(str, &endptr, base);
  337. #endif
  338. if (str[0] == '\0')
  339. return JIM_ERR;
  340. if (endptr[0] != '\0') {
  341. while(*endptr) {
  342. if (!isspace((int)*endptr))
  343. return JIM_ERR;
  344. endptr++;
  345. }
  346. }
  347. return JIM_OK;
  348. }
  349. int Jim_StringToIndex(const char *str, int *intPtr)
  350. {
  351. char *endptr;
  352. *intPtr = strtol(str, &endptr, 10);
  353. if (str[0] == '\0')
  354. return JIM_ERR;
  355. if (endptr[0] != '\0') {
  356. while(*endptr) {
  357. if (!isspace((int)*endptr))
  358. return JIM_ERR;
  359. endptr++;
  360. }
  361. }
  362. return JIM_OK;
  363. }
  364. /* The string representation of references has two features in order
  365. * to make the GC faster. The first is that every reference starts
  366. * with a non common character '~', in order to make the string matching
  367. * fater. The second is that the reference string rep his 32 characters
  368. * in length, this allows to avoid to check every object with a string
  369. * repr < 32, and usually there are many of this objects. */
  370. #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
  371. static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
  372. {
  373. const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
  374. sprintf(buf, fmt, refPtr->tag, id);
  375. return JIM_REFERENCE_SPACE;
  376. }
  377. int Jim_DoubleToString(char *buf, double doubleValue)
  378. {
  379. char *s;
  380. int len;
  381. len = sprintf(buf, "%.17g", doubleValue);
  382. s = buf;
  383. while(*s) {
  384. if (*s == '.') return len;
  385. s++;
  386. }
  387. /* Add a final ".0" if it's a number. But not
  388. * for NaN or InF */
  389. if (isdigit((int)buf[0])
  390. || ((buf[0] == '-' || buf[0] == '+')
  391. && isdigit((int)buf[1]))) {
  392. s[0] = '.';
  393. s[1] = '0';
  394. s[2] = '\0';
  395. return len+2;
  396. }
  397. return len;
  398. }
  399. int Jim_StringToDouble(const char *str, double *doublePtr)
  400. {
  401. char *endptr;
  402. *doublePtr = strtod(str, &endptr);
  403. if (str[0] == '\0' || endptr[0] != '\0')
  404. return JIM_ERR;
  405. return JIM_OK;
  406. }
  407. static jim_wide JimPowWide(jim_wide b, jim_wide e)
  408. {
  409. jim_wide i, res = 1;
  410. if ((b==0 && e!=0) || (e<0)) return 0;
  411. for(i=0; i<e; i++) {res *= b;}
  412. return res;
  413. }
  414. /* -----------------------------------------------------------------------------
  415. * Special functions
  416. * ---------------------------------------------------------------------------*/
  417. void Jim_Panic(const char *fmt, ...)
  418. {
  419. va_list ap;
  420. va_start(ap, fmt);
  421. fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
  422. vfprintf(stderr, fmt, ap);
  423. fprintf(stderr, "\n\n");
  424. va_end(ap);
  425. #ifdef HAVE_BACKTRACE
  426. {
  427. void *array[40];
  428. int size, i;
  429. char **strings;
  430. size = backtrace(array, 40);
  431. strings = backtrace_symbols(array, size);
  432. for (i = 0; i < size; i++)
  433. printf("[backtrace] %s\n", strings[i]);
  434. printf("[backtrace] Include the above lines and the output\n");
  435. printf("[backtrace] of 'nm <executable>' in the bug report.\n");
  436. }
  437. #endif
  438. abort();
  439. }
  440. /* -----------------------------------------------------------------------------
  441. * Memory allocation
  442. * ---------------------------------------------------------------------------*/
  443. /* Macro used for memory debugging.
  444. * In order for they to work you have to rename Jim_Alloc into _Jim_Alloc
  445. * and similary for Jim_Realloc and Jim_Free */
  446. #if 0
  447. #define Jim_Alloc(s) (printf("%s %d: Jim_Alloc(%d)\n",__FILE__,__LINE__,s),_Jim_Alloc(s))
  448. #define Jim_Free(p) (printf("%s %d: Jim_Free(%p)\n",__FILE__,__LINE__,p),_Jim_Free(p))
  449. #define Jim_Realloc(p,s) (printf("%s %d: Jim_Realloc(%p,%d)\n",__FILE__,__LINE__,p,s),_Jim_Realloc(p,s))
  450. #endif
  451. void *Jim_Alloc(int size)
  452. {
  453. void *p = malloc(size);
  454. if (p == NULL)
  455. Jim_Panic("Out of memory");
  456. return p;
  457. }
  458. void Jim_Free(void *ptr) {
  459. free(ptr);
  460. }
  461. void *Jim_Realloc(void *ptr, int size)
  462. {
  463. void *p = realloc(ptr, size);
  464. if (p == NULL)
  465. Jim_Panic("Out of memory");
  466. return p;
  467. }
  468. char *Jim_StrDup(const char *s)
  469. {
  470. int l = strlen(s);
  471. char *copy = Jim_Alloc(l+1);
  472. memcpy(copy, s, l+1);
  473. return copy;
  474. }
  475. char *Jim_StrDupLen(const char *s, int l)
  476. {
  477. char *copy = Jim_Alloc(l+1);
  478. memcpy(copy, s, l+1);
  479. copy[l] = 0; /* Just to be sure, original could be substring */
  480. return copy;
  481. }
  482. /* -----------------------------------------------------------------------------
  483. * Time related functions
  484. * ---------------------------------------------------------------------------*/
  485. /* Returns microseconds of CPU used since start. */
  486. static jim_wide JimClock(void)
  487. {
  488. #if (defined WIN32) && !(defined JIM_ANSIC)
  489. LARGE_INTEGER t, f;
  490. QueryPerformanceFrequency(&f);
  491. QueryPerformanceCounter(&t);
  492. return (long)((t.QuadPart * 1000000) / f.QuadPart);
  493. #else /* !WIN32 */
  494. clock_t clocks = clock();
  495. return (long)(clocks*(1000000/CLOCKS_PER_SEC));
  496. #endif /* WIN32 */
  497. }
  498. /* -----------------------------------------------------------------------------
  499. * Hash Tables
  500. * ---------------------------------------------------------------------------*/
  501. /* -------------------------- private prototypes ---------------------------- */
  502. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
  503. static unsigned int JimHashTableNextPower(unsigned int size);
  504. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
  505. /* -------------------------- hash functions -------------------------------- */
  506. /* Thomas Wang's 32 bit Mix Function */
  507. unsigned int Jim_IntHashFunction(unsigned int key)
  508. {
  509. key += ~(key << 15);
  510. key ^= (key >> 10);
  511. key += (key << 3);
  512. key ^= (key >> 6);
  513. key += ~(key << 11);
  514. key ^= (key >> 16);
  515. return key;
  516. }
  517. /* Identity hash function for integer keys */
  518. unsigned int Jim_IdentityHashFunction(unsigned int key)
  519. {
  520. return key;
  521. }
  522. /* Generic hash function (we are using to multiply by 9 and add the byte
  523. * as Tcl) */
  524. unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
  525. {
  526. unsigned int h = 0;
  527. while(len--)
  528. h += (h<<3)+*buf++;
  529. return h;
  530. }
  531. /* ----------------------------- API implementation ------------------------- */
  532. /* reset an hashtable already initialized with ht_init().
  533. * NOTE: This function should only called by ht_destroy(). */
  534. static void JimResetHashTable(Jim_HashTable *ht)
  535. {
  536. ht->table = NULL;
  537. ht->size = 0;
  538. ht->sizemask = 0;
  539. ht->used = 0;
  540. ht->collisions = 0;
  541. }
  542. /* Initialize the hash table */
  543. int Jim_InitHashTable(Jim_HashTable *ht, Jim_HashTableType *type,
  544. void *privDataPtr)
  545. {
  546. JimResetHashTable(ht);
  547. ht->type = type;
  548. ht->privdata = privDataPtr;
  549. return JIM_OK;
  550. }
  551. /* Resize the table to the minimal size that contains all the elements,
  552. * but with the invariant of a USER/BUCKETS ration near to <= 1 */
  553. int Jim_ResizeHashTable(Jim_HashTable *ht)
  554. {
  555. int minimal = ht->used;
  556. if (minimal < JIM_HT_INITIAL_SIZE)
  557. minimal = JIM_HT_INITIAL_SIZE;
  558. return Jim_ExpandHashTable(ht, minimal);
  559. }
  560. /* Expand or create the hashtable */
  561. int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
  562. {
  563. Jim_HashTable n; /* the new hashtable */
  564. unsigned int realsize = JimHashTableNextPower(size), i;
  565. /* the size is invalid if it is smaller than the number of
  566. * elements already inside the hashtable */
  567. if (ht->used >= size)
  568. return JIM_ERR;
  569. Jim_InitHashTable(&n, ht->type, ht->privdata);
  570. n.size = realsize;
  571. n.sizemask = realsize-1;
  572. n.table = Jim_Alloc(realsize*sizeof(Jim_HashEntry*));
  573. /* Initialize all the pointers to NULL */
  574. memset(n.table, 0, realsize*sizeof(Jim_HashEntry*));
  575. /* Copy all the elements from the old to the new table:
  576. * note that if the old hash table is empty ht->size is zero,
  577. * so Jim_ExpandHashTable just creates an hash table. */
  578. n.used = ht->used;
  579. for (i = 0; i < ht->size && ht->used > 0; i++) {
  580. Jim_HashEntry *he, *nextHe;
  581. if (ht->table[i] == NULL) continue;
  582. /* For each hash entry on this slot... */
  583. he = ht->table[i];
  584. while(he) {
  585. unsigned int h;
  586. nextHe = he->next;
  587. /* Get the new element index */
  588. h = Jim_HashKey(ht, he->key) & n.sizemask;
  589. he->next = n.table[h];
  590. n.table[h] = he;
  591. ht->used--;
  592. /* Pass to the next element */
  593. he = nextHe;
  594. }
  595. }
  596. assert(ht->used == 0);
  597. Jim_Free(ht->table);
  598. /* Remap the new hashtable in the old */
  599. *ht = n;
  600. return JIM_OK;
  601. }
  602. /* Add an element to the target hash table */
  603. int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
  604. {
  605. int index;
  606. Jim_HashEntry *entry;
  607. /* Get the index of the new element, or -1 if
  608. * the element already exists. */
  609. if ((index = JimInsertHashEntry(ht, key)) == -1)
  610. return JIM_ERR;
  611. /* Allocates the memory and stores key */
  612. entry = Jim_Alloc(sizeof(*entry));
  613. entry->next = ht->table[index];
  614. ht->table[index] = entry;
  615. /* Set the hash entry fields. */
  616. Jim_SetHashKey(ht, entry, key);
  617. Jim_SetHashVal(ht, entry, val);
  618. ht->used++;
  619. return JIM_OK;
  620. }
  621. /* Add an element, discarding the old if the key already exists */
  622. int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
  623. {
  624. Jim_HashEntry *entry;
  625. /* Try to add the element. If the key
  626. * does not exists Jim_AddHashEntry will suceed. */
  627. if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
  628. return JIM_OK;
  629. /* It already exists, get the entry */
  630. entry = Jim_FindHashEntry(ht, key);
  631. /* Free the old value and set the new one */
  632. Jim_FreeEntryVal(ht, entry);
  633. Jim_SetHashVal(ht, entry, val);
  634. return JIM_OK;
  635. }
  636. /* Search and remove an element */
  637. int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
  638. {
  639. unsigned int h;
  640. Jim_HashEntry *he, *prevHe;
  641. if (ht->size == 0)
  642. return JIM_ERR;
  643. h = Jim_HashKey(ht, key) & ht->sizemask;
  644. he = ht->table[h];
  645. prevHe = NULL;
  646. while(he) {
  647. if (Jim_CompareHashKeys(ht, key, he->key)) {
  648. /* Unlink the element from the list */
  649. if (prevHe)
  650. prevHe->next = he->next;
  651. else
  652. ht->table[h] = he->next;
  653. Jim_FreeEntryKey(ht, he);
  654. Jim_FreeEntryVal(ht, he);
  655. Jim_Free(he);
  656. ht->used--;
  657. return JIM_OK;
  658. }
  659. prevHe = he;
  660. he = he->next;
  661. }
  662. return JIM_ERR; /* not found */
  663. }
  664. /* Destroy an entire hash table */
  665. int Jim_FreeHashTable(Jim_HashTable *ht)
  666. {
  667. unsigned int i;
  668. /* Free all the elements */
  669. for (i = 0; i < ht->size && ht->used > 0; i++) {
  670. Jim_HashEntry *he, *nextHe;
  671. if ((he = ht->table[i]) == NULL) continue;
  672. while(he) {
  673. nextHe = he->next;
  674. Jim_FreeEntryKey(ht, he);
  675. Jim_FreeEntryVal(ht, he);
  676. Jim_Free(he);
  677. ht->used--;
  678. he = nextHe;
  679. }
  680. }
  681. /* Free the table and the allocated cache structure */
  682. Jim_Free(ht->table);
  683. /* Re-initialize the table */
  684. JimResetHashTable(ht);
  685. return JIM_OK; /* never fails */
  686. }
  687. Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
  688. {
  689. Jim_HashEntry *he;
  690. unsigned int h;
  691. if (ht->size == 0) return NULL;
  692. h = Jim_HashKey(ht, key) & ht->sizemask;
  693. he = ht->table[h];
  694. while(he) {
  695. if (Jim_CompareHashKeys(ht, key, he->key))
  696. return he;
  697. he = he->next;
  698. }
  699. return NULL;
  700. }
  701. Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
  702. {
  703. Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
  704. iter->ht = ht;
  705. iter->index = -1;
  706. iter->entry = NULL;
  707. iter->nextEntry = NULL;
  708. return iter;
  709. }
  710. Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
  711. {
  712. while (1) {
  713. if (iter->entry == NULL) {
  714. iter->index++;
  715. if (iter->index >=
  716. (signed)iter->ht->size) break;
  717. iter->entry = iter->ht->table[iter->index];
  718. } else {
  719. iter->entry = iter->nextEntry;
  720. }
  721. if (iter->entry) {
  722. /* We need to save the 'next' here, the iterator user
  723. * may delete the entry we are returning. */
  724. iter->nextEntry = iter->entry->next;
  725. return iter->entry;
  726. }
  727. }
  728. return NULL;
  729. }
  730. /* ------------------------- private functions ------------------------------ */
  731. /* Expand the hash table if needed */
  732. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
  733. {
  734. /* If the hash table is empty expand it to the intial size,
  735. * if the table is "full" dobule its size. */
  736. if (ht->size == 0)
  737. return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
  738. if (ht->size == ht->used)
  739. return Jim_ExpandHashTable(ht, ht->size*2);
  740. return JIM_OK;
  741. }
  742. /* Our hash table capability is a power of two */
  743. static unsigned int JimHashTableNextPower(unsigned int size)
  744. {
  745. unsigned int i = JIM_HT_INITIAL_SIZE;
  746. if (size >= 2147483648U)
  747. return 2147483648U;
  748. while(1) {
  749. if (i >= size)
  750. return i;
  751. i *= 2;
  752. }
  753. }
  754. /* Returns the index of a free slot that can be populated with
  755. * an hash entry for the given 'key'.
  756. * If the key already exists, -1 is returned. */
  757. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
  758. {
  759. unsigned int h;
  760. Jim_HashEntry *he;
  761. /* Expand the hashtable if needed */
  762. if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
  763. return -1;
  764. /* Compute the key hash value */
  765. h = Jim_HashKey(ht, key) & ht->sizemask;
  766. /* Search if this slot does not already contain the given key */
  767. he = ht->table[h];
  768. while(he) {
  769. if (Jim_CompareHashKeys(ht, key, he->key))
  770. return -1;
  771. he = he->next;
  772. }
  773. return h;
  774. }
  775. /* ----------------------- StringCopy Hash Table Type ------------------------*/
  776. static unsigned int JimStringCopyHTHashFunction(const void *key)
  777. {
  778. return Jim_GenHashFunction(key, strlen(key));
  779. }
  780. static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
  781. {
  782. int len = strlen(key);
  783. char *copy = Jim_Alloc(len+1);
  784. JIM_NOTUSED(privdata);
  785. memcpy(copy, key, len);
  786. copy[len] = '\0';
  787. return copy;
  788. }
  789. static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
  790. {
  791. int len = strlen(val);
  792. char *copy = Jim_Alloc(len+1);
  793. JIM_NOTUSED(privdata);
  794. memcpy(copy, val, len);
  795. copy[len] = '\0';
  796. return copy;
  797. }
  798. static int JimStringCopyHTKeyCompare(void *privdata, const void *key1,
  799. const void *key2)
  800. {
  801. JIM_NOTUSED(privdata);
  802. return strcmp(key1, key2) == 0;
  803. }
  804. static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
  805. {
  806. JIM_NOTUSED(privdata);
  807. Jim_Free((void*)key); /* ATTENTION: const cast */
  808. }
  809. static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
  810. {
  811. JIM_NOTUSED(privdata);
  812. Jim_Free((void*)val); /* ATTENTION: const cast */
  813. }
  814. static Jim_HashTableType JimStringCopyHashTableType = {
  815. JimStringCopyHTHashFunction, /* hash function */
  816. JimStringCopyHTKeyDup, /* key dup */
  817. NULL, /* val dup */
  818. JimStringCopyHTKeyCompare, /* key compare */
  819. JimStringCopyHTKeyDestructor, /* key destructor */
  820. NULL /* val destructor */
  821. };
  822. /* This is like StringCopy but does not auto-duplicate the key.
  823. * It's used for intepreter's shared strings. */
  824. static Jim_HashTableType JimSharedStringsHashTableType = {
  825. JimStringCopyHTHashFunction, /* hash function */
  826. NULL, /* key dup */
  827. NULL, /* val dup */
  828. JimStringCopyHTKeyCompare, /* key compare */
  829. JimStringCopyHTKeyDestructor, /* key destructor */
  830. NULL /* val destructor */
  831. };
  832. /* This is like StringCopy but also automatically handle dynamic
  833. * allocated C strings as values. */
  834. static Jim_HashTableType JimStringKeyValCopyHashTableType = {
  835. JimStringCopyHTHashFunction, /* hash function */
  836. JimStringCopyHTKeyDup, /* key dup */
  837. JimStringKeyValCopyHTValDup, /* val dup */
  838. JimStringCopyHTKeyCompare, /* key compare */
  839. JimStringCopyHTKeyDestructor, /* key destructor */
  840. JimStringKeyValCopyHTValDestructor, /* val destructor */
  841. };
  842. typedef struct AssocDataValue {
  843. Jim_InterpDeleteProc *delProc;
  844. void *data;
  845. } AssocDataValue;
  846. static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
  847. {
  848. AssocDataValue *assocPtr = (AssocDataValue *)data;
  849. if (assocPtr->delProc != NULL)
  850. assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
  851. Jim_Free(data);
  852. }
  853. static Jim_HashTableType JimAssocDataHashTableType = {
  854. JimStringCopyHTHashFunction, /* hash function */
  855. JimStringCopyHTKeyDup, /* key dup */
  856. NULL, /* val dup */
  857. JimStringCopyHTKeyCompare, /* key compare */
  858. JimStringCopyHTKeyDestructor, /* key destructor */
  859. JimAssocDataHashTableValueDestructor /* val destructor */
  860. };
  861. /* -----------------------------------------------------------------------------
  862. * Stack - This is a simple generic stack implementation. It is used for
  863. * example in the 'expr' expression compiler.
  864. * ---------------------------------------------------------------------------*/
  865. void Jim_InitStack(Jim_Stack *stack)
  866. {
  867. stack->len = 0;
  868. stack->maxlen = 0;
  869. stack->vector = NULL;
  870. }
  871. void Jim_FreeStack(Jim_Stack *stack)
  872. {
  873. Jim_Free(stack->vector);
  874. }
  875. int Jim_StackLen(Jim_Stack *stack)
  876. {
  877. return stack->len;
  878. }
  879. void Jim_StackPush(Jim_Stack *stack, void *element) {
  880. int neededLen = stack->len+1;
  881. if (neededLen > stack->maxlen) {
  882. stack->maxlen = neededLen*2;
  883. stack->vector = Jim_Realloc(stack->vector, sizeof(void*)*stack->maxlen);
  884. }
  885. stack->vector[stack->len] = element;
  886. stack->len++;
  887. }
  888. void *Jim_StackPop(Jim_Stack *stack)
  889. {
  890. if (stack->len == 0) return NULL;
  891. stack->len--;
  892. return stack->vector[stack->len];
  893. }
  894. void *Jim_StackPeek(Jim_Stack *stack)
  895. {
  896. if (stack->len == 0) return NULL;
  897. return stack->vector[stack->len-1];
  898. }
  899. void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr))
  900. {
  901. int i;
  902. for (i = 0; i < stack->len; i++)
  903. freeFunc(stack->vector[i]);
  904. }
  905. /* -----------------------------------------------------------------------------
  906. * Parser
  907. * ---------------------------------------------------------------------------*/
  908. /* Token types */
  909. #define JIM_TT_NONE -1 /* No token returned */
  910. #define JIM_TT_STR 0 /* simple string */
  911. #define JIM_TT_ESC 1 /* string that needs escape chars conversion */
  912. #define JIM_TT_VAR 2 /* var substitution */
  913. #define JIM_TT_DICTSUGAR 3 /* Syntax sugar for [dict get], $foo(bar) */
  914. #define JIM_TT_CMD 4 /* command substitution */
  915. #define JIM_TT_SEP 5 /* word separator */
  916. #define JIM_TT_EOL 6 /* line separator */
  917. /* Additional token types needed for expressions */
  918. #define JIM_TT_SUBEXPR_START 7
  919. #define JIM_TT_SUBEXPR_END 8
  920. #define JIM_TT_EXPR_NUMBER 9
  921. #define JIM_TT_EXPR_OPERATOR 10
  922. /* Parser states */
  923. #define JIM_PS_DEF 0 /* Default state */
  924. #define JIM_PS_QUOTE 1 /* Inside "" */
  925. /* Parser context structure. The same context is used both to parse
  926. * Tcl scripts and lists. */
  927. struct JimParserCtx {
  928. const char *prg; /* Program text */
  929. const char *p; /* Pointer to the point of the program we are parsing */
  930. int len; /* Left length of 'prg' */
  931. int linenr; /* Current line number */
  932. const char *tstart;
  933. const char *tend; /* Returned token is at tstart-tend in 'prg'. */
  934. int tline; /* Line number of the returned token */
  935. int tt; /* Token type */
  936. int eof; /* Non zero if EOF condition is true. */
  937. int state; /* Parser state */
  938. int comment; /* Non zero if the next chars may be a comment. */
  939. };
  940. #define JimParserEof(c) ((c)->eof)
  941. #define JimParserTstart(c) ((c)->tstart)
  942. #define JimParserTend(c) ((c)->tend)
  943. #define JimParserTtype(c) ((c)->tt)
  944. #define JimParserTline(c) ((c)->tline)
  945. static int JimParseScript(struct JimParserCtx *pc);
  946. static int JimParseSep(struct JimParserCtx *pc);
  947. static int JimParseEol(struct JimParserCtx *pc);
  948. static int JimParseCmd(struct JimParserCtx *pc);
  949. static int JimParseVar(struct JimParserCtx *pc);
  950. static int JimParseBrace(struct JimParserCtx *pc);
  951. static int JimParseStr(struct JimParserCtx *pc);
  952. static int JimParseComment(struct JimParserCtx *pc);
  953. static char *JimParserGetToken(struct JimParserCtx *pc,
  954. int *lenPtr, int *typePtr, int *linePtr);
  955. /* Initialize a parser context.
  956. * 'prg' is a pointer to the program text, linenr is the line
  957. * number of the first line contained in the program. */
  958. void JimParserInit(struct JimParserCtx *pc, const char *prg,
  959. int len, int linenr)
  960. {
  961. pc->prg = prg;
  962. pc->p = prg;
  963. pc->len = len;
  964. pc->tstart = NULL;
  965. pc->tend = NULL;
  966. pc->tline = 0;
  967. pc->tt = JIM_TT_NONE;
  968. pc->eof = 0;
  969. pc->state = JIM_PS_DEF;
  970. pc->linenr = linenr;
  971. pc->comment = 1;
  972. }
  973. int JimParseScript(struct JimParserCtx *pc)
  974. {
  975. while(1) { /* the while is used to reiterate with continue if needed */
  976. if (!pc->len) {
  977. pc->tstart = pc->p;
  978. pc->tend = pc->p-1;
  979. pc->tline = pc->linenr;
  980. pc->tt = JIM_TT_EOL;
  981. pc->eof = 1;
  982. return JIM_OK;
  983. }
  984. switch(*(pc->p)) {
  985. case '\\':
  986. if (*(pc->p+1) == '\n')
  987. return JimParseSep(pc);
  988. else {
  989. pc->comment = 0;
  990. return JimParseStr(pc);
  991. }
  992. break;
  993. case ' ':
  994. case '\t':
  995. case '\r':
  996. if (pc->state == JIM_PS_DEF)
  997. return JimParseSep(pc);
  998. else {
  999. pc->comment = 0;
  1000. return JimParseStr(pc);
  1001. }
  1002. break;
  1003. case '\n':
  1004. case ';':
  1005. pc->comment = 1;
  1006. if (pc->state == JIM_PS_DEF)
  1007. return JimParseEol(pc);
  1008. else
  1009. return JimParseStr(pc);
  1010. break;
  1011. case '[':
  1012. pc->comment = 0;
  1013. return JimParseCmd(pc);
  1014. break;
  1015. case '$':
  1016. pc->comment = 0;
  1017. if (JimParseVar(pc) == JIM_ERR) {
  1018. pc->tstart = pc->tend = pc->p++; pc->len--;
  1019. pc->tline = pc->linenr;
  1020. pc->tt = JIM_TT_STR;
  1021. return JIM_OK;
  1022. } else
  1023. return JIM_OK;
  1024. break;
  1025. case '#':
  1026. if (pc->comment) {
  1027. JimParseComment(pc);
  1028. continue;
  1029. } else {
  1030. return JimParseStr(pc);
  1031. }
  1032. default:
  1033. pc->comment = 0;
  1034. return JimParseStr(pc);
  1035. break;
  1036. }
  1037. return JIM_OK;
  1038. }
  1039. }
  1040. int JimParseSep(struct JimParserCtx *pc)
  1041. {
  1042. pc->tstart = pc->p;
  1043. pc->tline = pc->linenr;
  1044. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
  1045. (*pc->p == '\\' && *(pc->p+1) == '\n')) {
  1046. if (*pc->p == '\\') {
  1047. pc->p++; pc->len--;
  1048. pc->linenr++;
  1049. }
  1050. pc->p++; pc->len--;
  1051. }
  1052. pc->tend = pc->p-1;
  1053. pc->tt = JIM_TT_SEP;
  1054. return JIM_OK;
  1055. }
  1056. int JimParseEol(struct JimParserCtx *pc)
  1057. {
  1058. pc->tstart = pc->p;
  1059. pc->tline = pc->linenr;
  1060. while (*pc->p == ' ' || *pc->p == '\n' ||
  1061. *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
  1062. if (*pc->p == '\n')
  1063. pc->linenr++;
  1064. pc->p++; pc->len--;
  1065. }
  1066. pc->tend = pc->p-1;
  1067. pc->tt = JIM_TT_EOL;
  1068. return JIM_OK;
  1069. }
  1070. /* Todo. Don't stop if ']' appears inside {} or quoted.
  1071. * Also should handle the case of puts [string length "]"] */
  1072. int JimParseCmd(struct JimParserCtx *pc)
  1073. {
  1074. int level = 1;
  1075. int blevel = 0;
  1076. pc->tstart = ++pc->p; pc->len--;
  1077. pc->tline = pc->linenr;
  1078. while (1) {
  1079. if (pc->len == 0) {
  1080. break;
  1081. } else if (*pc->p == '[' && blevel == 0) {
  1082. level++;
  1083. } else if (*pc->p == ']' && blevel == 0) {
  1084. level--;
  1085. if (!level) break;
  1086. } else if (*pc->p == '\\') {
  1087. pc->p++; pc->len--;
  1088. } else if (*pc->p == '{') {
  1089. blevel++;
  1090. } else if (*pc->p == '}') {
  1091. if (blevel != 0)
  1092. blevel--;
  1093. } else if (*pc->p == '\n')
  1094. pc->linenr++;
  1095. pc->p++; pc->len--;
  1096. }
  1097. pc->tend = pc->p-1;
  1098. pc->tt = JIM_TT_CMD;
  1099. if (*pc->p == ']') {
  1100. pc->p++; pc->len--;
  1101. }
  1102. return JIM_OK;
  1103. }
  1104. int JimParseVar(struct JimParserCtx *pc)
  1105. {
  1106. int brace = 0, stop = 0, ttype = JIM_TT_VAR;
  1107. pc->tstart = ++pc->p; pc->len--; /* skip the $ */
  1108. pc->tline = pc->linenr;
  1109. if (*pc->p == '{') {
  1110. pc->tstart = ++pc->p; pc->len--;
  1111. brace = 1;
  1112. }
  1113. if (brace) {
  1114. while (!stop) {
  1115. if (*pc->p == '}' || pc->len == 0) {
  1116. stop = 1;
  1117. if (pc->len == 0)
  1118. continue;
  1119. }
  1120. else if (*pc->p == '\n')
  1121. pc->linenr++;
  1122. pc->p++; pc->len--;
  1123. }
  1124. if (pc->len == 0)
  1125. pc->tend = pc->p-1;
  1126. else
  1127. pc->tend = pc->p-2;
  1128. } else {
  1129. while (!stop) {
  1130. if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
  1131. (*pc->p >= 'A' && *pc->p <= 'Z') ||
  1132. (*pc->p >= '0' && *pc->p <= '9') || *pc->p == '_'))
  1133. stop = 1;
  1134. else {
  1135. pc->p++; pc->len--;
  1136. }
  1137. }
  1138. /* Parse [dict get] syntax sugar. */
  1139. if (*pc->p == '(') {
  1140. while (*pc->p != ')' && pc->len) {
  1141. pc->p++; pc->len--;
  1142. if (*pc->p == '\\' && pc->len >= 2) {
  1143. pc->p += 2; pc->len -= 2;
  1144. }
  1145. }
  1146. if (*pc->p != '\0') {
  1147. pc->p++; pc->len--;
  1148. }
  1149. ttype = JIM_TT_DICTSUGAR;
  1150. }
  1151. pc->tend = pc->p-1;
  1152. }
  1153. /* Check if we parsed just the '$' character.
  1154. * That's not a variable so an error is returned
  1155. * to tell the state machine to consider this '$' just
  1156. * a string. */
  1157. if (pc->tstart == pc->p) {
  1158. pc->p--; pc->len++;
  1159. return JIM_ERR;
  1160. }
  1161. pc->tt = ttype;
  1162. return JIM_OK;
  1163. }
  1164. int JimParseBrace(struct JimParserCtx *pc)
  1165. {
  1166. int level = 1;
  1167. pc->tstart = ++pc->p; pc->len--;
  1168. pc->tline = pc->linenr;
  1169. while (1) {
  1170. if (*pc->p == '\\' && pc->len >= 2) {
  1171. pc->p++; pc->len--;
  1172. if (*pc->p == '\n')
  1173. pc->linenr++;
  1174. } else if (*pc->p == '{') {
  1175. level++;
  1176. } else if (pc->len == 0 || *pc->p == '}') {
  1177. level--;
  1178. if (pc->len == 0 || level == 0) {
  1179. pc->tend = pc->p-1;
  1180. if (pc->len != 0) {
  1181. pc->p++; pc->len--;
  1182. }
  1183. pc->tt = JIM_TT_STR;
  1184. return JIM_OK;
  1185. }
  1186. } else if (*pc->p == '\n') {
  1187. pc->linenr++;
  1188. }
  1189. pc->p++; pc->len--;
  1190. }
  1191. return JIM_OK; /* unreached */
  1192. }
  1193. int JimParseStr(struct JimParserCtx *pc)
  1194. {
  1195. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1196. pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
  1197. if (newword && *pc->p == '{') {
  1198. return JimParseBrace(pc);
  1199. } else if (newword && *pc->p == '"') {
  1200. pc->state = JIM_PS_QUOTE;
  1201. pc->p++; pc->len--;
  1202. }
  1203. pc->tstart = pc->p;
  1204. pc->tline = pc->linenr;
  1205. while (1) {
  1206. if (pc->len == 0) {
  1207. pc->tend = pc->p-1;
  1208. pc->tt = JIM_TT_ESC;
  1209. return JIM_OK;
  1210. }
  1211. switch(*pc->p) {
  1212. case '\\':
  1213. if (pc->state == JIM_PS_DEF &&
  1214. *(pc->p+1) == '\n') {
  1215. pc->tend = pc->p-1;
  1216. pc->tt = JIM_TT_ESC;
  1217. return JIM_OK;
  1218. }
  1219. if (pc->len >= 2) {
  1220. pc->p++; pc->len--;
  1221. }
  1222. break;
  1223. case '$':
  1224. case '[':
  1225. pc->tend = pc->p-1;
  1226. pc->tt = JIM_TT_ESC;
  1227. return JIM_OK;
  1228. case ' ':
  1229. case '\t':
  1230. case '\n':
  1231. case '\r':
  1232. case ';':
  1233. if (pc->state == JIM_PS_DEF) {
  1234. pc->tend = pc->p-1;
  1235. pc->tt = JIM_TT_ESC;
  1236. return JIM_OK;
  1237. } else if (*pc->p == '\n') {
  1238. pc->linenr++;
  1239. }
  1240. break;
  1241. case '"':
  1242. if (pc->state == JIM_PS_QUOTE) {
  1243. pc->tend = pc->p-1;
  1244. pc->tt = JIM_TT_ESC;
  1245. pc->p++; pc->len--;
  1246. pc->state = JIM_PS_DEF;
  1247. return JIM_OK;
  1248. }
  1249. break;
  1250. }
  1251. pc->p++; pc->len--;
  1252. }
  1253. return JIM_OK; /* unreached */
  1254. }
  1255. int JimParseComment(struct JimParserCtx *pc)
  1256. {
  1257. while (*pc->p) {
  1258. if (*pc->p == '\n') {
  1259. pc->linenr++;
  1260. if (*(pc->p-1) != '\\') {
  1261. pc->p++; pc->len--;
  1262. return JIM_OK;
  1263. }
  1264. }
  1265. pc->p++; pc->len--;
  1266. }
  1267. return JIM_OK;
  1268. }
  1269. /* xdigitval and odigitval are helper functions for JimParserGetToken() */
  1270. static int xdigitval(int c)
  1271. {
  1272. if (c >= '0' && c <= '7') return c-'0';
  1273. if (c >= 'a' && c <= 'f') return c-'a'+10;
  1274. if (c >= 'A' && c <= 'F') return c-'A'+10;
  1275. return -1;
  1276. }
  1277. static int odigitval(int c)
  1278. {
  1279. if (c >= '0' && c <= '7') return c-'0';
  1280. return -1;
  1281. }
  1282. /* Perform Tcl escape substitution of 's', storing the result
  1283. * string into 'dest'. The escaped string is guaranteed to
  1284. * be the same length or shorted than the source string.
  1285. * Slen is the length of the string at 's', if it's -1 the string
  1286. * length will be calculated by the function.
  1287. *
  1288. * The function returns the length of the resulting string. */
  1289. static int JimEscape(char *dest, const char *s, int slen)
  1290. {
  1291. char *p = dest;
  1292. int i, len;
  1293. if (slen == -1)
  1294. slen = strlen(s);
  1295. for (i = 0; i < slen; i++) {
  1296. switch(s[i]) {
  1297. case '\\':
  1298. switch(s[i+1]) {
  1299. case 'a': *p++ = 0x7; i++; break;
  1300. case 'b': *p++ = 0x8; i++; break;
  1301. case 'f': *p++ = 0xc; i++; break;
  1302. case 'n': *p++ = 0xa; i++; break;
  1303. case 'r': *p++ = 0xd; i++; break;
  1304. case 't': *p++ = 0x9; i++; break;
  1305. case 'v': *p++ = 0xb; i++; break;
  1306. case '\0': *p++ = '\\'; i++; break;
  1307. case '\n': *p++ = ' '; i++; break;
  1308. default:
  1309. if (s[i+1] == 'x') {
  1310. int val = 0;
  1311. int c = xdigitval(s[i+2]);
  1312. if (c == -1) {
  1313. *p++ = 'x';
  1314. i++;
  1315. break;
  1316. }
  1317. val = c;
  1318. c = xdigitval(s[i+3]);
  1319. if (c == -1) {
  1320. *p++ = val;
  1321. i += 2;
  1322. break;
  1323. }
  1324. val = (val*16)+c;
  1325. *p++ = val;
  1326. i += 3;
  1327. break;
  1328. } else if (s[i+1] >= '0' && s[i+1] <= '7')
  1329. {
  1330. int val = 0;
  1331. int c = odigitval(s[i+1]);
  1332. val = c;
  1333. c = odigitval(s[i+2]);
  1334. if (c == -1) {
  1335. *p++ = val;
  1336. i ++;
  1337. break;
  1338. }
  1339. val = (val*8)+c;
  1340. c = odigitval(s[i+3]);
  1341. if (c == -1) {
  1342. *p++ = val;
  1343. i += 2;
  1344. break;
  1345. }
  1346. val = (val*8)+c;
  1347. *p++ = val;
  1348. i += 3;
  1349. } else {
  1350. *p++ = s[i+1];
  1351. i++;
  1352. }
  1353. break;
  1354. }
  1355. break;
  1356. default:
  1357. *p++ = s[i];
  1358. break;
  1359. }
  1360. }
  1361. len = p-dest;
  1362. *p++ = '\0';
  1363. return len;
  1364. }
  1365. /* Returns a dynamically allocated copy of the current token in the
  1366. * parser context. The function perform conversion of escapes if
  1367. * the token is of type JIM_TT_ESC.
  1368. *
  1369. * Note that after the conversion, tokens that are grouped with
  1370. * braces in the source code, are always recognizable from the
  1371. * identical string obtained in a different way from the type.
  1372. *
  1373. * For exmple the string:
  1374. *
  1375. * {expand}$a
  1376. *
  1377. * will return as first token "expand", of type JIM_TT_STR
  1378. *
  1379. * While the string:
  1380. *
  1381. * expand$a
  1382. *
  1383. * will return as first token "expand", of type JIM_TT_ESC
  1384. */
  1385. char *JimParserGetToken(struct JimParserCtx *pc,
  1386. int *lenPtr, int *typePtr, int *linePtr)
  1387. {
  1388. const char *start, *end;
  1389. char *token;
  1390. int len;
  1391. start = JimParserTstart(pc);
  1392. end = JimParserTend(pc);
  1393. if (start > end) {
  1394. if (lenPtr) *lenPtr = 0;
  1395. if (typePtr) *typePtr = JimParserTtype(pc);
  1396. if (linePtr) *linePtr = JimParserTline(pc);
  1397. token = Jim_Alloc(1);
  1398. token[0] = '\0';
  1399. return token;
  1400. }
  1401. len = (end-start)+1;
  1402. token = Jim_Alloc(len+1);
  1403. if (JimParserTtype(pc) != JIM_TT_ESC) {
  1404. /* No escape conversion needed? Just copy it. */
  1405. memcpy(token, start, len);
  1406. token[len] = '\0';
  1407. } else {
  1408. /* Else convert the escape chars. */
  1409. len = JimEscape(token, start, len);
  1410. }
  1411. if (lenPtr) *lenPtr = len;
  1412. if (typePtr) *typePtr = JimParserTtype(pc);
  1413. if (linePtr) *linePtr = JimParserTline(pc);
  1414. return token;
  1415. }
  1416. /* The following functin is not really part of the parsing engine of Jim,
  1417. * but it somewhat related. Given an string and its length, it tries
  1418. * to guess if the script is complete or there are instead " " or { }
  1419. * open and not completed. This is useful for interactive shells
  1420. * implementation and for [info complete].
  1421. *
  1422. * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
  1423. * '{' on scripts incomplete missing one or more '}' to be balanced.
  1424. * '"' on scripts incomplete missing a '"' char.
  1425. *
  1426. * If the script is complete, 1 is returned, otherwise 0. */
  1427. int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
  1428. {
  1429. int level = 0;
  1430. int state = ' ';
  1431. while(len) {
  1432. switch (*s) {
  1433. case '\\':
  1434. if (len > 1)
  1435. s++;
  1436. break;
  1437. case '"':
  1438. if (state == ' ') {
  1439. state = '"';
  1440. } else if (state == '"') {
  1441. state = ' ';
  1442. }
  1443. break;
  1444. case '{':
  1445. if (state == '{') {
  1446. level++;
  1447. } else if (state == ' ') {
  1448. state = '{';
  1449. level++;
  1450. }
  1451. break;
  1452. case '}':
  1453. if (state == '{') {
  1454. level--;
  1455. if (level == 0)
  1456. state = ' ';
  1457. }
  1458. break;
  1459. }
  1460. s++;
  1461. len--;
  1462. }
  1463. if (stateCharPtr)
  1464. *stateCharPtr = state;
  1465. return state == ' ';
  1466. }
  1467. /* -----------------------------------------------------------------------------
  1468. * Tcl Lists parsing
  1469. * ---------------------------------------------------------------------------*/
  1470. static int JimParseListSep(struct JimParserCtx *pc);
  1471. static int JimParseListStr(struct JimParserCtx *pc);
  1472. int JimParseList(struct JimParserCtx *pc)
  1473. {
  1474. if (pc->len == 0) {
  1475. pc->tstart = pc->tend = pc->p;
  1476. pc->tline = pc->linenr;
  1477. pc->tt = JIM_TT_EOL;
  1478. pc->eof = 1;
  1479. return JIM_OK;
  1480. }
  1481. switch(*pc->p) {
  1482. case ' ':
  1483. case '\n':
  1484. case '\t':
  1485. case '\r':
  1486. if (pc->state == JIM_PS_DEF)
  1487. return JimParseListSep(pc);
  1488. else
  1489. return JimParseListStr(pc);
  1490. break;
  1491. default:
  1492. return JimParseListStr(pc);
  1493. break;
  1494. }
  1495. return JIM_OK;
  1496. }
  1497. int JimParseListSep(struct JimParserCtx *pc)
  1498. {
  1499. pc->tstart = pc->p;
  1500. pc->tline = pc->linenr;
  1501. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n')
  1502. {
  1503. pc->p++; pc->len--;
  1504. }
  1505. pc->tend = pc->p-1;
  1506. pc->tt = JIM_TT_SEP;
  1507. return JIM_OK;
  1508. }
  1509. int JimParseListStr(struct JimParserCtx *pc)
  1510. {
  1511. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1512. pc->tt == JIM_TT_NONE);
  1513. if (newword && *pc->p == '{') {
  1514. return JimParseBrace(pc);
  1515. } else if (newword && *pc->p == '"') {
  1516. pc->state = JIM_PS_QUOTE;
  1517. pc->p++; pc->len--;
  1518. }
  1519. pc->tstart = pc->p;
  1520. pc->tline = pc->linenr;
  1521. while (1) {
  1522. if (pc->len == 0) {
  1523. pc->tend = pc->p-1;
  1524. pc->tt = JIM_TT_ESC;
  1525. return JIM_OK;
  1526. }
  1527. switch(*pc->p) {
  1528. case '\\':
  1529. pc->p++; pc->len--;
  1530. break;
  1531. case ' ':
  1532. case '\t':
  1533. case '\n':
  1534. case '\r':
  1535. if (pc->state == JIM_PS_DEF) {
  1536. pc->tend = pc->p-1;
  1537. pc->tt = JIM_TT_ESC;
  1538. return JIM_OK;
  1539. } else if (*pc->p == '\n') {
  1540. pc->linenr++;
  1541. }
  1542. break;
  1543. case '"':
  1544. if (pc->state == JIM_PS_QUOTE) {
  1545. pc->tend = pc->p-1;
  1546. pc->tt = JIM_TT_ESC;
  1547. pc->p++; pc->len--;
  1548. pc->state = JIM_PS_DEF;
  1549. return JIM_OK;
  1550. }
  1551. break;
  1552. }
  1553. pc->p++; pc->len--;
  1554. }
  1555. return JIM_OK; /* unreached */
  1556. }
  1557. /* -----------------------------------------------------------------------------
  1558. * Jim_Obj related functions
  1559. * ---------------------------------------------------------------------------*/
  1560. /* Return a new initialized object. */
  1561. Jim_Obj *Jim_NewObj(Jim_Interp *interp)
  1562. {
  1563. Jim_Obj *objPtr;
  1564. /* -- Check if there are objects in the free list -- */
  1565. if (interp->freeList != NULL) {
  1566. /* -- Unlink the object from the free list -- */
  1567. objPtr = interp->freeList;
  1568. interp->freeList = objPtr->nextObjPtr;
  1569. } else {
  1570. /* -- No ready to use objects: allocate a new one -- */
  1571. objPtr = Jim_Alloc(sizeof(*objPtr));
  1572. }
  1573. /* Object is returned with refCount of 0. Every
  1574. * kind of GC implemented should take care to don't try
  1575. * to scan objects with refCount == 0. */
  1576. objPtr->refCount = 0;
  1577. /* All the other fields are left not initialized to save time.
  1578. * The caller will probably want set they to the right
  1579. * value anyway. */
  1580. /* -- Put the object into the live list -- */
  1581. obj

Large files files are truncated, but you can click here to view the full file