/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
- /* Jim - A small embeddable Tcl interpreter
- * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
- * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
- *
- * $Id: jim.c 6455 2006-04-13 19:06:27Z arjenmarkus $
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * A copy of the license is also included in the source distribution
- * of Jim, as a TXT file name called LICENSE.
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #define __JIM_CORE__
- #define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */
- #ifndef JIM_ANSIC
- #define JIM_DYNLIB /* Dynamic library support for UNIX and WIN32 */
- #endif /* JIM_ANSIC */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <limits.h>
- #include <assert.h>
- #include <errno.h>
- #include <time.h>
- /* Include the platform dependent libraries for
- * dynamic loading of libraries. */
- #ifdef JIM_DYNLIB
- #if defined(_WIN32) || defined(WIN32)
- #ifndef WIN32
- #define WIN32 1
- #endif
- #define STRICT
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #if _MSC_VER >= 1000
- #pragma warning(disable:4146)
- #endif /* _MSC_VER */
- #else
- #include <dlfcn.h>
- #endif /* WIN32 */
- #endif /* JIM_DYNLIB */
- #include "jim.h"
- #ifdef HAVE_BACKTRACE
- #include <execinfo.h>
- #endif
- /* -----------------------------------------------------------------------------
- * Global variables
- * ---------------------------------------------------------------------------*/
- /* A shared empty string for the objects string representation.
- * Jim_InvalidateStringRep knows about it and don't try to free. */
- static char *JimEmptyStringRep = (char*) "";
- /* -----------------------------------------------------------------------------
- * Required prototypes of not exported functions
- * ---------------------------------------------------------------------------*/
- static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
- static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
- static void JimRegisterCoreApi(Jim_Interp *interp);
- extern Jim_HashTableType JimVariablesHashTableType;
- /* -----------------------------------------------------------------------------
- * Utility functions
- * ---------------------------------------------------------------------------*/
- /*
- * Convert a string to a jim_wide INTEGER.
- * This function originates from BSD.
- *
- * Ignores `locale' stuff. Assumes that the upper and lower case
- * alphabets and digits are each contiguous.
- */
- #ifdef HAVE_LONG_LONG
- #define JimIsAscii(c) (((c) & ~0x7f) == 0)
- static jim_wide JimStrtoll(const char *nptr, char **endptr, register int base)
- {
- register const char *s;
- register unsigned jim_wide acc;
- register unsigned char c;
- register unsigned jim_wide qbase, cutoff;
- register int neg, any, cutlim;
- /*
- * Skip white space and pick up leading +/- sign if any.
- * If base is 0, allow 0x for hex and 0 for octal, else
- * assume decimal; if base is already 16, allow 0x.
- */
- s = nptr;
- do {
- c = *s++;
- } while (isspace(c));
- if (c == '-') {
- neg = 1;
- c = *s++;
- } else {
- neg = 0;
- if (c == '+')
- c = *s++;
- }
- if ((base == 0 || base == 16) &&
- c == '0' && (*s == 'x' || *s == 'X')) {
- c = s[1];
- s += 2;
- base = 16;
- }
- if (base == 0)
- base = c == '0' ? 8 : 10;
- /*
- * Compute the cutoff value between legal numbers and illegal
- * numbers. That is the largest legal value, divided by the
- * base. An input number that is greater than this value, if
- * followed by a legal input character, is too big. One that
- * is equal to this value may be valid or not; the limit
- * between valid and invalid numbers is then based on the last
- * digit. For instance, if the range for quads is
- * [-9223372036854775808..9223372036854775807] and the input base
- * is 10, cutoff will be set to 922337203685477580 and cutlim to
- * either 7 (neg==0) or 8 (neg==1), meaning that if we have
- * accumulated a value > 922337203685477580, or equal but the
- * next digit is > 7 (or 8), the number is too big, and we will
- * return a range error.
- *
- * Set any if any `digits' consumed; make it negative to indicate
- * overflow.
- */
- qbase = (unsigned)base;
- cutoff = neg ? (unsigned jim_wide)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
- : LLONG_MAX;
- cutlim = (int)(cutoff % qbase);
- cutoff /= qbase;
- for (acc = 0, any = 0;; c = *s++) {
- if (!JimIsAscii(c))
- break;
- if (isdigit(c))
- c -= '0';
- else if (isalpha(c))
- c -= isupper(c) ? 'A' - 10 : 'a' - 10;
- else
- break;
- if (c >= base)
- break;
- if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
- any = -1;
- else {
- any = 1;
- acc *= qbase;
- acc += c;
- }
- }
- if (any < 0) {
- acc = neg ? LLONG_MIN : LLONG_MAX;
- errno = ERANGE;
- } else if (neg)
- acc = -acc;
- if (endptr != 0)
- *endptr = (char *)(any ? s - 1 : nptr);
- return (acc);
- }
- #endif
- /* Glob-style pattern matching. */
- static int JimStringMatch(const char *pattern, int patternLen,
- const char *string, int stringLen, int nocase)
- {
- while(patternLen) {
- switch(pattern[0]) {
- case '*':
- while (pattern[1] == '*') {
- pattern++;
- patternLen--;
- }
- if (patternLen == 1)
- return 1; /* match */
- while(stringLen) {
- if (JimStringMatch(pattern+1, patternLen-1,
- string, stringLen, nocase))
- return 1; /* match */
- string++;
- stringLen--;
- }
- return 0; /* no match */
- break;
- case '?':
- if (stringLen == 0)
- return 0; /* no match */
- string++;
- stringLen--;
- break;
- case '[':
- {
- int not, match;
- pattern++;
- patternLen--;
- not = pattern[0] == '^';
- if (not) {
- pattern++;
- patternLen--;
- }
- match = 0;
- while(1) {
- if (pattern[0] == '\\') {
- pattern++;
- patternLen--;
- if (pattern[0] == string[0])
- match = 1;
- } else if (pattern[0] == ']') {
- break;
- } else if (patternLen == 0) {
- pattern--;
- patternLen++;
- break;
- } else if (pattern[1] == '-' && patternLen >= 3) {
- int start = pattern[0];
- int end = pattern[2];
- int c = string[0];
- if (start > end) {
- int t = start;
- start = end;
- end = t;
- }
- if (nocase) {
- start = tolower(start);
- end = tolower(end);
- c = tolower(c);
- }
- pattern += 2;
- patternLen -= 2;
- if (c >= start && c <= end)
- match = 1;
- } else {
- if (!nocase) {
- if (pattern[0] == string[0])
- match = 1;
- } else {
- if (tolower((int)pattern[0]) == tolower((int)string[0]))
- match = 1;
- }
- }
- pattern++;
- patternLen--;
- }
- if (not)
- match = !match;
- if (!match)
- return 0; /* no match */
- string++;
- stringLen--;
- break;
- }
- case '\\':
- if (patternLen >= 2) {
- pattern++;
- patternLen--;
- }
- /* fall through */
- default:
- if (!nocase) {
- if (pattern[0] != string[0])
- return 0; /* no match */
- } else {
- if (tolower((int)pattern[0]) != tolower((int)string[0]))
- return 0; /* no match */
- }
- string++;
- stringLen--;
- break;
- }
- pattern++;
- patternLen--;
- if (stringLen == 0) {
- while(*pattern == '*') {
- pattern++;
- patternLen--;
- }
- break;
- }
- }
- if (patternLen == 0 && stringLen == 0)
- return 1;
- return 0;
- }
- int JimStringCompare(const char *s1, int l1, const char *s2, int l2,
- int nocase)
- {
- unsigned char *u1 = (unsigned char*) s1, *u2 = (unsigned char*) s2;
- if (nocase == 0) {
- while(l1 && l2) {
- if (*u1 != *u2)
- return (int)*u1-*u2;
- u1++; u2++; l1--; l2--;
- }
- if (!l1 && !l2) return 0;
- return l1-l2;
- } else {
- while(l1 && l2) {
- if (tolower((int)*u1) != tolower((int)*u2))
- return tolower((int)*u1)-tolower((int)*u2);
- u1++; u2++; l1--; l2--;
- }
- if (!l1 && !l2) return 0;
- return l1-l2;
- }
- }
- /* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
- * The index of the first occurrence of s1 in s2 is returned.
- * If s1 is not found inside s2, -1 is returned. */
- int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int index)
- {
- int i;
- if (!l1 || !l2 || l1 > l2) return -1;
- if (index < 0) index = 0;
- s2 += index;
- for (i = index; i <= l2-l1; i++) {
- if (memcmp(s2, s1, l1) == 0)
- return i;
- s2++;
- }
- return -1;
- }
- int Jim_WideToString(char *buf, jim_wide wideValue)
- {
- const char *fmt = "%" JIM_WIDE_MODIFIER;
- return sprintf(buf, fmt, wideValue);
- }
- int Jim_StringToWide(const char *str, jim_wide *widePtr, int base)
- {
- char *endptr;
- #ifdef HAVE_LONG_LONG
- *widePtr = JimStrtoll(str, &endptr, base);
- #else
- *widePtr = strtol(str, &endptr, base);
- #endif
- if (str[0] == '\0')
- return JIM_ERR;
- if (endptr[0] != '\0') {
- while(*endptr) {
- if (!isspace((int)*endptr))
- return JIM_ERR;
- endptr++;
- }
- }
- return JIM_OK;
- }
- int Jim_StringToIndex(const char *str, int *intPtr)
- {
- char *endptr;
- *intPtr = strtol(str, &endptr, 10);
- if (str[0] == '\0')
- return JIM_ERR;
- if (endptr[0] != '\0') {
- while(*endptr) {
- if (!isspace((int)*endptr))
- return JIM_ERR;
- endptr++;
- }
- }
- return JIM_OK;
- }
- /* The string representation of references has two features in order
- * to make the GC faster. The first is that every reference starts
- * with a non common character '~', in order to make the string matching
- * fater. The second is that the reference string rep his 32 characters
- * in length, this allows to avoid to check every object with a string
- * repr < 32, and usually there are many of this objects. */
- #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
- static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
- {
- const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
- sprintf(buf, fmt, refPtr->tag, id);
- return JIM_REFERENCE_SPACE;
- }
- int Jim_DoubleToString(char *buf, double doubleValue)
- {
- char *s;
- int len;
- len = sprintf(buf, "%.17g", doubleValue);
- s = buf;
- while(*s) {
- if (*s == '.') return len;
- s++;
- }
- /* Add a final ".0" if it's a number. But not
- * for NaN or InF */
- if (isdigit((int)buf[0])
- || ((buf[0] == '-' || buf[0] == '+')
- && isdigit((int)buf[1]))) {
- s[0] = '.';
- s[1] = '0';
- s[2] = '\0';
- return len+2;
- }
- return len;
- }
- int Jim_StringToDouble(const char *str, double *doublePtr)
- {
- char *endptr;
- *doublePtr = strtod(str, &endptr);
- if (str[0] == '\0' || endptr[0] != '\0')
- return JIM_ERR;
- return JIM_OK;
- }
- static jim_wide JimPowWide(jim_wide b, jim_wide e)
- {
- jim_wide i, res = 1;
- if ((b==0 && e!=0) || (e<0)) return 0;
- for(i=0; i<e; i++) {res *= b;}
- return res;
- }
- /* -----------------------------------------------------------------------------
- * Special functions
- * ---------------------------------------------------------------------------*/
- void Jim_Panic(const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n\n");
- va_end(ap);
- #ifdef HAVE_BACKTRACE
- {
- void *array[40];
- int size, i;
- char **strings;
- size = backtrace(array, 40);
- strings = backtrace_symbols(array, size);
- for (i = 0; i < size; i++)
- printf("[backtrace] %s\n", strings[i]);
- printf("[backtrace] Include the above lines and the output\n");
- printf("[backtrace] of 'nm <executable>' in the bug report.\n");
- }
- #endif
- abort();
- }
- /* -----------------------------------------------------------------------------
- * Memory allocation
- * ---------------------------------------------------------------------------*/
- /* Macro used for memory debugging.
- * In order for they to work you have to rename Jim_Alloc into _Jim_Alloc
- * and similary for Jim_Realloc and Jim_Free */
- #if 0
- #define Jim_Alloc(s) (printf("%s %d: Jim_Alloc(%d)\n",__FILE__,__LINE__,s),_Jim_Alloc(s))
- #define Jim_Free(p) (printf("%s %d: Jim_Free(%p)\n",__FILE__,__LINE__,p),_Jim_Free(p))
- #define Jim_Realloc(p,s) (printf("%s %d: Jim_Realloc(%p,%d)\n",__FILE__,__LINE__,p,s),_Jim_Realloc(p,s))
- #endif
- void *Jim_Alloc(int size)
- {
- void *p = malloc(size);
- if (p == NULL)
- Jim_Panic("Out of memory");
- return p;
- }
- void Jim_Free(void *ptr) {
- free(ptr);
- }
- void *Jim_Realloc(void *ptr, int size)
- {
- void *p = realloc(ptr, size);
- if (p == NULL)
- Jim_Panic("Out of memory");
- return p;
- }
- char *Jim_StrDup(const char *s)
- {
- int l = strlen(s);
- char *copy = Jim_Alloc(l+1);
- memcpy(copy, s, l+1);
- return copy;
- }
- char *Jim_StrDupLen(const char *s, int l)
- {
- char *copy = Jim_Alloc(l+1);
-
- memcpy(copy, s, l+1);
- copy[l] = 0; /* Just to be sure, original could be substring */
- return copy;
- }
- /* -----------------------------------------------------------------------------
- * Time related functions
- * ---------------------------------------------------------------------------*/
- /* Returns microseconds of CPU used since start. */
- static jim_wide JimClock(void)
- {
- #if (defined WIN32) && !(defined JIM_ANSIC)
- LARGE_INTEGER t, f;
- QueryPerformanceFrequency(&f);
- QueryPerformanceCounter(&t);
- return (long)((t.QuadPart * 1000000) / f.QuadPart);
- #else /* !WIN32 */
- clock_t clocks = clock();
- return (long)(clocks*(1000000/CLOCKS_PER_SEC));
- #endif /* WIN32 */
- }
- /* -----------------------------------------------------------------------------
- * Hash Tables
- * ---------------------------------------------------------------------------*/
- /* -------------------------- private prototypes ---------------------------- */
- static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
- static unsigned int JimHashTableNextPower(unsigned int size);
- static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
- /* -------------------------- hash functions -------------------------------- */
- /* Thomas Wang's 32 bit Mix Function */
- unsigned int Jim_IntHashFunction(unsigned int key)
- {
- key += ~(key << 15);
- key ^= (key >> 10);
- key += (key << 3);
- key ^= (key >> 6);
- key += ~(key << 11);
- key ^= (key >> 16);
- return key;
- }
- /* Identity hash function for integer keys */
- unsigned int Jim_IdentityHashFunction(unsigned int key)
- {
- return key;
- }
- /* Generic hash function (we are using to multiply by 9 and add the byte
- * as Tcl) */
- unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
- {
- unsigned int h = 0;
- while(len--)
- h += (h<<3)+*buf++;
- return h;
- }
- /* ----------------------------- API implementation ------------------------- */
- /* reset an hashtable already initialized with ht_init().
- * NOTE: This function should only called by ht_destroy(). */
- static void JimResetHashTable(Jim_HashTable *ht)
- {
- ht->table = NULL;
- ht->size = 0;
- ht->sizemask = 0;
- ht->used = 0;
- ht->collisions = 0;
- }
- /* Initialize the hash table */
- int Jim_InitHashTable(Jim_HashTable *ht, Jim_HashTableType *type,
- void *privDataPtr)
- {
- JimResetHashTable(ht);
- ht->type = type;
- ht->privdata = privDataPtr;
- return JIM_OK;
- }
- /* Resize the table to the minimal size that contains all the elements,
- * but with the invariant of a USER/BUCKETS ration near to <= 1 */
- int Jim_ResizeHashTable(Jim_HashTable *ht)
- {
- int minimal = ht->used;
- if (minimal < JIM_HT_INITIAL_SIZE)
- minimal = JIM_HT_INITIAL_SIZE;
- return Jim_ExpandHashTable(ht, minimal);
- }
- /* Expand or create the hashtable */
- int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
- {
- Jim_HashTable n; /* the new hashtable */
- unsigned int realsize = JimHashTableNextPower(size), i;
- /* the size is invalid if it is smaller than the number of
- * elements already inside the hashtable */
- if (ht->used >= size)
- return JIM_ERR;
- Jim_InitHashTable(&n, ht->type, ht->privdata);
- n.size = realsize;
- n.sizemask = realsize-1;
- n.table = Jim_Alloc(realsize*sizeof(Jim_HashEntry*));
- /* Initialize all the pointers to NULL */
- memset(n.table, 0, realsize*sizeof(Jim_HashEntry*));
- /* Copy all the elements from the old to the new table:
- * note that if the old hash table is empty ht->size is zero,
- * so Jim_ExpandHashTable just creates an hash table. */
- n.used = ht->used;
- for (i = 0; i < ht->size && ht->used > 0; i++) {
- Jim_HashEntry *he, *nextHe;
- if (ht->table[i] == NULL) continue;
-
- /* For each hash entry on this slot... */
- he = ht->table[i];
- while(he) {
- unsigned int h;
- nextHe = he->next;
- /* Get the new element index */
- h = Jim_HashKey(ht, he->key) & n.sizemask;
- he->next = n.table[h];
- n.table[h] = he;
- ht->used--;
- /* Pass to the next element */
- he = nextHe;
- }
- }
- assert(ht->used == 0);
- Jim_Free(ht->table);
- /* Remap the new hashtable in the old */
- *ht = n;
- return JIM_OK;
- }
- /* Add an element to the target hash table */
- int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
- {
- int index;
- Jim_HashEntry *entry;
- /* Get the index of the new element, or -1 if
- * the element already exists. */
- if ((index = JimInsertHashEntry(ht, key)) == -1)
- return JIM_ERR;
- /* Allocates the memory and stores key */
- entry = Jim_Alloc(sizeof(*entry));
- entry->next = ht->table[index];
- ht->table[index] = entry;
- /* Set the hash entry fields. */
- Jim_SetHashKey(ht, entry, key);
- Jim_SetHashVal(ht, entry, val);
- ht->used++;
- return JIM_OK;
- }
- /* Add an element, discarding the old if the key already exists */
- int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
- {
- Jim_HashEntry *entry;
- /* Try to add the element. If the key
- * does not exists Jim_AddHashEntry will suceed. */
- if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
- return JIM_OK;
- /* It already exists, get the entry */
- entry = Jim_FindHashEntry(ht, key);
- /* Free the old value and set the new one */
- Jim_FreeEntryVal(ht, entry);
- Jim_SetHashVal(ht, entry, val);
- return JIM_OK;
- }
- /* Search and remove an element */
- int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
- {
- unsigned int h;
- Jim_HashEntry *he, *prevHe;
- if (ht->size == 0)
- return JIM_ERR;
- h = Jim_HashKey(ht, key) & ht->sizemask;
- he = ht->table[h];
- prevHe = NULL;
- while(he) {
- if (Jim_CompareHashKeys(ht, key, he->key)) {
- /* Unlink the element from the list */
- if (prevHe)
- prevHe->next = he->next;
- else
- ht->table[h] = he->next;
- Jim_FreeEntryKey(ht, he);
- Jim_FreeEntryVal(ht, he);
- Jim_Free(he);
- ht->used--;
- return JIM_OK;
- }
- prevHe = he;
- he = he->next;
- }
- return JIM_ERR; /* not found */
- }
- /* Destroy an entire hash table */
- int Jim_FreeHashTable(Jim_HashTable *ht)
- {
- unsigned int i;
- /* Free all the elements */
- for (i = 0; i < ht->size && ht->used > 0; i++) {
- Jim_HashEntry *he, *nextHe;
- if ((he = ht->table[i]) == NULL) continue;
- while(he) {
- nextHe = he->next;
- Jim_FreeEntryKey(ht, he);
- Jim_FreeEntryVal(ht, he);
- Jim_Free(he);
- ht->used--;
- he = nextHe;
- }
- }
- /* Free the table and the allocated cache structure */
- Jim_Free(ht->table);
- /* Re-initialize the table */
- JimResetHashTable(ht);
- return JIM_OK; /* never fails */
- }
- Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
- {
- Jim_HashEntry *he;
- unsigned int h;
- if (ht->size == 0) return NULL;
- h = Jim_HashKey(ht, key) & ht->sizemask;
- he = ht->table[h];
- while(he) {
- if (Jim_CompareHashKeys(ht, key, he->key))
- return he;
- he = he->next;
- }
- return NULL;
- }
- Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
- {
- Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
- iter->ht = ht;
- iter->index = -1;
- iter->entry = NULL;
- iter->nextEntry = NULL;
- return iter;
- }
- Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
- {
- while (1) {
- if (iter->entry == NULL) {
- iter->index++;
- if (iter->index >=
- (signed)iter->ht->size) break;
- iter->entry = iter->ht->table[iter->index];
- } else {
- iter->entry = iter->nextEntry;
- }
- if (iter->entry) {
- /* We need to save the 'next' here, the iterator user
- * may delete the entry we are returning. */
- iter->nextEntry = iter->entry->next;
- return iter->entry;
- }
- }
- return NULL;
- }
- /* ------------------------- private functions ------------------------------ */
- /* Expand the hash table if needed */
- static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
- {
- /* If the hash table is empty expand it to the intial size,
- * if the table is "full" dobule its size. */
- if (ht->size == 0)
- return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
- if (ht->size == ht->used)
- return Jim_ExpandHashTable(ht, ht->size*2);
- return JIM_OK;
- }
- /* Our hash table capability is a power of two */
- static unsigned int JimHashTableNextPower(unsigned int size)
- {
- unsigned int i = JIM_HT_INITIAL_SIZE;
- if (size >= 2147483648U)
- return 2147483648U;
- while(1) {
- if (i >= size)
- return i;
- i *= 2;
- }
- }
- /* Returns the index of a free slot that can be populated with
- * an hash entry for the given 'key'.
- * If the key already exists, -1 is returned. */
- static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
- {
- unsigned int h;
- Jim_HashEntry *he;
- /* Expand the hashtable if needed */
- if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
- return -1;
- /* Compute the key hash value */
- h = Jim_HashKey(ht, key) & ht->sizemask;
- /* Search if this slot does not already contain the given key */
- he = ht->table[h];
- while(he) {
- if (Jim_CompareHashKeys(ht, key, he->key))
- return -1;
- he = he->next;
- }
- return h;
- }
- /* ----------------------- StringCopy Hash Table Type ------------------------*/
- static unsigned int JimStringCopyHTHashFunction(const void *key)
- {
- return Jim_GenHashFunction(key, strlen(key));
- }
- static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
- {
- int len = strlen(key);
- char *copy = Jim_Alloc(len+1);
- JIM_NOTUSED(privdata);
- memcpy(copy, key, len);
- copy[len] = '\0';
- return copy;
- }
- static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
- {
- int len = strlen(val);
- char *copy = Jim_Alloc(len+1);
- JIM_NOTUSED(privdata);
- memcpy(copy, val, len);
- copy[len] = '\0';
- return copy;
- }
- static int JimStringCopyHTKeyCompare(void *privdata, const void *key1,
- const void *key2)
- {
- JIM_NOTUSED(privdata);
- return strcmp(key1, key2) == 0;
- }
- static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
- {
- JIM_NOTUSED(privdata);
- Jim_Free((void*)key); /* ATTENTION: const cast */
- }
- static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
- {
- JIM_NOTUSED(privdata);
- Jim_Free((void*)val); /* ATTENTION: const cast */
- }
- static Jim_HashTableType JimStringCopyHashTableType = {
- JimStringCopyHTHashFunction, /* hash function */
- JimStringCopyHTKeyDup, /* key dup */
- NULL, /* val dup */
- JimStringCopyHTKeyCompare, /* key compare */
- JimStringCopyHTKeyDestructor, /* key destructor */
- NULL /* val destructor */
- };
- /* This is like StringCopy but does not auto-duplicate the key.
- * It's used for intepreter's shared strings. */
- static Jim_HashTableType JimSharedStringsHashTableType = {
- JimStringCopyHTHashFunction, /* hash function */
- NULL, /* key dup */
- NULL, /* val dup */
- JimStringCopyHTKeyCompare, /* key compare */
- JimStringCopyHTKeyDestructor, /* key destructor */
- NULL /* val destructor */
- };
- /* This is like StringCopy but also automatically handle dynamic
- * allocated C strings as values. */
- static Jim_HashTableType JimStringKeyValCopyHashTableType = {
- JimStringCopyHTHashFunction, /* hash function */
- JimStringCopyHTKeyDup, /* key dup */
- JimStringKeyValCopyHTValDup, /* val dup */
- JimStringCopyHTKeyCompare, /* key compare */
- JimStringCopyHTKeyDestructor, /* key destructor */
- JimStringKeyValCopyHTValDestructor, /* val destructor */
- };
- typedef struct AssocDataValue {
- Jim_InterpDeleteProc *delProc;
- void *data;
- } AssocDataValue;
- static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
- {
- AssocDataValue *assocPtr = (AssocDataValue *)data;
- if (assocPtr->delProc != NULL)
- assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
- Jim_Free(data);
- }
- static Jim_HashTableType JimAssocDataHashTableType = {
- JimStringCopyHTHashFunction, /* hash function */
- JimStringCopyHTKeyDup, /* key dup */
- NULL, /* val dup */
- JimStringCopyHTKeyCompare, /* key compare */
- JimStringCopyHTKeyDestructor, /* key destructor */
- JimAssocDataHashTableValueDestructor /* val destructor */
- };
- /* -----------------------------------------------------------------------------
- * Stack - This is a simple generic stack implementation. It is used for
- * example in the 'expr' expression compiler.
- * ---------------------------------------------------------------------------*/
- void Jim_InitStack(Jim_Stack *stack)
- {
- stack->len = 0;
- stack->maxlen = 0;
- stack->vector = NULL;
- }
- void Jim_FreeStack(Jim_Stack *stack)
- {
- Jim_Free(stack->vector);
- }
- int Jim_StackLen(Jim_Stack *stack)
- {
- return stack->len;
- }
- void Jim_StackPush(Jim_Stack *stack, void *element) {
- int neededLen = stack->len+1;
- if (neededLen > stack->maxlen) {
- stack->maxlen = neededLen*2;
- stack->vector = Jim_Realloc(stack->vector, sizeof(void*)*stack->maxlen);
- }
- stack->vector[stack->len] = element;
- stack->len++;
- }
- void *Jim_StackPop(Jim_Stack *stack)
- {
- if (stack->len == 0) return NULL;
- stack->len--;
- return stack->vector[stack->len];
- }
- void *Jim_StackPeek(Jim_Stack *stack)
- {
- if (stack->len == 0) return NULL;
- return stack->vector[stack->len-1];
- }
- void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr))
- {
- int i;
- for (i = 0; i < stack->len; i++)
- freeFunc(stack->vector[i]);
- }
- /* -----------------------------------------------------------------------------
- * Parser
- * ---------------------------------------------------------------------------*/
- /* Token types */
- #define JIM_TT_NONE -1 /* No token returned */
- #define JIM_TT_STR 0 /* simple string */
- #define JIM_TT_ESC 1 /* string that needs escape chars conversion */
- #define JIM_TT_VAR 2 /* var substitution */
- #define JIM_TT_DICTSUGAR 3 /* Syntax sugar for [dict get], $foo(bar) */
- #define JIM_TT_CMD 4 /* command substitution */
- #define JIM_TT_SEP 5 /* word separator */
- #define JIM_TT_EOL 6 /* line separator */
- /* Additional token types needed for expressions */
- #define JIM_TT_SUBEXPR_START 7
- #define JIM_TT_SUBEXPR_END 8
- #define JIM_TT_EXPR_NUMBER 9
- #define JIM_TT_EXPR_OPERATOR 10
- /* Parser states */
- #define JIM_PS_DEF 0 /* Default state */
- #define JIM_PS_QUOTE 1 /* Inside "" */
- /* Parser context structure. The same context is used both to parse
- * Tcl scripts and lists. */
- struct JimParserCtx {
- const char *prg; /* Program text */
- const char *p; /* Pointer to the point of the program we are parsing */
- int len; /* Left length of 'prg' */
- int linenr; /* Current line number */
- const char *tstart;
- const char *tend; /* Returned token is at tstart-tend in 'prg'. */
- int tline; /* Line number of the returned token */
- int tt; /* Token type */
- int eof; /* Non zero if EOF condition is true. */
- int state; /* Parser state */
- int comment; /* Non zero if the next chars may be a comment. */
- };
- #define JimParserEof(c) ((c)->eof)
- #define JimParserTstart(c) ((c)->tstart)
- #define JimParserTend(c) ((c)->tend)
- #define JimParserTtype(c) ((c)->tt)
- #define JimParserTline(c) ((c)->tline)
- static int JimParseScript(struct JimParserCtx *pc);
- static int JimParseSep(struct JimParserCtx *pc);
- static int JimParseEol(struct JimParserCtx *pc);
- static int JimParseCmd(struct JimParserCtx *pc);
- static int JimParseVar(struct JimParserCtx *pc);
- static int JimParseBrace(struct JimParserCtx *pc);
- static int JimParseStr(struct JimParserCtx *pc);
- static int JimParseComment(struct JimParserCtx *pc);
- static char *JimParserGetToken(struct JimParserCtx *pc,
- int *lenPtr, int *typePtr, int *linePtr);
- /* Initialize a parser context.
- * 'prg' is a pointer to the program text, linenr is the line
- * number of the first line contained in the program. */
- void JimParserInit(struct JimParserCtx *pc, const char *prg,
- int len, int linenr)
- {
- pc->prg = prg;
- pc->p = prg;
- pc->len = len;
- pc->tstart = NULL;
- pc->tend = NULL;
- pc->tline = 0;
- pc->tt = JIM_TT_NONE;
- pc->eof = 0;
- pc->state = JIM_PS_DEF;
- pc->linenr = linenr;
- pc->comment = 1;
- }
- int JimParseScript(struct JimParserCtx *pc)
- {
- while(1) { /* the while is used to reiterate with continue if needed */
- if (!pc->len) {
- pc->tstart = pc->p;
- pc->tend = pc->p-1;
- pc->tline = pc->linenr;
- pc->tt = JIM_TT_EOL;
- pc->eof = 1;
- return JIM_OK;
- }
- switch(*(pc->p)) {
- case '\\':
- if (*(pc->p+1) == '\n')
- return JimParseSep(pc);
- else {
- pc->comment = 0;
- return JimParseStr(pc);
- }
- break;
- case ' ':
- case '\t':
- case '\r':
- if (pc->state == JIM_PS_DEF)
- return JimParseSep(pc);
- else {
- pc->comment = 0;
- return JimParseStr(pc);
- }
- break;
- case '\n':
- case ';':
- pc->comment = 1;
- if (pc->state == JIM_PS_DEF)
- return JimParseEol(pc);
- else
- return JimParseStr(pc);
- break;
- case '[':
- pc->comment = 0;
- return JimParseCmd(pc);
- break;
- case '$':
- pc->comment = 0;
- if (JimParseVar(pc) == JIM_ERR) {
- pc->tstart = pc->tend = pc->p++; pc->len--;
- pc->tline = pc->linenr;
- pc->tt = JIM_TT_STR;
- return JIM_OK;
- } else
- return JIM_OK;
- break;
- case '#':
- if (pc->comment) {
- JimParseComment(pc);
- continue;
- } else {
- return JimParseStr(pc);
- }
- default:
- pc->comment = 0;
- return JimParseStr(pc);
- break;
- }
- return JIM_OK;
- }
- }
- int JimParseSep(struct JimParserCtx *pc)
- {
- pc->tstart = pc->p;
- pc->tline = pc->linenr;
- while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
- (*pc->p == '\\' && *(pc->p+1) == '\n')) {
- if (*pc->p == '\\') {
- pc->p++; pc->len--;
- pc->linenr++;
- }
- pc->p++; pc->len--;
- }
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_SEP;
- return JIM_OK;
- }
- int JimParseEol(struct JimParserCtx *pc)
- {
- pc->tstart = pc->p;
- pc->tline = pc->linenr;
- while (*pc->p == ' ' || *pc->p == '\n' ||
- *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
- if (*pc->p == '\n')
- pc->linenr++;
- pc->p++; pc->len--;
- }
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_EOL;
- return JIM_OK;
- }
- /* Todo. Don't stop if ']' appears inside {} or quoted.
- * Also should handle the case of puts [string length "]"] */
- int JimParseCmd(struct JimParserCtx *pc)
- {
- int level = 1;
- int blevel = 0;
- pc->tstart = ++pc->p; pc->len--;
- pc->tline = pc->linenr;
- while (1) {
- if (pc->len == 0) {
- break;
- } else if (*pc->p == '[' && blevel == 0) {
- level++;
- } else if (*pc->p == ']' && blevel == 0) {
- level--;
- if (!level) break;
- } else if (*pc->p == '\\') {
- pc->p++; pc->len--;
- } else if (*pc->p == '{') {
- blevel++;
- } else if (*pc->p == '}') {
- if (blevel != 0)
- blevel--;
- } else if (*pc->p == '\n')
- pc->linenr++;
- pc->p++; pc->len--;
- }
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_CMD;
- if (*pc->p == ']') {
- pc->p++; pc->len--;
- }
- return JIM_OK;
- }
- int JimParseVar(struct JimParserCtx *pc)
- {
- int brace = 0, stop = 0, ttype = JIM_TT_VAR;
- pc->tstart = ++pc->p; pc->len--; /* skip the $ */
- pc->tline = pc->linenr;
- if (*pc->p == '{') {
- pc->tstart = ++pc->p; pc->len--;
- brace = 1;
- }
- if (brace) {
- while (!stop) {
- if (*pc->p == '}' || pc->len == 0) {
- stop = 1;
- if (pc->len == 0)
- continue;
- }
- else if (*pc->p == '\n')
- pc->linenr++;
- pc->p++; pc->len--;
- }
- if (pc->len == 0)
- pc->tend = pc->p-1;
- else
- pc->tend = pc->p-2;
- } else {
- while (!stop) {
- if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
- (*pc->p >= 'A' && *pc->p <= 'Z') ||
- (*pc->p >= '0' && *pc->p <= '9') || *pc->p == '_'))
- stop = 1;
- else {
- pc->p++; pc->len--;
- }
- }
- /* Parse [dict get] syntax sugar. */
- if (*pc->p == '(') {
- while (*pc->p != ')' && pc->len) {
- pc->p++; pc->len--;
- if (*pc->p == '\\' && pc->len >= 2) {
- pc->p += 2; pc->len -= 2;
- }
- }
- if (*pc->p != '\0') {
- pc->p++; pc->len--;
- }
- ttype = JIM_TT_DICTSUGAR;
- }
- pc->tend = pc->p-1;
- }
- /* Check if we parsed just the '$' character.
- * That's not a variable so an error is returned
- * to tell the state machine to consider this '$' just
- * a string. */
- if (pc->tstart == pc->p) {
- pc->p--; pc->len++;
- return JIM_ERR;
- }
- pc->tt = ttype;
- return JIM_OK;
- }
- int JimParseBrace(struct JimParserCtx *pc)
- {
- int level = 1;
- pc->tstart = ++pc->p; pc->len--;
- pc->tline = pc->linenr;
- while (1) {
- if (*pc->p == '\\' && pc->len >= 2) {
- pc->p++; pc->len--;
- if (*pc->p == '\n')
- pc->linenr++;
- } else if (*pc->p == '{') {
- level++;
- } else if (pc->len == 0 || *pc->p == '}') {
- level--;
- if (pc->len == 0 || level == 0) {
- pc->tend = pc->p-1;
- if (pc->len != 0) {
- pc->p++; pc->len--;
- }
- pc->tt = JIM_TT_STR;
- return JIM_OK;
- }
- } else if (*pc->p == '\n') {
- pc->linenr++;
- }
- pc->p++; pc->len--;
- }
- return JIM_OK; /* unreached */
- }
- int JimParseStr(struct JimParserCtx *pc)
- {
- int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
- pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
- if (newword && *pc->p == '{') {
- return JimParseBrace(pc);
- } else if (newword && *pc->p == '"') {
- pc->state = JIM_PS_QUOTE;
- pc->p++; pc->len--;
- }
- pc->tstart = pc->p;
- pc->tline = pc->linenr;
- while (1) {
- if (pc->len == 0) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- }
- switch(*pc->p) {
- case '\\':
- if (pc->state == JIM_PS_DEF &&
- *(pc->p+1) == '\n') {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- }
- if (pc->len >= 2) {
- pc->p++; pc->len--;
- }
- break;
- case '$':
- case '[':
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- case ';':
- if (pc->state == JIM_PS_DEF) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- } else if (*pc->p == '\n') {
- pc->linenr++;
- }
- break;
- case '"':
- if (pc->state == JIM_PS_QUOTE) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- pc->p++; pc->len--;
- pc->state = JIM_PS_DEF;
- return JIM_OK;
- }
- break;
- }
- pc->p++; pc->len--;
- }
- return JIM_OK; /* unreached */
- }
- int JimParseComment(struct JimParserCtx *pc)
- {
- while (*pc->p) {
- if (*pc->p == '\n') {
- pc->linenr++;
- if (*(pc->p-1) != '\\') {
- pc->p++; pc->len--;
- return JIM_OK;
- }
- }
- pc->p++; pc->len--;
- }
- return JIM_OK;
- }
- /* xdigitval and odigitval are helper functions for JimParserGetToken() */
- static int xdigitval(int c)
- {
- if (c >= '0' && c <= '7') return c-'0';
- if (c >= 'a' && c <= 'f') return c-'a'+10;
- if (c >= 'A' && c <= 'F') return c-'A'+10;
- return -1;
- }
- static int odigitval(int c)
- {
- if (c >= '0' && c <= '7') return c-'0';
- return -1;
- }
- /* Perform Tcl escape substitution of 's', storing the result
- * string into 'dest'. The escaped string is guaranteed to
- * be the same length or shorted than the source string.
- * Slen is the length of the string at 's', if it's -1 the string
- * length will be calculated by the function.
- *
- * The function returns the length of the resulting string. */
- static int JimEscape(char *dest, const char *s, int slen)
- {
- char *p = dest;
- int i, len;
-
- if (slen == -1)
- slen = strlen(s);
- for (i = 0; i < slen; i++) {
- switch(s[i]) {
- case '\\':
- switch(s[i+1]) {
- case 'a': *p++ = 0x7; i++; break;
- case 'b': *p++ = 0x8; i++; break;
- case 'f': *p++ = 0xc; i++; break;
- case 'n': *p++ = 0xa; i++; break;
- case 'r': *p++ = 0xd; i++; break;
- case 't': *p++ = 0x9; i++; break;
- case 'v': *p++ = 0xb; i++; break;
- case '\0': *p++ = '\\'; i++; break;
- case '\n': *p++ = ' '; i++; break;
- default:
- if (s[i+1] == 'x') {
- int val = 0;
- int c = xdigitval(s[i+2]);
- if (c == -1) {
- *p++ = 'x';
- i++;
- break;
- }
- val = c;
- c = xdigitval(s[i+3]);
- if (c == -1) {
- *p++ = val;
- i += 2;
- break;
- }
- val = (val*16)+c;
- *p++ = val;
- i += 3;
- break;
- } else if (s[i+1] >= '0' && s[i+1] <= '7')
- {
- int val = 0;
- int c = odigitval(s[i+1]);
- val = c;
- c = odigitval(s[i+2]);
- if (c == -1) {
- *p++ = val;
- i ++;
- break;
- }
- val = (val*8)+c;
- c = odigitval(s[i+3]);
- if (c == -1) {
- *p++ = val;
- i += 2;
- break;
- }
- val = (val*8)+c;
- *p++ = val;
- i += 3;
- } else {
- *p++ = s[i+1];
- i++;
- }
- break;
- }
- break;
- default:
- *p++ = s[i];
- break;
- }
- }
- len = p-dest;
- *p++ = '\0';
- return len;
- }
- /* Returns a dynamically allocated copy of the current token in the
- * parser context. The function perform conversion of escapes if
- * the token is of type JIM_TT_ESC.
- *
- * Note that after the conversion, tokens that are grouped with
- * braces in the source code, are always recognizable from the
- * identical string obtained in a different way from the type.
- *
- * For exmple the string:
- *
- * {expand}$a
- *
- * will return as first token "expand", of type JIM_TT_STR
- *
- * While the string:
- *
- * expand$a
- *
- * will return as first token "expand", of type JIM_TT_ESC
- */
- char *JimParserGetToken(struct JimParserCtx *pc,
- int *lenPtr, int *typePtr, int *linePtr)
- {
- const char *start, *end;
- char *token;
- int len;
- start = JimParserTstart(pc);
- end = JimParserTend(pc);
- if (start > end) {
- if (lenPtr) *lenPtr = 0;
- if (typePtr) *typePtr = JimParserTtype(pc);
- if (linePtr) *linePtr = JimParserTline(pc);
- token = Jim_Alloc(1);
- token[0] = '\0';
- return token;
- }
- len = (end-start)+1;
- token = Jim_Alloc(len+1);
- if (JimParserTtype(pc) != JIM_TT_ESC) {
- /* No escape conversion needed? Just copy it. */
- memcpy(token, start, len);
- token[len] = '\0';
- } else {
- /* Else convert the escape chars. */
- len = JimEscape(token, start, len);
- }
- if (lenPtr) *lenPtr = len;
- if (typePtr) *typePtr = JimParserTtype(pc);
- if (linePtr) *linePtr = JimParserTline(pc);
- return token;
- }
- /* The following functin is not really part of the parsing engine of Jim,
- * but it somewhat related. Given an string and its length, it tries
- * to guess if the script is complete or there are instead " " or { }
- * open and not completed. This is useful for interactive shells
- * implementation and for [info complete].
- *
- * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
- * '{' on scripts incomplete missing one or more '}' to be balanced.
- * '"' on scripts incomplete missing a '"' char.
- *
- * If the script is complete, 1 is returned, otherwise 0. */
- int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
- {
- int level = 0;
- int state = ' ';
- while(len) {
- switch (*s) {
- case '\\':
- if (len > 1)
- s++;
- break;
- case '"':
- if (state == ' ') {
- state = '"';
- } else if (state == '"') {
- state = ' ';
- }
- break;
- case '{':
- if (state == '{') {
- level++;
- } else if (state == ' ') {
- state = '{';
- level++;
- }
- break;
- case '}':
- if (state == '{') {
- level--;
- if (level == 0)
- state = ' ';
- }
- break;
- }
- s++;
- len--;
- }
- if (stateCharPtr)
- *stateCharPtr = state;
- return state == ' ';
- }
- /* -----------------------------------------------------------------------------
- * Tcl Lists parsing
- * ---------------------------------------------------------------------------*/
- static int JimParseListSep(struct JimParserCtx *pc);
- static int JimParseListStr(struct JimParserCtx *pc);
- int JimParseList(struct JimParserCtx *pc)
- {
- if (pc->len == 0) {
- pc->tstart = pc->tend = pc->p;
- pc->tline = pc->linenr;
- pc->tt = JIM_TT_EOL;
- pc->eof = 1;
- return JIM_OK;
- }
- switch(*pc->p) {
- case ' ':
- case '\n':
- case '\t':
- case '\r':
- if (pc->state == JIM_PS_DEF)
- return JimParseListSep(pc);
- else
- return JimParseListStr(pc);
- break;
- default:
- return JimParseListStr(pc);
- break;
- }
- return JIM_OK;
- }
- int JimParseListSep(struct JimParserCtx *pc)
- {
- pc->tstart = pc->p;
- pc->tline = pc->linenr;
- while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n')
- {
- pc->p++; pc->len--;
- }
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_SEP;
- return JIM_OK;
- }
- int JimParseListStr(struct JimParserCtx *pc)
- {
- int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
- pc->tt == JIM_TT_NONE);
- if (newword && *pc->p == '{') {
- return JimParseBrace(pc);
- } else if (newword && *pc->p == '"') {
- pc->state = JIM_PS_QUOTE;
- pc->p++; pc->len--;
- }
- pc->tstart = pc->p;
- pc->tline = pc->linenr;
- while (1) {
- if (pc->len == 0) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- }
- switch(*pc->p) {
- case '\\':
- pc->p++; pc->len--;
- break;
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- if (pc->state == JIM_PS_DEF) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- return JIM_OK;
- } else if (*pc->p == '\n') {
- pc->linenr++;
- }
- break;
- case '"':
- if (pc->state == JIM_PS_QUOTE) {
- pc->tend = pc->p-1;
- pc->tt = JIM_TT_ESC;
- pc->p++; pc->len--;
- pc->state = JIM_PS_DEF;
- return JIM_OK;
- }
- break;
- }
- pc->p++; pc->len--;
- }
- return JIM_OK; /* unreached */
- }
- /* -----------------------------------------------------------------------------
- * Jim_Obj related functions
- * ---------------------------------------------------------------------------*/
- /* Return a new initialized object. */
- Jim_Obj *Jim_NewObj(Jim_Interp *interp)
- {
- Jim_Obj *objPtr;
- /* -- Check if there are objects in the free list -- */
- if (interp->freeList != NULL) {
- /* -- Unlink the object from the free list -- */
- objPtr = interp->freeList;
- interp->freeList = objPtr->nextObjPtr;
- } else {
- /* -- No ready to use objects: allocate a new one -- */
- objPtr = Jim_Alloc(sizeof(*objPtr));
- }
- /* Object is returned with refCount of 0. Every
- * kind of GC implemented should take care to don't try
- * to scan objects with refCount == 0. */
- objPtr->refCount = 0;
- /* All the other fields are left not initialized to save time.
- * The caller will probably want set they to the right
- * value anyway. */
- /* -- Put the object into the live list -- */
- obj…
Large files files are truncated, but you can click here to view the full file