Jim Tcl
Check-in [b8e69cbcb0]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:jim.c: Various minor cleanups

Small improvements to code for clarity and code reduction. Improve comments.

Signed-off-by: Steve Bennett <steveb@workware.net.au>

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b8e69cbcb0473a94f19fb5b23c51b4738b2f6af2
User & Date: steveb@workware.net.au 2017-12-02 09:51:39
Context
2017-12-31
01:45
regexp: Implement class shorthand escapes in brackets

The following class shorthand escapes now match Tcl when used within bracket expressions:

\d [[:digit:]] \s [[:space:]] \w [[:alnum:]_] (note underscore)

e.g. [a-f\d] => [a-f0-9]

Previously these shorthand escapes were only implemented outside bracket expressions.

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: aa2e5832cf user: steveb@workware.net.au tags: trunk

2017-12-02
09:51
jim.c: Various minor cleanups

Small improvements to code for clarity and code reduction. Improve comments.

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: b8e69cbcb0 user: steveb@workware.net.au tags: trunk

2017-11-29
05:46
tests: clock.test needs cmd clock

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 4d96df65f9 user: steveb@workware.net.au tags: trunk

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to jim.c.

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
364
365
366
367
368
369
370
371
372
373



374
375
376
377
378
379
380
...
391
392
393
394
395
396
397
398



399
400
401
402
403
404
405
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
...
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
....
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
....
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
....
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
....
2000
2001
2002
2003
2004
2005
2006
2007

2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
....
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
....
2230
2231
2232
2233
2234
2235
2236
2237


2238
2239
2240
2241
2242
2243
2244
....
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
....
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
....
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
....
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
....
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
....
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
....
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
....
3862
3863
3864
3865
3866
3867
3868





3869
3870
3871
3872
3873
3874
3875
....
4033
4034
4035
4036
4037
4038
4039




4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
....
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
....
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
....
4460
4461
4462
4463
4464
4465
4466



4467
4468
4469
4470
4471
4472
4473
....
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
....
4707
4708
4709
4710
4711
4712
4713
4714
4715

4716
4717
4718
4719
4720
4721
4722
            /* Is this a range? a-z */
            int start;
            int end;

            pattern += utf8_tounicode_case(pattern, &start, nocase);
            if (pattern[0] == '-' && pattern[1]) {
                /* skip '-' */
                pattern += utf8_tounicode(pattern, &pchar);
                pattern += utf8_tounicode_case(pattern, &end, nocase);

                /* Handle reversed range too */
                if ((c >= start && c <= end) || (c >= end && c <= start)) {
                    match = 1;
                }
                continue;
................................................................................
    }
    if (*s2) {
        return -1;
    }
    return 0;
}

/* 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. */



static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
{
    int i;
    int l1bytelen;

    if (!l1 || !l2 || l1 > l2) {
        return -1;
................................................................................
            return i;
        }
        s2 += utf8_tounicode(s2, &c);
    }
    return -1;
}

/**



 * Note: Lengths and return value are in bytes, not chars.
 */
static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
{
    const char *p;

    if (!l1 || !l2 || l1 > l2)
................................................................................
        }
    }
    return -1;
}

#ifdef JIM_UTF8
/**
 * Note: Lengths and return value are in chars.
 */
static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
{
    int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
    if (n > 0) {
        n = utf8_strlen(s2, n);
    }
................................................................................
            }
            endptr++;
        }
    }
    return JIM_OK;
}

/* Parses the front of a number to determine it's sign and base
 * Returns the index to start parsing according to the given base
 */
static int JimNumberBase(const char *str, int *base, int *sign)
{
    int i = 0;

    *base = 10;
................................................................................

/* ------------------------- private functions ------------------------------ */

/* Expand the hash table if needed */
static void 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)
        Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
    if (ht->size == ht->used)
        Jim_ExpandHashTable(ht, ht->size * 2);
}

/* Our hash table capability is a power of two */
................................................................................
/* Is this token an expression operator? */
#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)

/**
 * Results of missing quotes, braces, etc. from parsing.
 */
struct JimParseMissing {
    int ch;             /* At end of parse, ' ' if complete or '{', '[', '"', '\\' , '{' if incomplete */
    int line;           /* Line number starting the missing token */
};

/* Parser context structure. The same context is used both to parse
 * Tcl scripts and lists. */
struct JimParserCtx
{
    const char *p;              /* Pointer to the point of the program we are parsing */
    int len;                    /* Remaining length */
    int linenr;                 /* Current line number */
    const char *tstart;
    const char *tend;           /* Returned token is at tstart-tend in 'prg'. */
................................................................................
    return JIM_OK;
}

/*
** Here are the rules for parsing:
** {braced expression}
** - Count open and closing braces
** - Backslash escapes meaning of braces
**
** "quoted expression"
** - First double quote at start of word terminates the expression
** - Backslash escapes quote and bracket
** - [commands brackets] are counted/nested
** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules)
**
** [command expression]
** - Count open and closing brackets
** - Backslash escapes quote, bracket and brace
** - [commands brackets] are counted/nested
** - "quoted expressions" are parsed according to quoting rules
** - {braced expressions} are parsed according to brace rules
**
** For everything, backslash escapes the next char, newline increments current line
*/

................................................................................
    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'.
 *
 * 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;

................................................................................
{
    const char *start, *end;
    char *token;
    int len;

    start = pc->tstart;
    end = pc->tend;
    if (start > end) {

        len = 0;
        token = Jim_Alloc(1);
        token[0] = '\0';
    }
    else {
        len = (end - start) + 1;
        token = Jim_Alloc(len + 1);
        if (pc->tt != 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);
        }
    }

    return Jim_NewStringObjNoAlloc(interp, token, len);
}

/* -----------------------------------------------------------------------------
 * Tcl Lists parsing
................................................................................
    }
    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 to set them to the right
     * value anyway. */

    /* -- Put the object into the live list -- */
    objPtr->prevObjPtr = NULL;
    objPtr->nextObjPtr = interp->liveList;
    if (interp->liveList)
................................................................................

    dupPtr = Jim_NewObj(interp);
    if (objPtr->bytes == NULL) {
        /* Object does not have a valid string representation. */
        dupPtr->bytes = NULL;
    }
    else if (objPtr->length == 0) {
        /* Zero length, so don't even bother with the type-specific dup, since all zero length objects look the same */


        dupPtr->bytes = JimEmptyStringRep;
        dupPtr->length = 0;
        dupPtr->typePtr = NULL;
        return dupPtr;
    }
    else {
        dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
................................................................................
        objPtr->typePtr->updateStringProc(objPtr);
    }
    if (lenPtr)
        *lenPtr = objPtr->length;
    return objPtr->bytes;
}

/* Just returns the length of the object's string rep */
int Jim_Length(Jim_Obj *objPtr)
{
    if (objPtr->bytes == NULL) {
        /* Invalid string repr. Generate it. */
        JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
        objPtr->typePtr->updateStringProc(objPtr);
    }
................................................................................
    if (len == -1)
        len = strlen(s);
    /* Alloc/Set the string rep. */
    if (len == 0) {
        objPtr->bytes = JimEmptyStringRep;
    }
    else {
        objPtr->bytes = Jim_Alloc(len + 1);
        memcpy(objPtr->bytes, s, len);
        objPtr->bytes[len] = '\0';
    }
    objPtr->length = len;

    /* No typePtr field for the vanilla string object. */
    objPtr->typePtr = NULL;
    return objPtr;
}
................................................................................
 */
static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
    char *buf;
    int len;
    const char *str;

    SetStringFromAny(interp, strObjPtr);

    str = Jim_GetString(strObjPtr, &len);

#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
................................................................................
 */
static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
    char *buf;
    const char *str;
    int len;

    if (strObjPtr->typePtr != &stringObjType) {
        SetStringFromAny(interp, strObjPtr);
    }

    str = Jim_GetString(strObjPtr, &len);

#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
................................................................................
{
    char *buf, *p;
    int len;
    int c;
    const char *str;

    str = Jim_GetString(strObjPtr, &len);
    if (len == 0) {
        return strObjPtr;
    }
#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
#endif
    buf = p = Jim_Alloc(len + 1);
................................................................................
 * Note: this isn't binary safe, but it hardly needs to be.*/
int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
{
    if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
        return 1;
    }
    else {
        const char *objStr = Jim_String(objPtr);

        if (strcmp(str, objStr) != 0)
            return 0;

        if (objPtr->typePtr != &comparedStringObjType) {
            Jim_FreeIntRep(interp, objPtr);
            objPtr->typePtr = &comparedStringObjType;
        }
        objPtr->internalRep.ptr = (char *)str;  /*ATTENTION: const cast */
................................................................................
    }
}

/* Variables HashTable Type.
 *
 * Keys are dynamically allocated strings, Values are Jim_Var structures.
 */

/* Variables HashTable Type.
 *
 * Keys are dynamic allocated strings, Values are Jim_Var structures. */
static void JimVariablesHTValDestructor(void *interp, void *val)
{
    Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
    Jim_Free(val);
}

static const Jim_HashTableType JimVariablesHashTableType = {
................................................................................
        /* This command is being defined in a non-global namespace */
        nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
        Jim_AppendStrings(interp, nsObj, "::", name, NULL);
    }
    return nsObj;
}






Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
{
    Jim_Obj *resultObj;

    const char *name = Jim_String(nameObjPtr);
    if (name[0] == ':' && name[1] == ':') {
        return nameObjPtr;
................................................................................
                objPtr);
            return JIM_ERR;
        }
    }
    return JIM_OK;
}





static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
{
#ifdef jim_ext_namespace
    if (cmdPtr->isproc) {
        /* XXX: Really need JimNamespaceSplit() */
        const char *pt = strrchr(cmdname, ':');
        if (pt && pt != cmdname && pt[-1] == ':') {
            Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
            cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
            Jim_IncrRefCount(cmdPtr->u.proc.nsObj);

            if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
                /* This commands shadows a global command, so a proc epoch update is required */
                Jim_InterpIncrProcEpoch(interp);
            }
        }
    }
#endif
}

................................................................................
    FreeCommandInternalRep,
    DupCommandInternalRep,
    NULL,
    JIM_TYPE_REFERENCES,
};

/* This function returns the command structure for the command name
 * stored in objPtr. It tries to specialize the objPtr to contain
 * a cached info instead to perform the lookup into the hash table
 * every time. The information cached may not be uptodate, in such
 * a case the lookup is performed and the cache updated.
 *
 * Respects the 'upcall' setting
 */
Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
{
    Jim_Cmd *cmd;

    /* In order to be valid, the proc epoch must match and
     * the lookup must have occurred in the same namespace
................................................................................
            return NULL;
        }
#ifdef jim_ext_namespace
found:
#endif
        cmd = Jim_GetHashEntryVal(he);

        /* Free the old internal repr and set the new one. */
        Jim_FreeIntRep(interp, objPtr);
        objPtr->typePtr = &commandObjType;
        objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
        objPtr->internalRep.cmdValue.cmdPtr = cmd;
        objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
        Jim_IncrRefCount(interp->framePtr->nsObj);
    }
................................................................................

/* For now that's dummy. Variables lookup should be optimized
 * in many ways, with caching of lookups, and possibly with
 * a table of pre-allocated vars in every CallFrame for local vars.
 * All the caching should also have an 'epoch' mechanism similar
 * to the one used by Tcl for procedures lookup caching. */




int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
{
    int err;
    Jim_Var *var;

    switch (SetVariableFromAny(interp, nameObjPtr)) {
        case JIM_DICT_SUGAR:
................................................................................
    result = Jim_SetVariableStr(interp, name, objPtr);
    interp->framePtr = savedFramePtr;
    return result;
}

int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
{
    Jim_Obj *nameObjPtr, *valObjPtr;
    int result;

    nameObjPtr = Jim_NewStringObj(interp, name, -1);
    valObjPtr = Jim_NewStringObj(interp, val, -1);
    Jim_IncrRefCount(nameObjPtr);
    Jim_IncrRefCount(valObjPtr);
    result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
    Jim_DecrRefCount(interp, nameObjPtr);
    Jim_DecrRefCount(interp, valObjPtr);
    return result;
}

int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
    Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
{
................................................................................
    objPtr = Jim_GetVariableStr(interp, name, flags);
    interp->framePtr = savedFramePtr;

    return objPtr;
}

/* Unset a variable.
 * Note: On success unset invalidates all the variable objects created
 * in the current call frame incrementing. */

int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
{
    Jim_Var *varPtr;
    int retval;
    Jim_CallFrame *framePtr;

    retval = SetVariableFromAny(interp, nameObjPtr);







|







 







|

|
>
>
>







 







|
>
>
>







 







|







 







|







 







|







 







|



|
|







 







|


|
|

|



|







 







|
|







 







|
>

<
<

<
<
|
|
|
|
|
|
|
|
|
<







 







|
|

|







 







|
>
>







 







|







 







|
<
<







 







<
<







 







<
<
<
<







 







<
<
|







 







<
<
|







 







<
<
<
<







 







>
>
>
>
>







 







>
>
>
>












|







 







|
|
|
|

|







 







|







 







>
>
>







 







|


<

<

|
<







 







|
|
>







220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
....
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
....
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
....
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
....
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015


2016


2017
2018
2019
2020
2021
2022
2023
2024
2025

2026
2027
2028
2029
2030
2031
2032
....
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
....
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
....
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
....
2420
2421
2422
2423
2424
2425
2426
2427


2428
2429
2430
2431
2432
2433
2434
....
2743
2744
2745
2746
2747
2748
2749


2750
2751
2752
2753
2754
2755
2756
....
2765
2766
2767
2768
2769
2770
2771




2772
2773
2774
2775
2776
2777
2778
....
2789
2790
2791
2792
2793
2794
2795


2796
2797
2798
2799
2800
2801
2802
2803
....
3078
3079
3080
3081
3082
3083
3084


3085
3086
3087
3088
3089
3090
3091
3092
....
3792
3793
3794
3795
3796
3797
3798




3799
3800
3801
3802
3803
3804
3805
....
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
....
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
....
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
....
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
....
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
....
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532

4533

4534
4535

4536
4537
4538
4539
4540
4541
4542
....
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
            /* Is this a range? a-z */
            int start;
            int end;

            pattern += utf8_tounicode_case(pattern, &start, nocase);
            if (pattern[0] == '-' && pattern[1]) {
                /* skip '-' */
                pattern++;
                pattern += utf8_tounicode_case(pattern, &end, nocase);

                /* Handle reversed range too */
                if ((c >= start && c <= end) || (c >= end && c <= start)) {
                    match = 1;
                }
                continue;
................................................................................
    }
    if (*s2) {
        return -1;
    }
    return 0;
}

/* Search for '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.
 *
 * Note: Lengths and return value are in bytes, not chars.
 */
static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
{
    int i;
    int l1bytelen;

    if (!l1 || !l2 || l1 > l2) {
        return -1;
................................................................................
            return i;
        }
        s2 += utf8_tounicode(s2, &c);
    }
    return -1;
}

/* Search for the last occurrence 's1' inside 's2', starting to search from char 'index' of 's2'.
 * The index of the last occurrence of s1 in s2 is returned.
 * If s1 is not found inside s2, -1 is returned.
 *
 * Note: Lengths and return value are in bytes, not chars.
 */
static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
{
    const char *p;

    if (!l1 || !l2 || l1 > l2)
................................................................................
        }
    }
    return -1;
}

#ifdef JIM_UTF8
/**
 * Per JimStringLast but lengths and return value are in chars, not bytes.
 */
static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
{
    int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
    if (n > 0) {
        n = utf8_strlen(s2, n);
    }
................................................................................
            }
            endptr++;
        }
    }
    return JIM_OK;
}

/* Parses the front of a number to determine its sign and base.
 * Returns the index to start parsing according to the given base
 */
static int JimNumberBase(const char *str, int *base, int *sign)
{
    int i = 0;

    *base = 10;
................................................................................

/* ------------------------- private functions ------------------------------ */

/* Expand the hash table if needed */
static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
{
    /* If the hash table is empty expand it to the intial size,
     * if the table is "full" double its size. */
    if (ht->size == 0)
        Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
    if (ht->size == ht->used)
        Jim_ExpandHashTable(ht, ht->size * 2);
}

/* Our hash table capability is a power of two */
................................................................................
/* Is this token an expression operator? */
#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)

/**
 * Results of missing quotes, braces, etc. from parsing.
 */
struct JimParseMissing {
    int ch;             /* At end of parse, ' ' if complete or '{', '[', '"', '\\', '}' if incomplete */
    int line;           /* Line number starting the missing token */
};

/* Parser context structure. The same context is used to parse
 * Tcl scripts, expressions and lists. */
struct JimParserCtx
{
    const char *p;              /* Pointer to the point of the program we are parsing */
    int len;                    /* Remaining length */
    int linenr;                 /* Current line number */
    const char *tstart;
    const char *tend;           /* Returned token is at tstart-tend in 'prg'. */
................................................................................
    return JIM_OK;
}

/*
** Here are the rules for parsing:
** {braced expression}
** - Count open and closing braces
** - Backslash escapes meaning of braces but doesn't remove the backslash
**
** "quoted expression"
** - Unescaped double quote terminates the expression
** - Backslash escapes next char
** - [commands brackets] are counted/nested
** - command rules apply within [brackets], not quoting rules (i.e. brackets have their own rules)
**
** [command expression]
** - Count open and closing brackets
** - Backslash escapes next char
** - [commands brackets] are counted/nested
** - "quoted expressions" are parsed according to quoting rules
** - {braced expressions} are parsed according to brace rules
**
** For everything, backslash escapes the next char, newline increments current line
*/

................................................................................
    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 shorter than the source string.
 * slen is the length of the string at 's'.
 *
 * 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;

................................................................................
{
    const char *start, *end;
    char *token;
    int len;

    start = pc->tstart;
    end = pc->tend;
    len = (end - start) + 1;
    if (len < 0) {
        len = 0;


    }


    token = Jim_Alloc(len + 1);
    if (pc->tt != 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);

    }

    return Jim_NewStringObjNoAlloc(interp, token, len);
}

/* -----------------------------------------------------------------------------
 * Tcl Lists parsing
................................................................................
    }
    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 avoid
     * scanning objects with refCount == 0. */
    objPtr->refCount = 0;
    /* All the other fields are left uninitialized to save time.
     * The caller will probably want to set them to the right
     * value anyway. */

    /* -- Put the object into the live list -- */
    objPtr->prevObjPtr = NULL;
    objPtr->nextObjPtr = interp->liveList;
    if (interp->liveList)
................................................................................

    dupPtr = Jim_NewObj(interp);
    if (objPtr->bytes == NULL) {
        /* Object does not have a valid string representation. */
        dupPtr->bytes = NULL;
    }
    else if (objPtr->length == 0) {
        /* Zero length, so don't even bother with the type-specific dup,
         * since all zero length objects look the same
         */
        dupPtr->bytes = JimEmptyStringRep;
        dupPtr->length = 0;
        dupPtr->typePtr = NULL;
        return dupPtr;
    }
    else {
        dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
................................................................................
        objPtr->typePtr->updateStringProc(objPtr);
    }
    if (lenPtr)
        *lenPtr = objPtr->length;
    return objPtr->bytes;
}

/* Just returns the length (in bytes) of the object's string rep */
int Jim_Length(Jim_Obj *objPtr)
{
    if (objPtr->bytes == NULL) {
        /* Invalid string repr. Generate it. */
        JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
        objPtr->typePtr->updateStringProc(objPtr);
    }
................................................................................
    if (len == -1)
        len = strlen(s);
    /* Alloc/Set the string rep. */
    if (len == 0) {
        objPtr->bytes = JimEmptyStringRep;
    }
    else {
        objPtr->bytes = Jim_StrDupLen(s, len);


    }
    objPtr->length = len;

    /* No typePtr field for the vanilla string object. */
    objPtr->typePtr = NULL;
    return objPtr;
}
................................................................................
 */
static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
    char *buf;
    int len;
    const char *str;



    str = Jim_GetString(strObjPtr, &len);

#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
................................................................................
 */
static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
{
    char *buf;
    const char *str;
    int len;





    str = Jim_GetString(strObjPtr, &len);

#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
................................................................................
{
    char *buf, *p;
    int len;
    int c;
    const char *str;

    str = Jim_GetString(strObjPtr, &len);



#ifdef JIM_UTF8
    /* Case mapping can change the utf-8 length of the string.
     * But at worst it will be by one extra byte per char
     */
    len *= 2;
#endif
    buf = p = Jim_Alloc(len + 1);
................................................................................
 * Note: this isn't binary safe, but it hardly needs to be.*/
int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
{
    if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
        return 1;
    }
    else {


        if (strcmp(str, Jim_String(objPtr)) != 0)
            return 0;

        if (objPtr->typePtr != &comparedStringObjType) {
            Jim_FreeIntRep(interp, objPtr);
            objPtr->typePtr = &comparedStringObjType;
        }
        objPtr->internalRep.ptr = (char *)str;  /*ATTENTION: const cast */
................................................................................
    }
}

/* Variables HashTable Type.
 *
 * Keys are dynamically allocated strings, Values are Jim_Var structures.
 */




static void JimVariablesHTValDestructor(void *interp, void *val)
{
    Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
    Jim_Free(val);
}

static const Jim_HashTableType JimVariablesHashTableType = {
................................................................................
        /* This command is being defined in a non-global namespace */
        nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
        Jim_AppendStrings(interp, nsObj, "::", name, NULL);
    }
    return nsObj;
}

/**
 * If nameObjPtr starts with "::", returns it.
 * Otherwise returns a new object with nameObjPtr prefixed with "::".
 * In this case, decrements the ref count of nameObjPtr.
 */
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
{
    Jim_Obj *resultObj;

    const char *name = Jim_String(nameObjPtr);
    if (name[0] == ':' && name[1] == ':') {
        return nameObjPtr;
................................................................................
                objPtr);
            return JIM_ERR;
        }
    }
    return JIM_OK;
}

/**
 * If the command is a proc, sets/updates the cached namespace (nsObj)
 * based on the command name.
 */
static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
{
#ifdef jim_ext_namespace
    if (cmdPtr->isproc) {
        /* XXX: Really need JimNamespaceSplit() */
        const char *pt = strrchr(cmdname, ':');
        if (pt && pt != cmdname && pt[-1] == ':') {
            Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
            cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
            Jim_IncrRefCount(cmdPtr->u.proc.nsObj);

            if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
                /* This command shadows a global command, so a proc epoch update is required */
                Jim_InterpIncrProcEpoch(interp);
            }
        }
    }
#endif
}

................................................................................
    FreeCommandInternalRep,
    DupCommandInternalRep,
    NULL,
    JIM_TYPE_REFERENCES,
};

/* This function returns the command structure for the command name
 * stored in objPtr. It specializes the objPtr to contain
 * cached info instead of performing the lookup into the hash table
 * every time. The information cached may not be up-to-date, in this
 * case the lookup is performed and the cache updated.
 *
 * Respects the 'upcall' setting.
 */
Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
{
    Jim_Cmd *cmd;

    /* In order to be valid, the proc epoch must match and
     * the lookup must have occurred in the same namespace
................................................................................
            return NULL;
        }
#ifdef jim_ext_namespace
found:
#endif
        cmd = Jim_GetHashEntryVal(he);

        /* Free the old internal rep and set the new one. */
        Jim_FreeIntRep(interp, objPtr);
        objPtr->typePtr = &commandObjType;
        objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
        objPtr->internalRep.cmdValue.cmdPtr = cmd;
        objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
        Jim_IncrRefCount(interp->framePtr->nsObj);
    }
................................................................................

/* For now that's dummy. Variables lookup should be optimized
 * in many ways, with caching of lookups, and possibly with
 * a table of pre-allocated vars in every CallFrame for local vars.
 * All the caching should also have an 'epoch' mechanism similar
 * to the one used by Tcl for procedures lookup caching. */

/**
 * Set the variable nameObjPtr to value valObjptr.
 */
int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
{
    int err;
    Jim_Var *var;

    switch (SetVariableFromAny(interp, nameObjPtr)) {
        case JIM_DICT_SUGAR:
................................................................................
    result = Jim_SetVariableStr(interp, name, objPtr);
    interp->framePtr = savedFramePtr;
    return result;
}

int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
{
    Jim_Obj *valObjPtr;
    int result;


    valObjPtr = Jim_NewStringObj(interp, val, -1);

    Jim_IncrRefCount(valObjPtr);
    result = Jim_SetVariableStr(interp, name, valObjPtr);

    Jim_DecrRefCount(interp, valObjPtr);
    return result;
}

int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
    Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
{
................................................................................
    objPtr = Jim_GetVariableStr(interp, name, flags);
    interp->framePtr = savedFramePtr;

    return objPtr;
}

/* Unset a variable.
 * Note: On success unset invalidates all the (cached) variable objects
 * by incrementing callFrameEpoch
 */
int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
{
    Jim_Var *varPtr;
    int retval;
    Jim_CallFrame *framePtr;

    retval = SetVariableFromAny(interp, nameObjPtr);