Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclUtil.c @ 63

Last change on this file since 63 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 86.4 KB
Line 
1/*
2 * tclUtil.c --
3 *
4 *      This file contains utility functions that are used by many Tcl
5 *      commands.
6 *
7 * Copyright (c) 1987-1993 The Regents of the University of California.
8 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
9 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
10 *
11 * See the file "license.terms" for information on usage and redistribution of
12 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tclUtil.c,v 1.97 2008/02/26 20:18:14 hobbs Exp $
15 */
16
17#include "tclInt.h"
18#include <float.h>
19#include <math.h>
20
21/*
22 * The absolute pathname of the executable in which this Tcl library is
23 * running.
24 */
25
26static ProcessGlobalValue executableName = {
27    0, 0, NULL, NULL, NULL, NULL, NULL
28};
29
30/*
31 * The following values are used in the flags returned by Tcl_ScanElement and
32 * used by Tcl_ConvertElement. The values TCL_DONT_USE_BRACES and
33 * TCL_DONT_QUOTE_HASH are defined in tcl.h; make sure neither value overlaps
34 * with any of the values below.
35 *
36 * TCL_DONT_USE_BRACES -        1 means the string mustn't be enclosed in
37 *                              braces (e.g. it contains unmatched braces, or
38 *                              ends in a backslash character, or user just
39 *                              doesn't want braces); handle all special
40 *                              characters by adding backslashes.
41 * USE_BRACES -                 1 means the string contains a special
42 *                              character that can be handled simply by
43 *                              enclosing the entire argument in braces.
44 * BRACES_UNMATCHED -           1 means that braces aren't properly matched in
45 *                              the argument.
46 * TCL_DONT_QUOTE_HASH -        1 means the caller insists that a leading hash
47 *                              character ('#') should *not* be quoted. This
48 *                              is appropriate when the caller can guarantee
49 *                              the element is not the first element of a
50 *                              list, so [eval] cannot mis-parse the element
51 *                              as a comment.
52 */
53
54#define USE_BRACES              2
55#define BRACES_UNMATCHED        4
56
57/*
58 * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to
59 * access the precision to be used for double formatting.
60 */
61
62static Tcl_ThreadDataKey precisionKey;
63
64/*
65 * Prototypes for functions defined later in this file.
66 */
67
68static void             ClearHash(Tcl_HashTable *tablePtr);
69static void             FreeProcessGlobalValue(ClientData clientData);
70static void             FreeThreadHash(ClientData clientData);
71static Tcl_HashTable *  GetThreadHash(Tcl_ThreadDataKey *keyPtr);
72static int              SetEndOffsetFromAny(Tcl_Interp* interp,
73                            Tcl_Obj* objPtr);
74static void             UpdateStringOfEndOffset(Tcl_Obj* objPtr);
75
76/*
77 * The following is the Tcl object type definition for an object that
78 * represents a list index in the form, "end-offset". It is used as a
79 * performance optimization in TclGetIntForIndex. The internal rep is an
80 * integer, so no memory management is required for it.
81 */
82
83Tcl_ObjType tclEndOffsetType = {
84    "end-offset",                       /* name */
85    NULL,                               /* freeIntRepProc */
86    NULL,                               /* dupIntRepProc */
87    UpdateStringOfEndOffset,            /* updateStringProc */
88    SetEndOffsetFromAny
89};
90
91/*
92 *----------------------------------------------------------------------
93 *
94 * TclFindElement --
95 *
96 *      Given a pointer into a Tcl list, locate the first (or next) element in
97 *      the list.
98 *
99 * Results:
100 *      The return value is normally TCL_OK, which means that the element was
101 *      successfully located. If TCL_ERROR is returned it means that list
102 *      didn't have proper list structure; the interp's result contains a more
103 *      detailed error message.
104 *
105 *      If TCL_OK is returned, then *elementPtr will be set to point to the
106 *      first element of list, and *nextPtr will be set to point to the
107 *      character just after any white space following the last character
108 *      that's part of the element. If this is the last argument in the list,
109 *      then *nextPtr will point just after the last character in the list
110 *      (i.e., at the character at list+listLength). If sizePtr is non-NULL,
111 *      *sizePtr is filled in with the number of characters in the element. If
112 *      the element is in braces, then *elementPtr will point to the character
113 *      after the opening brace and *sizePtr will not include either of the
114 *      braces. If there isn't an element in the list, *sizePtr will be zero,
115 *      and both *elementPtr and *termPtr will point just after the last
116 *      character in the list. Note: this function does NOT collapse backslash
117 *      sequences.
118 *
119 * Side effects:
120 *      None.
121 *
122 *----------------------------------------------------------------------
123 */
124
125int
126TclFindElement(
127    Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
128                                 * NULL, then no error message is left after
129                                 * errors. */
130    CONST char *list,           /* Points to the first byte of a string
131                                 * containing a Tcl list with zero or more
132                                 * elements (possibly in braces). */
133    int listLength,             /* Number of bytes in the list's string. */
134    CONST char **elementPtr,    /* Where to put address of first significant
135                                 * character in first element of list. */
136    CONST char **nextPtr,       /* Fill in with location of character just
137                                 * after all white space following end of
138                                 * argument (next arg or end of list). */
139    int *sizePtr,               /* If non-zero, fill in with size of
140                                 * element. */
141    int *bracePtr)              /* If non-zero, fill in with non-zero/zero to
142                                 * indicate that arg was/wasn't in braces. */
143{
144    CONST char *p = list;
145    CONST char *elemStart;      /* Points to first byte of first element. */
146    CONST char *limit;          /* Points just after list's last byte. */
147    int openBraces = 0;         /* Brace nesting level during parse. */
148    int inQuotes = 0;
149    int size = 0;               /* lint. */
150    int numChars;
151    CONST char *p2;
152
153    /*
154     * Skim off leading white space and check for an opening brace or quote.
155     * We treat embedded NULLs in the list as bytes belonging to a list
156     * element.
157     */
158
159    limit = (list + listLength);
160    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
161        p++;
162    }
163    if (p == limit) {           /* no element found */
164        elemStart = limit;
165        goto done;
166    }
167
168    if (*p == '{') {
169        openBraces = 1;
170        p++;
171    } else if (*p == '"') {
172        inQuotes = 1;
173        p++;
174    }
175    elemStart = p;
176    if (bracePtr != 0) {
177        *bracePtr = openBraces;
178    }
179
180    /*
181     * Find element's end (a space, close brace, or the end of the string).
182     */
183
184    while (p < limit) {
185        switch (*p) {
186            /*
187             * Open brace: don't treat specially unless the element is in
188             * braces. In this case, keep a nesting count.
189             */
190
191        case '{':
192            if (openBraces != 0) {
193                openBraces++;
194            }
195            break;
196
197            /*
198             * Close brace: if element is in braces, keep nesting count and
199             * quit when the last close brace is seen.
200             */
201
202        case '}':
203            if (openBraces > 1) {
204                openBraces--;
205            } else if (openBraces == 1) {
206                size = (p - elemStart);
207                p++;
208                if ((p >= limit)
209                        || isspace(UCHAR(*p))) {        /* INTL: ISO space. */
210                    goto done;
211                }
212
213                /*
214                 * Garbage after the closing brace; return an error.
215                 */
216
217                if (interp != NULL) {
218                    p2 = p;
219                    while ((p2 < limit)
220                            && (!isspace(UCHAR(*p2)))   /* INTL: ISO space. */
221                            && (p2 < p+20)) {
222                        p2++;
223                    }
224                    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
225                            "list element in braces followed by \"%.*s\" "
226                            "instead of space", (int) (p2-p), p));
227                }
228                return TCL_ERROR;
229            }
230            break;
231
232            /*
233             * Backslash: skip over everything up to the end of the backslash
234             * sequence.
235             */
236
237        case '\\':
238            Tcl_UtfBackslash(p, &numChars, NULL);
239            p += (numChars - 1);
240            break;
241
242            /*
243             * Space: ignore if element is in braces or quotes; otherwise
244             * terminate element.
245             */
246
247        case ' ':
248        case '\f':
249        case '\n':
250        case '\r':
251        case '\t':
252        case '\v':
253            if ((openBraces == 0) && !inQuotes) {
254                size = (p - elemStart);
255                goto done;
256            }
257            break;
258
259            /*
260             * Double-quote: if element is in quotes then terminate it.
261             */
262
263        case '"':
264            if (inQuotes) {
265                size = (p - elemStart);
266                p++;
267                if ((p >= limit)
268                        || isspace(UCHAR(*p))) {        /* INTL: ISO space */
269                    goto done;
270                }
271
272                /*
273                 * Garbage after the closing quote; return an error.
274                 */
275
276                if (interp != NULL) {
277                    p2 = p;
278                    while ((p2 < limit)
279                            && (!isspace(UCHAR(*p2)))   /* INTL: ISO space */
280                            && (p2 < p+20)) {
281                        p2++;
282                    }
283                    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
284                            "list element in quotes followed by \"%.*s\" "
285                            "instead of space", (int) (p2-p), p));
286                }
287                return TCL_ERROR;
288            }
289            break;
290        }
291        p++;
292    }
293
294    /*
295     * End of list: terminate element.
296     */
297
298    if (p == limit) {
299        if (openBraces != 0) {
300            if (interp != NULL) {
301                Tcl_SetResult(interp, "unmatched open brace in list",
302                        TCL_STATIC);
303            }
304            return TCL_ERROR;
305        } else if (inQuotes) {
306            if (interp != NULL) {
307                Tcl_SetResult(interp, "unmatched open quote in list",
308                        TCL_STATIC);
309            }
310            return TCL_ERROR;
311        }
312        size = (p - elemStart);
313    }
314
315  done:
316    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
317        p++;
318    }
319    *elementPtr = elemStart;
320    *nextPtr = p;
321    if (sizePtr != 0) {
322        *sizePtr = size;
323    }
324    return TCL_OK;
325}
326
327/*
328 *----------------------------------------------------------------------
329 *
330 * TclCopyAndCollapse --
331 *
332 *      Copy a string and eliminate any backslashes that aren't in braces.
333 *
334 * Results:
335 *      Count characters get copied from src to dst. Along the way, if
336 *      backslash sequences are found outside braces, the backslashes are
337 *      eliminated in the copy. After scanning count chars from source, a null
338 *      character is placed at the end of dst. Returns the number of
339 *      characters that got copied.
340 *
341 * Side effects:
342 *      None.
343 *
344 *----------------------------------------------------------------------
345 */
346
347int
348TclCopyAndCollapse(
349    int count,                  /* Number of characters to copy from src. */
350    CONST char *src,            /* Copy from here... */
351    char *dst)                  /* ... to here. */
352{
353    register char c;
354    int numRead;
355    int newCount = 0;
356    int backslashCount;
357
358    for (c = *src;  count > 0;  src++, c = *src, count--) {
359        if (c == '\\') {
360            backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
361            dst += backslashCount;
362            newCount += backslashCount;
363            src += numRead-1;
364            count -= numRead-1;
365        } else {
366            *dst = c;
367            dst++;
368            newCount++;
369        }
370    }
371    *dst = 0;
372    return newCount;
373}
374
375/*
376 *----------------------------------------------------------------------
377 *
378 * Tcl_SplitList --
379 *
380 *      Splits a list up into its constituent fields.
381 *
382 * Results
383 *      The return value is normally TCL_OK, which means that the list was
384 *      successfully split up. If TCL_ERROR is returned, it means that "list"
385 *      didn't have proper list structure; the interp's result will contain a
386 *      more detailed error message.
387 *
388 *      *argvPtr will be filled in with the address of an array whose elements
389 *      point to the elements of list, in order. *argcPtr will get filled in
390 *      with the number of valid elements in the array. A single block of
391 *      memory is dynamically allocated to hold both the argv array and a copy
392 *      of the list (with backslashes and braces removed in the standard way).
393 *      The caller must eventually free this memory by calling free() on
394 *      *argvPtr. Note: *argvPtr and *argcPtr are only modified if the
395 *      function returns normally.
396 *
397 * Side effects:
398 *      Memory is allocated.
399 *
400 *----------------------------------------------------------------------
401 */
402
403int
404Tcl_SplitList(
405    Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
406                                 * NULL, no error message is left. */
407    CONST char *list,           /* Pointer to string with list structure. */
408    int *argcPtr,               /* Pointer to location to fill in with the
409                                 * number of elements in the list. */
410    CONST char ***argvPtr)      /* Pointer to place to store pointer to array
411                                 * of pointers to list elements. */
412{
413    CONST char **argv, *l, *element;
414    char *p;
415    int length, size, i, result, elSize, brace;
416
417    /*
418     * Figure out how much space to allocate. There must be enough space for
419     * both the array of pointers and also for a copy of the list. To estimate
420     * the number of pointers needed, count the number of space characters in
421     * the list.
422     */
423
424    for (size = 2, l = list; *l != 0; l++) {
425        if (isspace(UCHAR(*l))) {                       /* INTL: ISO space. */
426            size++;
427
428            /*
429             * Consecutive space can only count as a single list delimiter.
430             */
431
432            while (1) {
433                char next = *(l + 1);
434
435                if (next == '\0') {
436                    break;
437                }
438                ++l;
439                if (isspace(UCHAR(next))) {             /* INTL: ISO space. */
440                    continue;
441                }
442                break;
443            }
444        }
445    }
446    length = l - list;
447    argv = (CONST char **) ckalloc((unsigned)
448            ((size * sizeof(char *)) + length + 1));
449    for (i = 0, p = ((char *) argv) + size*sizeof(char *);
450            *list != 0;  i++) {
451        CONST char *prevList = list;
452
453        result = TclFindElement(interp, list, length, &element, &list,
454                &elSize, &brace);
455        length -= (list - prevList);
456        if (result != TCL_OK) {
457            ckfree((char *) argv);
458            return result;
459        }
460        if (*element == 0) {
461            break;
462        }
463        if (i >= size) {
464            ckfree((char *) argv);
465            if (interp != NULL) {
466                Tcl_SetResult(interp, "internal error in Tcl_SplitList",
467                        TCL_STATIC);
468            }
469            return TCL_ERROR;
470        }
471        argv[i] = p;
472        if (brace) {
473            memcpy(p, element, (size_t) elSize);
474            p += elSize;
475            *p = 0;
476            p++;
477        } else {
478            TclCopyAndCollapse(elSize, element, p);
479            p += elSize+1;
480        }
481    }
482
483    argv[i] = NULL;
484    *argvPtr = argv;
485    *argcPtr = i;
486    return TCL_OK;
487}
488
489/*
490 *----------------------------------------------------------------------
491 *
492 * TclMarkList --
493 *
494 *      Marks the locations within a string where list elements start and
495 *      computes where they end.
496 *
497 * Results
498 *      The return value is normally TCL_OK, which means that the list was
499 *      successfully split up. If TCL_ERROR is returned, it means that "list"
500 *      didn't have proper list structure; the interp's result will contain a
501 *      more detailed error message.
502 *
503 *      *argvPtr will be filled in with the address of an array whose elements
504 *      point to the places where the elements of list start, in order.
505 *      *argcPtr will get filled in with the number of valid elements in the
506 *      array. *argszPtr will get filled in with the address of an array whose
507 *      elements are the lengths of the elements of the list, in order.
508 *      Note: *argvPtr, *argcPtr and *argszPtr are only modified if the
509 *      function returns normally.
510 *
511 * Side effects:
512 *      Memory is allocated.
513 *
514 *----------------------------------------------------------------------
515 */
516
517int
518TclMarkList(
519    Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
520                                 * NULL, no error message is left. */
521    CONST char *list,           /* Pointer to string with list structure. */
522    CONST char *end,            /* Pointer to first char after the list. */
523    int *argcPtr,               /* Pointer to location to fill in with the
524                                 * number of elements in the list. */
525    CONST int **argszPtr,       /* Pointer to place to store length of list
526                                 * elements. */
527    CONST char ***argvPtr)      /* Pointer to place to store pointer to array
528                                 * of pointers to list elements. */
529{
530    CONST char **argv, *l, *element;
531    int *argn, length, size, i, result, elSize, brace;
532
533    /*
534     * Figure out how much space to allocate. There must be enough space for
535     * the array of pointers and lengths. To estimate the number of pointers
536     * needed, count the number of whitespace characters in the list.
537     */
538
539    for (size=2, l=list ; l!=end ; l++) {
540        if (isspace(UCHAR(*l))) {                       /* INTL: ISO space. */
541            size++;
542
543            /*
544             * Consecutive space can only count as a single list delimiter.
545             */
546
547            while (1) {
548                char next = *(l + 1);
549
550                if ((l+1) == end) {
551                    break;
552                }
553                ++l;
554                if (isspace(UCHAR(next))) {             /* INTL: ISO space. */
555                    continue;
556                }
557                break;
558            }
559        }
560    }
561    length = l - list;
562    argv = (CONST char **) ckalloc((unsigned) size * sizeof(char *));
563    argn = (int *) ckalloc((unsigned) size * sizeof(int *));
564
565    for (i = 0; list != end;  i++) {
566        CONST char *prevList = list;
567
568        result = TclFindElement(interp, list, length, &element, &list,
569                &elSize, &brace);
570        length -= (list - prevList);
571        if (result != TCL_OK) {
572            ckfree((char *) argv);
573            ckfree((char *) argn);
574            return result;
575        }
576        if (*element == 0) {
577            break;
578        }
579        if (i >= size) {
580            ckfree((char *) argv);
581            ckfree((char *) argn);
582            if (interp != NULL) {
583                Tcl_SetResult(interp, "internal error in TclMarkList",
584                        TCL_STATIC);
585            }
586            return TCL_ERROR;
587        }
588        argv[i] = element;
589        argn[i] = elSize;
590    }
591
592    argv[i] = NULL;
593    argn[i] = 0;
594    *argvPtr = argv;
595    *argszPtr = argn;
596    *argcPtr = i;
597    return TCL_OK;
598}
599
600/*
601 *----------------------------------------------------------------------
602 *
603 * Tcl_ScanElement --
604 *
605 *      This function is a companion function to Tcl_ConvertElement. It scans
606 *      a string to see what needs to be done to it (e.g. add backslashes or
607 *      enclosing braces) to make the string into a valid Tcl list element.
608 *
609 * Results:
610 *      The return value is an overestimate of the number of characters that
611 *      will be needed by Tcl_ConvertElement to produce a valid list element
612 *      from string. The word at *flagPtr is filled in with a value needed by
613 *      Tcl_ConvertElement when doing the actual conversion.
614 *
615 * Side effects:
616 *      None.
617 *
618 *----------------------------------------------------------------------
619 */
620
621int
622Tcl_ScanElement(
623    register CONST char *string,/* String to convert to list element. */
624    register int *flagPtr)      /* Where to store information to guide
625                                 * Tcl_ConvertCountedElement. */
626{
627    return Tcl_ScanCountedElement(string, -1, flagPtr);
628}
629
630/*
631 *----------------------------------------------------------------------
632 *
633 * Tcl_ScanCountedElement --
634 *
635 *      This function is a companion function to Tcl_ConvertCountedElement. It
636 *      scans a string to see what needs to be done to it (e.g. add
637 *      backslashes or enclosing braces) to make the string into a valid Tcl
638 *      list element. If length is -1, then the string is scanned up to the
639 *      first null byte.
640 *
641 * Results:
642 *      The return value is an overestimate of the number of characters that
643 *      will be needed by Tcl_ConvertCountedElement to produce a valid list
644 *      element from string. The word at *flagPtr is filled in with a value
645 *      needed by Tcl_ConvertCountedElement when doing the actual conversion.
646 *
647 * Side effects:
648 *      None.
649 *
650 *----------------------------------------------------------------------
651 */
652
653int
654Tcl_ScanCountedElement(
655    CONST char *string,         /* String to convert to Tcl list element. */
656    int length,                 /* Number of bytes in string, or -1. */
657    int *flagPtr)               /* Where to store information to guide
658                                 * Tcl_ConvertElement. */
659{
660    int flags, nestingLevel;
661    register CONST char *p, *lastChar;
662
663    /*
664     * This function and Tcl_ConvertElement together do two things:
665     *
666     * 1. They produce a proper list, one that will yield back the argument
667     *    strings when evaluated or when disassembled with Tcl_SplitList. This
668     *    is the most important thing.
669     *
670     * 2. They try to produce legible output, which means minimizing the use
671     *    of backslashes (using braces instead). However, there are some
672     *    situations where backslashes must be used (e.g. an element like
673     *    "{abc": the leading brace will have to be backslashed. For each
674     *    element, one of three things must be done:
675     *
676     *    (a) Use the element as-is (it doesn't contain any special
677     *        characters). This is the most desirable option.
678     *
679     *    (b) Enclose the element in braces, but leave the contents alone.
680     *        This happens if the element contains embedded space, or if it
681     *        contains characters with special interpretation ($, [, ;, or \),
682     *        or if it starts with a brace or double-quote, or if there are no
683     *        characters in the element.
684     *
685     *    (c) Don't enclose the element in braces, but add backslashes to
686     *        prevent special interpretation of special characters. This is a
687     *        last resort used when the argument would normally fall under
688     *        case (b) but contains unmatched braces. It also occurs if the
689     *        last character of the argument is a backslash or if the element
690     *        contains a backslash followed by newline.
691     *
692     * The function figures out how many bytes will be needed to store the
693     * result (actually, it overestimates). It also collects information about
694     * the element in the form of a flags word.
695     *
696     * Note: list elements produced by this function and
697     * Tcl_ConvertCountedElement must have the property that they can be
698     * enclosing in curly braces to make sub-lists. This means, for example,
699     * that we must not leave unmatched curly braces in the resulting list
700     * element. This property is necessary in order for functions like
701     * Tcl_DStringStartSublist to work.
702     */
703
704    nestingLevel = 0;
705    flags = 0;
706    if (string == NULL) {
707        string = "";
708    }
709    if (length == -1) {
710        length = strlen(string);
711    }
712    lastChar = string + length;
713    p = string;
714    if ((p == lastChar) || (*p == '{') || (*p == '"')) {
715        flags |= USE_BRACES;
716    }
717    for (; p < lastChar; p++) {
718        switch (*p) {
719        case '{':
720            nestingLevel++;
721            break;
722        case '}':
723            nestingLevel--;
724            if (nestingLevel < 0) {
725                flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
726            }
727            break;
728        case '[':
729        case '$':
730        case ';':
731        case ' ':
732        case '\f':
733        case '\n':
734        case '\r':
735        case '\t':
736        case '\v':
737            flags |= USE_BRACES;
738            break;
739        case '\\':
740            if ((p+1 == lastChar) || (p[1] == '\n')) {
741                flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
742            } else {
743                int size;
744
745                Tcl_UtfBackslash(p, &size, NULL);
746                p += size-1;
747                flags |= USE_BRACES;
748            }
749            break;
750        }
751    }
752    if (nestingLevel != 0) {
753        flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
754    }
755    *flagPtr = flags;
756
757    /*
758     * Allow enough space to backslash every character plus leave two spaces
759     * for braces.
760     */
761
762    return 2*(p-string) + 2;
763}
764
765/*
766 *----------------------------------------------------------------------
767 *
768 * Tcl_ConvertElement --
769 *
770 *      This is a companion function to Tcl_ScanElement. Given the information
771 *      produced by Tcl_ScanElement, this function converts a string to a list
772 *      element equal to that string.
773 *
774 * Results:
775 *      Information is copied to *dst in the form of a list element identical
776 *      to src (i.e. if Tcl_SplitList is applied to dst it will produce a
777 *      string identical to src). The return value is a count of the number of
778 *      characters copied (not including the terminating NULL character).
779 *
780 * Side effects:
781 *      None.
782 *
783 *----------------------------------------------------------------------
784 */
785
786int
787Tcl_ConvertElement(
788    register CONST char *src,   /* Source information for list element. */
789    register char *dst,         /* Place to put list-ified element. */
790    register int flags)         /* Flags produced by Tcl_ScanElement. */
791{
792    return Tcl_ConvertCountedElement(src, -1, dst, flags);
793}
794
795/*
796 *----------------------------------------------------------------------
797 *
798 * Tcl_ConvertCountedElement --
799 *
800 *      This is a companion function to Tcl_ScanCountedElement. Given the
801 *      information produced by Tcl_ScanCountedElement, this function converts
802 *      a string to a list element equal to that string.
803 *
804 * Results:
805 *      Information is copied to *dst in the form of a list element identical
806 *      to src (i.e. if Tcl_SplitList is applied to dst it will produce a
807 *      string identical to src). The return value is a count of the number of
808 *      characters copied (not including the terminating NULL character).
809 *
810 * Side effects:
811 *      None.
812 *
813 *----------------------------------------------------------------------
814 */
815
816int
817Tcl_ConvertCountedElement(
818    register CONST char *src,   /* Source information for list element. */
819    int length,                 /* Number of bytes in src, or -1. */
820    char *dst,                  /* Place to put list-ified element. */
821    int flags)                  /* Flags produced by Tcl_ScanElement. */
822{
823    register char *p = dst;
824    register CONST char *lastChar;
825
826    /*
827     * See the comment block at the beginning of the Tcl_ScanElement code for
828     * details of how this works.
829     */
830
831    if (src && length == -1) {
832        length = strlen(src);
833    }
834    if ((src == NULL) || (length == 0)) {
835        p[0] = '{';
836        p[1] = '}';
837        p[2] = 0;
838        return 2;
839    }
840    lastChar = src + length;
841    if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
842        flags |= USE_BRACES;
843    }
844    if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
845        *p = '{';
846        p++;
847        for (; src != lastChar; src++, p++) {
848            *p = *src;
849        }
850        *p = '}';
851        p++;
852    } else {
853        if (*src == '{') {
854            /*
855             * Can't have a leading brace unless the whole element is enclosed
856             * in braces. Add a backslash before the brace. Furthermore, this
857             * may destroy the balance between open and close braces, so set
858             * BRACES_UNMATCHED.
859             */
860
861            p[0] = '\\';
862            p[1] = '{';
863            p += 2;
864            src++;
865            flags |= BRACES_UNMATCHED;
866        } else if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
867            /*
868             * Leading '#' could be seen by [eval] as the start of a comment,
869             * if on the first element of a list, so quote it.
870             */
871
872            p[0] = '\\';
873            p[1] = '#';
874            p += 2;
875            src++;
876        }
877        for (; src != lastChar; src++) {
878            switch (*src) {
879            case ']':
880            case '[':
881            case '$':
882            case ';':
883            case ' ':
884            case '\\':
885            case '"':
886                *p = '\\';
887                p++;
888                break;
889            case '{':
890            case '}':
891                /*
892                 * It may not seem necessary to backslash braces, but it is.
893                 * The reason for this is that the resulting list element may
894                 * actually be an element of a sub-list enclosed in braces
895                 * (e.g. if Tcl_DStringStartSublist has been invoked), so
896                 * there may be a brace mismatch if the braces aren't
897                 * backslashed.
898                 */
899
900                if (flags & BRACES_UNMATCHED) {
901                    *p = '\\';
902                    p++;
903                }
904                break;
905            case '\f':
906                *p = '\\';
907                p++;
908                *p = 'f';
909                p++;
910                continue;
911            case '\n':
912                *p = '\\';
913                p++;
914                *p = 'n';
915                p++;
916                continue;
917            case '\r':
918                *p = '\\';
919                p++;
920                *p = 'r';
921                p++;
922                continue;
923            case '\t':
924                *p = '\\';
925                p++;
926                *p = 't';
927                p++;
928                continue;
929            case '\v':
930                *p = '\\';
931                p++;
932                *p = 'v';
933                p++;
934                continue;
935            }
936            *p = *src;
937            p++;
938        }
939    }
940    *p = '\0';
941    return p-dst;
942}
943
944/*
945 *----------------------------------------------------------------------
946 *
947 * Tcl_Merge --
948 *
949 *      Given a collection of strings, merge them together into a single
950 *      string that has proper Tcl list structured (i.e. Tcl_SplitList may be
951 *      used to retrieve strings equal to the original elements, and Tcl_Eval
952 *      will parse the string back into its original elements).
953 *
954 * Results:
955 *      The return value is the address of a dynamically-allocated string
956 *      containing the merged list.
957 *
958 * Side effects:
959 *      None.
960 *
961 *----------------------------------------------------------------------
962 */
963
964char *
965Tcl_Merge(
966    int argc,                   /* How many strings to merge. */
967    CONST char * CONST *argv)   /* Array of string values. */
968{
969#   define LOCAL_SIZE 20
970    int localFlags[LOCAL_SIZE], *flagPtr;
971    int numChars;
972    char *result;
973    char *dst;
974    int i;
975
976    /*
977     * Pass 1: estimate space, gather flags.
978     */
979
980    if (argc <= LOCAL_SIZE) {
981        flagPtr = localFlags;
982    } else {
983        flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
984    }
985    numChars = 1;
986    for (i = 0; i < argc; i++) {
987        numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
988    }
989
990    /*
991     * Pass two: copy into the result area.
992     */
993
994    result = (char *) ckalloc((unsigned) numChars);
995    dst = result;
996    for (i = 0; i < argc; i++) {
997        numChars = Tcl_ConvertElement(argv[i], dst,
998                flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
999        dst += numChars;
1000        *dst = ' ';
1001        dst++;
1002    }
1003    if (dst == result) {
1004        *dst = 0;
1005    } else {
1006        dst[-1] = 0;
1007    }
1008
1009    if (flagPtr != localFlags) {
1010        ckfree((char *) flagPtr);
1011    }
1012    return result;
1013}
1014
1015/*
1016 *----------------------------------------------------------------------
1017 *
1018 * Tcl_Backslash --
1019 *
1020 *      Figure out how to handle a backslash sequence.
1021 *
1022 * Results:
1023 *      The return value is the character that should be substituted in place
1024 *      of the backslash sequence that starts at src. If readPtr isn't NULL
1025 *      then it is filled in with a count of the number of characters in the
1026 *      backslash sequence.
1027 *
1028 * Side effects:
1029 *      None.
1030 *
1031 *----------------------------------------------------------------------
1032 */
1033
1034char
1035Tcl_Backslash(
1036    CONST char *src,            /* Points to the backslash character of a
1037                                 * backslash sequence. */
1038    int *readPtr)               /* Fill in with number of characters read from
1039                                 * src, unless NULL. */
1040{
1041    char buf[TCL_UTF_MAX];
1042    Tcl_UniChar ch;
1043
1044    Tcl_UtfBackslash(src, readPtr, buf);
1045    TclUtfToUniChar(buf, &ch);
1046    return (char) ch;
1047}
1048
1049/*
1050 *----------------------------------------------------------------------
1051 *
1052 * Tcl_Concat --
1053 *
1054 *      Concatenate a set of strings into a single large string.
1055 *
1056 * Results:
1057 *      The return value is dynamically-allocated string containing a
1058 *      concatenation of all the strings in argv, with spaces between the
1059 *      original argv elements.
1060 *
1061 * Side effects:
1062 *      Memory is allocated for the result; the caller is responsible for
1063 *      freeing the memory.
1064 *
1065 *----------------------------------------------------------------------
1066 */
1067
1068char *
1069Tcl_Concat(
1070    int argc,                   /* Number of strings to concatenate. */
1071    CONST char * CONST *argv)   /* Array of strings to concatenate. */
1072{
1073    int totalSize, i;
1074    char *p;
1075    char *result;
1076
1077    for (totalSize = 1, i = 0; i < argc; i++) {
1078        totalSize += strlen(argv[i]) + 1;
1079    }
1080    result = (char *) ckalloc((unsigned) totalSize);
1081    if (argc == 0) {
1082        *result = '\0';
1083        return result;
1084    }
1085    for (p = result, i = 0; i < argc; i++) {
1086        CONST char *element;
1087        int length;
1088
1089        /*
1090         * Clip white space off the front and back of the string to generate a
1091         * neater result, and ignore any empty elements.
1092         */
1093
1094        element = argv[i];
1095        while (isspace(UCHAR(*element))) { /* INTL: ISO space. */
1096            element++;
1097        }
1098        for (length = strlen(element);
1099                (length > 0)
1100                && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */
1101                && ((length < 2) || (element[length-2] != '\\'));
1102                length--) {
1103            /* Null loop body. */
1104        }
1105        if (length == 0) {
1106            continue;
1107        }
1108        memcpy(p, element, (size_t) length);
1109        p += length;
1110        *p = ' ';
1111        p++;
1112    }
1113    if (p != result) {
1114        p[-1] = 0;
1115    } else {
1116        *p = 0;
1117    }
1118    return result;
1119}
1120
1121/*
1122 *----------------------------------------------------------------------
1123 *
1124 * Tcl_ConcatObj --
1125 *
1126 *      Concatenate the strings from a set of objects into a single string
1127 *      object with spaces between the original strings.
1128 *
1129 * Results:
1130 *      The return value is a new string object containing a concatenation of
1131 *      the strings in objv. Its ref count is zero.
1132 *
1133 * Side effects:
1134 *      A new object is created.
1135 *
1136 *----------------------------------------------------------------------
1137 */
1138
1139Tcl_Obj *
1140Tcl_ConcatObj(
1141    int objc,                   /* Number of objects to concatenate. */
1142    Tcl_Obj *CONST objv[])      /* Array of objects to concatenate. */
1143{
1144    int allocSize, finalSize, length, elemLength, i;
1145    char *p;
1146    char *element;
1147    char *concatStr;
1148    Tcl_Obj *objPtr, *resPtr;
1149
1150    /*
1151     * Check first to see if all the items are of list type or empty. If so,
1152     * we will concat them together as lists, and return a list object. This
1153     * is only valid when the lists have no current string representation,
1154     * since we don't know what the original type was. An original string rep
1155     * may have lost some whitespace info when converted which could be
1156     * important.
1157     */
1158
1159    for (i = 0;  i < objc;  i++) {
1160        List *listRepPtr;
1161
1162        objPtr = objv[i];
1163        if (objPtr->typePtr != &tclListType) {
1164            TclGetString(objPtr);
1165            if (objPtr->length) {
1166                break;
1167            } else {
1168                continue;
1169            }
1170        }
1171        listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1;
1172        if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) {
1173            break;
1174        }
1175    }
1176    if (i == objc) {
1177        Tcl_Obj **listv;
1178        int listc;
1179
1180        resPtr = NULL;
1181        for (i = 0;  i < objc;  i++) {
1182            /*
1183             * Tcl_ListObjAppendList could be used here, but this saves us a
1184             * bit of type checking (since we've already done it). Use of
1185             * INT_MAX tells us to always put the new stuff on the end. It
1186             * will be set right in Tcl_ListObjReplace.
1187             * Note that all objs at this point are either lists or have an
1188             * empty string rep.
1189             */
1190
1191            objPtr = objv[i];
1192            if (objPtr->bytes && !objPtr->length) {
1193                continue;
1194            }
1195            TclListObjGetElements(NULL, objPtr, &listc, &listv);
1196            if (listc) {
1197                if (resPtr) {
1198                    Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv);
1199                } else {
1200                    if (Tcl_IsShared(objPtr)) {
1201                        resPtr = TclListObjCopy(NULL, objPtr);
1202                    } else {
1203                        resPtr = objPtr;
1204                    }
1205                }
1206            }
1207        }
1208        if (!resPtr) {
1209            resPtr = Tcl_NewObj();
1210        }
1211        return resPtr;
1212    }
1213
1214    /*
1215     * Something cannot be determined to be safe, so build the concatenation
1216     * the slow way, using the string representations.
1217     */
1218
1219    allocSize = 0;
1220    for (i = 0;  i < objc;  i++) {
1221        objPtr = objv[i];
1222        element = TclGetStringFromObj(objPtr, &length);
1223        if ((element != NULL) && (length > 0)) {
1224            allocSize += (length + 1);
1225        }
1226    }
1227    if (allocSize == 0) {
1228        allocSize = 1;          /* enough for the NULL byte at end */
1229    }
1230
1231    /*
1232     * Allocate storage for the concatenated result. Note that allocSize is
1233     * one more than the total number of characters, and so includes room for
1234     * the terminating NULL byte.
1235     */
1236
1237    concatStr = ckalloc((unsigned) allocSize);
1238
1239    /*
1240     * Now concatenate the elements. Clip white space off the front and back
1241     * to generate a neater result, and ignore any empty elements. Also put a
1242     * null byte at the end.
1243     */
1244
1245    finalSize = 0;
1246    if (objc == 0) {
1247        *concatStr = '\0';
1248    } else {
1249        p = concatStr;
1250        for (i = 0;  i < objc;  i++) {
1251            objPtr = objv[i];
1252            element = TclGetStringFromObj(objPtr, &elemLength);
1253            while ((elemLength > 0) && (UCHAR(*element) < 127)
1254                    && isspace(UCHAR(*element))) { /* INTL: ISO C space. */
1255                element++;
1256                elemLength--;
1257            }
1258
1259            /*
1260             * Trim trailing white space. But, be careful not to trim a space
1261             * character if it is preceded by a backslash: in this case it
1262             * could be significant.
1263             */
1264
1265            while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127)
1266                    && isspace(UCHAR(element[elemLength-1]))
1267                                                /* INTL: ISO C space. */
1268                    && ((elemLength < 2) || (element[elemLength-2] != '\\'))) {
1269                elemLength--;
1270            }
1271            if (elemLength == 0) {
1272                continue;       /* nothing left of this element */
1273            }
1274            memcpy(p, element, (size_t) elemLength);
1275            p += elemLength;
1276            *p = ' ';
1277            p++;
1278            finalSize += (elemLength + 1);
1279        }
1280        if (p != concatStr) {
1281            p[-1] = 0;
1282            finalSize -= 1;     /* we overwrote the final ' ' */
1283        } else {
1284            *p = 0;
1285        }
1286    }
1287
1288    TclNewObj(objPtr);
1289    objPtr->bytes = concatStr;
1290    objPtr->length = finalSize;
1291    return objPtr;
1292}
1293
1294/*
1295 *----------------------------------------------------------------------
1296 *
1297 * Tcl_StringMatch --
1298 *
1299 *      See if a particular string matches a particular pattern.
1300 *
1301 * Results:
1302 *      The return value is 1 if string matches pattern, and 0 otherwise. The
1303 *      matching operation permits the following special characters in the
1304 *      pattern: *?\[] (see the manual entry for details on what these mean).
1305 *
1306 * Side effects:
1307 *      None.
1308 *
1309 *----------------------------------------------------------------------
1310 */
1311
1312int
1313Tcl_StringMatch(
1314    CONST char *str,            /* String. */
1315    CONST char *pattern)        /* Pattern, which may contain special
1316                                 * characters. */
1317{
1318    return Tcl_StringCaseMatch(str, pattern, 0);
1319}
1320
1321/*
1322 *----------------------------------------------------------------------
1323 *
1324 * Tcl_StringCaseMatch --
1325 *
1326 *      See if a particular string matches a particular pattern. Allows case
1327 *      insensitivity.
1328 *
1329 * Results:
1330 *      The return value is 1 if string matches pattern, and 0 otherwise. The
1331 *      matching operation permits the following special characters in the
1332 *      pattern: *?\[] (see the manual entry for details on what these mean).
1333 *
1334 * Side effects:
1335 *      None.
1336 *
1337 *----------------------------------------------------------------------
1338 */
1339
1340int
1341Tcl_StringCaseMatch(
1342    CONST char *str,            /* String. */
1343    CONST char *pattern,        /* Pattern, which may contain special
1344                                 * characters. */
1345    int nocase)                 /* 0 for case sensitive, 1 for insensitive */
1346{
1347    int p, charLen;
1348    CONST char *pstart = pattern;
1349    Tcl_UniChar ch1, ch2;
1350
1351    while (1) {
1352        p = *pattern;
1353
1354        /*
1355         * See if we're at the end of both the pattern and the string. If so,
1356         * we succeeded. If we're at the end of the pattern but not at the end
1357         * of the string, we failed.
1358         */
1359
1360        if (p == '\0') {
1361            return (*str == '\0');
1362        }
1363        if ((*str == '\0') && (p != '*')) {
1364            return 0;
1365        }
1366
1367        /*
1368         * Check for a "*" as the next pattern character. It matches any
1369         * substring. We handle this by calling ourselves recursively for each
1370         * postfix of string, until either we match or we reach the end of the
1371         * string.
1372         */
1373
1374        if (p == '*') {
1375            /*
1376             * Skip all successive *'s in the pattern
1377             */
1378
1379            while (*(++pattern) == '*') {}
1380            p = *pattern;
1381            if (p == '\0') {
1382                return 1;
1383            }
1384
1385            /*
1386             * This is a special case optimization for single-byte utf.
1387             */
1388
1389            if (UCHAR(*pattern) < 0x80) {
1390                ch2 = (Tcl_UniChar)
1391                        (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
1392            } else {
1393                Tcl_UtfToUniChar(pattern, &ch2);
1394                if (nocase) {
1395                    ch2 = Tcl_UniCharToLower(ch2);
1396                }
1397            }
1398
1399            while (1) {
1400                /*
1401                 * Optimization for matching - cruise through the string
1402                 * quickly if the next char in the pattern isn't a special
1403                 * character
1404                 */
1405
1406                if ((p != '[') && (p != '?') && (p != '\\')) {
1407                    if (nocase) {
1408                        while (*str) {
1409                            charLen = TclUtfToUniChar(str, &ch1);
1410                            if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) {
1411                                break;
1412                            }
1413                            str += charLen;
1414                        }
1415                    } else {
1416                        /*
1417                         * There's no point in trying to make this code
1418                         * shorter, as the number of bytes you want to compare
1419                         * each time is non-constant.
1420                         */
1421
1422                        while (*str) {
1423                            charLen = TclUtfToUniChar(str, &ch1);
1424                            if (ch2 == ch1) {
1425                                break;
1426                            }
1427                            str += charLen;
1428                        }
1429                    }
1430                }
1431                if (Tcl_StringCaseMatch(str, pattern, nocase)) {
1432                    return 1;
1433                }
1434                if (*str == '\0') {
1435                    return 0;
1436                }
1437                str += TclUtfToUniChar(str, &ch1);
1438            }
1439        }
1440
1441        /*
1442         * Check for a "?" as the next pattern character. It matches any
1443         * single character.
1444         */
1445
1446        if (p == '?') {
1447            pattern++;
1448            str += TclUtfToUniChar(str, &ch1);
1449            continue;
1450        }
1451
1452        /*
1453         * Check for a "[" as the next pattern character. It is followed by a
1454         * list of characters that are acceptable, or by a range (two
1455         * characters separated by "-").
1456         */
1457
1458        if (p == '[') {
1459            Tcl_UniChar startChar, endChar;
1460
1461            pattern++;
1462            if (UCHAR(*str) < 0x80) {
1463                ch1 = (Tcl_UniChar)
1464                        (nocase ? tolower(UCHAR(*str)) : UCHAR(*str));
1465                str++;
1466            } else {
1467                str += Tcl_UtfToUniChar(str, &ch1);
1468                if (nocase) {
1469                    ch1 = Tcl_UniCharToLower(ch1);
1470                }
1471            }
1472            while (1) {
1473                if ((*pattern == ']') || (*pattern == '\0')) {
1474                    return 0;
1475                }
1476                if (UCHAR(*pattern) < 0x80) {
1477                    startChar = (Tcl_UniChar) (nocase
1478                            ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
1479                    pattern++;
1480                } else {
1481                    pattern += Tcl_UtfToUniChar(pattern, &startChar);
1482                    if (nocase) {
1483                        startChar = Tcl_UniCharToLower(startChar);
1484                    }
1485                }
1486                if (*pattern == '-') {
1487                    pattern++;
1488                    if (*pattern == '\0') {
1489                        return 0;
1490                    }
1491                    if (UCHAR(*pattern) < 0x80) {
1492                        endChar = (Tcl_UniChar) (nocase
1493                                ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
1494                        pattern++;
1495                    } else {
1496                        pattern += Tcl_UtfToUniChar(pattern, &endChar);
1497                        if (nocase) {
1498                            endChar = Tcl_UniCharToLower(endChar);
1499                        }
1500                    }
1501                    if (((startChar <= ch1) && (ch1 <= endChar))
1502                            || ((endChar <= ch1) && (ch1 <= startChar))) {
1503                        /*
1504                         * Matches ranges of form [a-z] or [z-a].
1505                         */
1506
1507                        break;
1508                    }
1509                } else if (startChar == ch1) {
1510                    break;
1511                }
1512            }
1513            while (*pattern != ']') {
1514                if (*pattern == '\0') {
1515                    pattern = Tcl_UtfPrev(pattern, pstart);
1516                    break;
1517                }
1518                pattern++;
1519            }
1520            pattern++;
1521            continue;
1522        }
1523
1524        /*
1525         * If the next pattern character is '\', just strip off the '\' so we
1526         * do exact matching on the character that follows.
1527         */
1528
1529        if (p == '\\') {
1530            pattern++;
1531            if (*pattern == '\0') {
1532                return 0;
1533            }
1534        }
1535
1536        /*
1537         * There's no special character. Just make sure that the next bytes of
1538         * each string match.
1539         */
1540
1541        str += TclUtfToUniChar(str, &ch1);
1542        pattern += TclUtfToUniChar(pattern, &ch2);
1543        if (nocase) {
1544            if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) {
1545                return 0;
1546            }
1547        } else if (ch1 != ch2) {
1548            return 0;
1549        }
1550    }
1551}
1552
1553/*
1554 *----------------------------------------------------------------------
1555 *
1556 * TclByteArrayMatch --
1557 *
1558 *      See if a particular string matches a particular pattern.  Does not
1559 *      allow for case insensitivity.
1560 *      Parallels tclUtf.c:TclUniCharMatch, adjusted for char* and sans nocase.
1561 *
1562 * Results:
1563 *      The return value is 1 if string matches pattern, and 0 otherwise. The
1564 *      matching operation permits the following special characters in the
1565 *      pattern: *?\[] (see the manual entry for details on what these mean).
1566 *
1567 * Side effects:
1568 *      None.
1569 *
1570 *----------------------------------------------------------------------
1571 */
1572
1573int
1574TclByteArrayMatch(
1575    const unsigned char *string,        /* String. */
1576    int strLen,                         /* Length of String */
1577    const unsigned char *pattern,       /* Pattern, which may contain special
1578                                         * characters. */
1579    int ptnLen,                         /* Length of Pattern */
1580    int flags)
1581{
1582    const unsigned char *stringEnd, *patternEnd;
1583    unsigned char p;
1584
1585    stringEnd = string + strLen;
1586    patternEnd = pattern + ptnLen;
1587
1588    while (1) {
1589        /*
1590         * See if we're at the end of both the pattern and the string. If so,
1591         * we succeeded. If we're at the end of the pattern but not at the end
1592         * of the string, we failed.
1593         */
1594
1595        if (pattern == patternEnd) {
1596            return (string == stringEnd);
1597        }
1598        p = *pattern;
1599        if ((string == stringEnd) && (p != '*')) {
1600            return 0;
1601        }
1602
1603        /*
1604         * Check for a "*" as the next pattern character. It matches any
1605         * substring. We handle this by skipping all the characters up to the
1606         * next matching one in the pattern, and then calling ourselves
1607         * recursively for each postfix of string, until either we match or we
1608         * reach the end of the string.
1609         */
1610
1611        if (p == '*') {
1612            /*
1613             * Skip all successive *'s in the pattern.
1614             */
1615
1616            while (*(++pattern) == '*') {
1617                /* empty body */
1618            }
1619            if (pattern == patternEnd) {
1620                return 1;
1621            }
1622            p = *pattern;
1623            while (1) {
1624                /*
1625                 * Optimization for matching - cruise through the string
1626                 * quickly if the next char in the pattern isn't a special
1627                 * character.
1628                 */
1629
1630                if ((p != '[') && (p != '?') && (p != '\\')) {
1631                    while ((string < stringEnd) && (p != *string)) {
1632                        string++;
1633                    }
1634                }
1635                if (TclByteArrayMatch(string, stringEnd - string,
1636                                pattern, patternEnd - pattern, 0)) {
1637                    return 1;
1638                }
1639                if (string == stringEnd) {
1640                    return 0;
1641                }
1642                string++;
1643            }
1644        }
1645
1646        /*
1647         * Check for a "?" as the next pattern character. It matches any
1648         * single character.
1649         */
1650
1651        if (p == '?') {
1652            pattern++;
1653            string++;
1654            continue;
1655        }
1656
1657        /*
1658         * Check for a "[" as the next pattern character. It is followed by a
1659         * list of characters that are acceptable, or by a range (two
1660         * characters separated by "-").
1661         */
1662
1663        if (p == '[') {
1664            unsigned char ch1, startChar, endChar;
1665
1666            pattern++;
1667            ch1 = *string;
1668            string++;
1669            while (1) {
1670                if ((*pattern == ']') || (pattern == patternEnd)) {
1671                    return 0;
1672                }
1673                startChar = *pattern;
1674                pattern++;
1675                if (*pattern == '-') {
1676                    pattern++;
1677                    if (pattern == patternEnd) {
1678                        return 0;
1679                    }
1680                    endChar = *pattern;
1681                    pattern++;
1682                    if (((startChar <= ch1) && (ch1 <= endChar))
1683                            || ((endChar <= ch1) && (ch1 <= startChar))) {
1684                        /*
1685                         * Matches ranges of form [a-z] or [z-a].
1686                         */
1687                        break;
1688                    }
1689                } else if (startChar == ch1) {
1690                    break;
1691                }
1692            }
1693            while (*pattern != ']') {
1694                if (pattern == patternEnd) {
1695                    pattern--;
1696                    break;
1697                }
1698                pattern++;
1699            }
1700            pattern++;
1701            continue;
1702        }
1703
1704        /*
1705         * If the next pattern character is '\', just strip off the '\' so we
1706         * do exact matching on the character that follows.
1707         */
1708
1709        if (p == '\\') {
1710            if (++pattern == patternEnd) {
1711                return 0;
1712            }
1713        }
1714
1715        /*
1716         * There's no special character. Just make sure that the next bytes of
1717         * each string match.
1718         */
1719
1720        if (*string != *pattern) {
1721            return 0;
1722        }
1723        string++;
1724        pattern++;
1725    }
1726}
1727
1728/*
1729 *----------------------------------------------------------------------
1730 *
1731 * TclStringMatchObj --
1732 *
1733 *      See if a particular string matches a particular pattern.
1734 *      Allows case insensitivity.  This is the generic multi-type handler
1735 *      for the various matching algorithms.
1736 *
1737 * Results:
1738 *      The return value is 1 if string matches pattern, and 0 otherwise. The
1739 *      matching operation permits the following special characters in the
1740 *      pattern: *?\[] (see the manual entry for details on what these mean).
1741 *
1742 * Side effects:
1743 *      None.
1744 *
1745 *----------------------------------------------------------------------
1746 */
1747
1748int
1749TclStringMatchObj(
1750    Tcl_Obj *strObj,    /* string object. */
1751    Tcl_Obj *ptnObj,    /* pattern object. */
1752    int flags)          /* Only TCL_MATCH_NOCASE should be passed or 0. */
1753{
1754    int match, length, plen;
1755
1756    /*
1757     * Promote based on the type of incoming object.
1758     * XXX: Currently doesn't take advantage of exact-ness that
1759     * XXX: TclReToGlob tells us about
1760    trivial = nocase ? 0 : TclMatchIsTrivial(TclGetString(ptnObj));
1761     */
1762
1763    if ((strObj->typePtr == &tclStringType)) {
1764        Tcl_UniChar *udata, *uptn;
1765
1766        udata = Tcl_GetUnicodeFromObj(strObj, &length);
1767        uptn  = Tcl_GetUnicodeFromObj(ptnObj, &plen);
1768        match = TclUniCharMatch(udata, length, uptn, plen, flags);
1769    } else if ((strObj->typePtr == &tclByteArrayType) && !flags) {
1770        unsigned char *data, *ptn;
1771
1772        data = Tcl_GetByteArrayFromObj(strObj, &length);
1773        ptn  = Tcl_GetByteArrayFromObj(ptnObj, &plen);
1774        match = TclByteArrayMatch(data, length, ptn, plen, 0);
1775    } else {
1776        match = Tcl_StringCaseMatch(TclGetString(strObj),
1777                TclGetString(ptnObj), flags);
1778    }
1779    return match;
1780}
1781
1782/*
1783 *----------------------------------------------------------------------
1784 *
1785 * Tcl_DStringInit --
1786 *
1787 *      Initializes a dynamic string, discarding any previous contents of the
1788 *      string (Tcl_DStringFree should have been called already if the dynamic
1789 *      string was previously in use).
1790 *
1791 * Results:
1792 *      None.
1793 *
1794 * Side effects:
1795 *      The dynamic string is initialized to be empty.
1796 *
1797 *----------------------------------------------------------------------
1798 */
1799
1800void
1801Tcl_DStringInit(
1802    Tcl_DString *dsPtr)         /* Pointer to structure for dynamic string. */
1803{
1804    dsPtr->string = dsPtr->staticSpace;
1805    dsPtr->length = 0;
1806    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
1807    dsPtr->staticSpace[0] = '\0';
1808}
1809
1810/*
1811 *----------------------------------------------------------------------
1812 *
1813 * Tcl_DStringAppend --
1814 *
1815 *      Append more bytes to the current value of a dynamic string.
1816 *
1817 * Results:
1818 *      The return value is a pointer to the dynamic string's new value.
1819 *
1820 * Side effects:
1821 *      Length bytes from "bytes" (or all of "bytes" if length is less than
1822 *      zero) are added to the current value of the string. Memory gets
1823 *      reallocated if needed to accomodate the string's new size.
1824 *
1825 *----------------------------------------------------------------------
1826 */
1827
1828char *
1829Tcl_DStringAppend(
1830    Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
1831    CONST char *bytes,          /* String to append. If length is -1 then this
1832                                 * must be null-terminated. */
1833    int length)                 /* Number of bytes from "bytes" to append. If
1834                                 * < 0, then append all of bytes, up to null
1835                                 * at end. */
1836{
1837    int newSize;
1838    char *dst;
1839    CONST char *end;
1840
1841    if (length < 0) {
1842        length = strlen(bytes);
1843    }
1844    newSize = length + dsPtr->length;
1845
1846    /*
1847     * Allocate a larger buffer for the string if the current one isn't large
1848     * enough. Allocate extra space in the new buffer so that there will be
1849     * room to grow before we have to allocate again.
1850     */
1851
1852    if (newSize >= dsPtr->spaceAvl) {
1853        dsPtr->spaceAvl = newSize * 2;
1854        if (dsPtr->string == dsPtr->staticSpace) {
1855            char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
1856
1857            memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
1858            dsPtr->string = newString;
1859        } else {
1860            dsPtr->string = ckrealloc((void *) dsPtr->string,
1861                    (size_t) dsPtr->spaceAvl);
1862        }
1863    }
1864
1865    /*
1866     * Copy the new string into the buffer at the end of the old one.
1867     */
1868
1869    for (dst = dsPtr->string + dsPtr->length, end = bytes+length;
1870            bytes < end; bytes++, dst++) {
1871        *dst = *bytes;
1872    }
1873    *dst = '\0';
1874    dsPtr->length += length;
1875    return dsPtr->string;
1876}
1877
1878/*
1879 *----------------------------------------------------------------------
1880 *
1881 * Tcl_DStringAppendElement --
1882 *
1883 *      Append a list element to the current value of a dynamic string.
1884 *
1885 * Results:
1886 *      The return value is a pointer to the dynamic string's new value.
1887 *
1888 * Side effects:
1889 *      String is reformatted as a list element and added to the current value
1890 *      of the string. Memory gets reallocated if needed to accomodate the
1891 *      string's new size.
1892 *
1893 *----------------------------------------------------------------------
1894 */
1895
1896char *
1897Tcl_DStringAppendElement(
1898    Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
1899    CONST char *element)        /* String to append. Must be
1900                                 * null-terminated. */
1901{
1902    int newSize, flags, strSize;
1903    char *dst;
1904
1905    strSize = ((element== NULL) ? 0 : strlen(element));
1906    newSize = Tcl_ScanCountedElement(element, strSize, &flags)
1907        + dsPtr->length + 1;
1908
1909    /*
1910     * Allocate a larger buffer for the string if the current one isn't large
1911     * enough. Allocate extra space in the new buffer so that there will be
1912     * room to grow before we have to allocate again. SPECIAL NOTE: must use
1913     * memcpy, not strcpy, to copy the string to a larger buffer, since there
1914     * may be embedded NULLs in the string in some cases.
1915     */
1916
1917    if (newSize >= dsPtr->spaceAvl) {
1918        dsPtr->spaceAvl = newSize * 2;
1919        if (dsPtr->string == dsPtr->staticSpace) {
1920            char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
1921
1922            memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
1923            dsPtr->string = newString;
1924        } else {
1925            dsPtr->string = (char *) ckrealloc((void *) dsPtr->string,
1926                    (size_t) dsPtr->spaceAvl);
1927        }
1928    }
1929
1930    /*
1931     * Convert the new string to a list element and copy it into the buffer at
1932     * the end, with a space, if needed.
1933     */
1934
1935    dst = dsPtr->string + dsPtr->length;
1936    if (TclNeedSpace(dsPtr->string, dst)) {
1937        *dst = ' ';
1938        dst++;
1939        dsPtr->length++;
1940
1941        /*
1942         * If we need a space to separate this element from preceding stuff,
1943         * then this element will not lead a list, and need not have it's
1944         * leading '#' quoted.
1945         */
1946
1947        flags |= TCL_DONT_QUOTE_HASH;
1948    }
1949    dsPtr->length += Tcl_ConvertCountedElement(element, strSize, dst, flags);
1950    return dsPtr->string;
1951}
1952
1953/*
1954 *----------------------------------------------------------------------
1955 *
1956 * Tcl_DStringSetLength --
1957 *
1958 *      Change the length of a dynamic string. This can cause the string to
1959 *      either grow or shrink, depending on the value of length.
1960 *
1961 * Results:
1962 *      None.
1963 *
1964 * Side effects:
1965 *      The length of dsPtr is changed to length and a null byte is stored at
1966 *      that position in the string. If length is larger than the space
1967 *      allocated for dsPtr, then a panic occurs.
1968 *
1969 *----------------------------------------------------------------------
1970 */
1971
1972void
1973Tcl_DStringSetLength(
1974    Tcl_DString *dsPtr,         /* Structure describing dynamic string. */
1975    int length)                 /* New length for dynamic string. */
1976{
1977    int newsize;
1978
1979    if (length < 0) {
1980        length = 0;
1981    }
1982    if (length >= dsPtr->spaceAvl) {
1983        /*
1984         * There are two interesting cases here. In the first case, the user
1985         * may be trying to allocate a large buffer of a specific size. It
1986         * would be wasteful to overallocate that buffer, so we just allocate
1987         * enough for the requested size plus the trailing null byte. In the
1988         * second case, we are growing the buffer incrementally, so we need
1989         * behavior similar to Tcl_DStringAppend. The requested length will
1990         * usually be a small delta above the current spaceAvl, so we'll end
1991         * up doubling the old size. This won't grow the buffer quite as
1992         * quickly, but it should be close enough.
1993         */
1994
1995        newsize = dsPtr->spaceAvl * 2;
1996        if (length < newsize) {
1997            dsPtr->spaceAvl = newsize;
1998        } else {
1999            dsPtr->spaceAvl = length + 1;
2000        }
2001        if (dsPtr->string == dsPtr->staticSpace) {
2002            char *newString = ckalloc((unsigned) dsPtr->spaceAvl);
2003
2004            memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
2005            dsPtr->string = newString;
2006        } else {
2007            dsPtr->string = (char *) ckrealloc((void *) dsPtr->string,
2008                    (size_t) dsPtr->spaceAvl);
2009        }
2010    }
2011    dsPtr->length = length;
2012    dsPtr->string[length] = 0;
2013}
2014
2015/*
2016 *----------------------------------------------------------------------
2017 *
2018 * Tcl_DStringFree --
2019 *
2020 *      Frees up any memory allocated for the dynamic string and reinitializes
2021 *      the string to an empty state.
2022 *
2023 * Results:
2024 *      None.
2025 *
2026 * Side effects:
2027 *      The previous contents of the dynamic string are lost, and the new
2028 *      value is an empty string.
2029 *
2030 *----------------------------------------------------------------------
2031 */
2032
2033void
2034Tcl_DStringFree(
2035    Tcl_DString *dsPtr)         /* Structure describing dynamic string. */
2036{
2037    if (dsPtr->string != dsPtr->staticSpace) {
2038        ckfree(dsPtr->string);
2039    }
2040    dsPtr->string = dsPtr->staticSpace;
2041    dsPtr->length = 0;
2042    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
2043    dsPtr->staticSpace[0] = '\0';
2044}
2045
2046/*
2047 *----------------------------------------------------------------------
2048 *
2049 * Tcl_DStringResult --
2050 *
2051 *      This function moves the value of a dynamic string into an interpreter
2052 *      as its string result. Afterwards, the dynamic string is reset to an
2053 *      empty string.
2054 *
2055 * Results:
2056 *      None.
2057 *
2058 * Side effects:
2059 *      The string is "moved" to interp's result, and any existing string
2060 *      result for interp is freed. dsPtr is reinitialized to an empty string.
2061 *
2062 *----------------------------------------------------------------------
2063 */
2064
2065void
2066Tcl_DStringResult(
2067    Tcl_Interp *interp,         /* Interpreter whose result is to be reset. */
2068    Tcl_DString *dsPtr)         /* Dynamic string that is to become the
2069                                 * result of interp. */
2070{
2071    Tcl_ResetResult(interp);
2072
2073    if (dsPtr->string != dsPtr->staticSpace) {
2074        interp->result = dsPtr->string;
2075        interp->freeProc = TCL_DYNAMIC;
2076    } else if (dsPtr->length < TCL_RESULT_SIZE) {
2077        interp->result = ((Interp *) interp)->resultSpace;
2078        strcpy(interp->result, dsPtr->string);
2079    } else {
2080        Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
2081    }
2082
2083    dsPtr->string = dsPtr->staticSpace;
2084    dsPtr->length = 0;
2085    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
2086    dsPtr->staticSpace[0] = '\0';
2087}
2088
2089/*
2090 *----------------------------------------------------------------------
2091 *
2092 * Tcl_DStringGetResult --
2093 *
2094 *      This function moves an interpreter's result into a dynamic string.
2095 *
2096 * Results:
2097 *      None.
2098 *
2099 * Side effects:
2100 *      The interpreter's string result is cleared, and the previous contents
2101 *      of dsPtr are freed.
2102 *
2103 *      If the string result is empty, the object result is moved to the
2104 *      string result, then the object result is reset.
2105 *
2106 *----------------------------------------------------------------------
2107 */
2108
2109void
2110Tcl_DStringGetResult(
2111    Tcl_Interp *interp,         /* Interpreter whose result is to be reset. */
2112    Tcl_DString *dsPtr)         /* Dynamic string that is to become the result
2113                                 * of interp. */
2114{
2115    Interp *iPtr = (Interp *) interp;
2116
2117    if (dsPtr->string != dsPtr->staticSpace) {
2118        ckfree(dsPtr->string);
2119    }
2120
2121    /*
2122     * If the string result is empty, move the object result to the string
2123     * result, then reset the object result.
2124     */
2125
2126    (void) Tcl_GetStringResult(interp);
2127
2128    dsPtr->length = strlen(iPtr->result);
2129    if (iPtr->freeProc != NULL) {
2130        if (iPtr->freeProc == TCL_DYNAMIC) {
2131            dsPtr->string = iPtr->result;
2132            dsPtr->spaceAvl = dsPtr->length+1;
2133        } else {
2134            dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
2135            memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1);
2136            (*iPtr->freeProc)(iPtr->result);
2137        }
2138        dsPtr->spaceAvl = dsPtr->length+1;
2139        iPtr->freeProc = NULL;
2140    } else {
2141        if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
2142            dsPtr->string = dsPtr->staticSpace;
2143            dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
2144        } else {
2145            dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
2146            dsPtr->spaceAvl = dsPtr->length + 1;
2147        }
2148        memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1);
2149    }
2150
2151    iPtr->result = iPtr->resultSpace;
2152    iPtr->resultSpace[0] = 0;
2153}
2154
2155/*
2156 *----------------------------------------------------------------------
2157 *
2158 * Tcl_DStringStartSublist --
2159 *
2160 *      This function adds the necessary information to a dynamic string
2161 *      (e.g. " {") to start a sublist. Future element appends will be in the
2162 *      sublist rather than the main list.
2163 *
2164 * Results:
2165 *      None.
2166 *
2167 * Side effects:
2168 *      Characters get added to the dynamic string.
2169 *
2170 *----------------------------------------------------------------------
2171 */
2172
2173void
2174Tcl_DStringStartSublist(
2175    Tcl_DString *dsPtr)         /* Dynamic string. */
2176{
2177    if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
2178        Tcl_DStringAppend(dsPtr, " {", -1);
2179    } else {
2180        Tcl_DStringAppend(dsPtr, "{", -1);
2181    }
2182}
2183
2184/*
2185 *----------------------------------------------------------------------
2186 *
2187 * Tcl_DStringEndSublist --
2188 *
2189 *      This function adds the necessary characters to a dynamic string to end
2190 *      a sublist (e.g. "}"). Future element appends will be in the enclosing
2191 *      (sub)list rather than the current sublist.
2192 *
2193 * Results:
2194 *      None.
2195 *
2196 * Side effects:
2197 *      None.
2198 *
2199 *----------------------------------------------------------------------
2200 */
2201
2202void
2203Tcl_DStringEndSublist(
2204    Tcl_DString *dsPtr)         /* Dynamic string. */
2205{
2206    Tcl_DStringAppend(dsPtr, "}", -1);
2207}
2208
2209/*
2210 *----------------------------------------------------------------------
2211 *
2212 * Tcl_PrintDouble --
2213 *
2214 *      Given a floating-point value, this function converts it to an ASCII
2215 *      string using.
2216 *
2217 * Results:
2218 *      The ASCII equivalent of "value" is written at "dst". It is written
2219 *      using the current precision, and it is guaranteed to contain a decimal
2220 *      point or exponent, so that it looks like a floating-point value and
2221 *      not an integer.
2222 *
2223 * Side effects:
2224 *      None.
2225 *
2226 *----------------------------------------------------------------------
2227 */
2228
2229void
2230Tcl_PrintDouble(
2231    Tcl_Interp *interp,         /* Interpreter whose tcl_precision variable
2232                                 * used to be used to control printing. It's
2233                                 * ignored now. */
2234    double value,               /* Value to print as string. */
2235    char *dst)                  /* Where to store converted value; must have
2236                                 * at least TCL_DOUBLE_SPACE characters. */
2237{
2238    char *p, c;
2239    int exp;
2240    int signum;
2241    char buffer[TCL_DOUBLE_SPACE];
2242    Tcl_UniChar ch;
2243
2244    int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int)sizeof(int));
2245
2246    /*
2247     * If *precisionPtr == 0, then use TclDoubleDigits to develop a decimal
2248     * significand and exponent, then format it in E or F format as
2249     * appropriate. If *precisionPtr != 0, use the native sprintf and then add
2250     * a trailing ".0" if there is no decimal point in the rep.
2251     */
2252
2253    if (*precisionPtr == 0) {
2254        /*
2255         * Handle NaN.
2256         */
2257
2258        if (TclIsNaN(value)) {
2259            TclFormatNaN(value, dst);
2260            return;
2261        }
2262
2263        /*
2264         * Handle infinities.
2265         */
2266
2267        if (TclIsInfinite(value)) {
2268            if (value < 0) {
2269                strcpy(dst, "-Inf");
2270            } else {
2271                strcpy(dst, "Inf");
2272            }
2273            return;
2274        }
2275
2276        /*
2277         * Ordinary (normal and denormal) values.
2278         */
2279
2280        exp = TclDoubleDigits(buffer, value, &signum);
2281        if (signum) {
2282            *dst++ = '-';
2283        }
2284        p = buffer;
2285        if (exp < -3 || exp > 17) {
2286            /*
2287             * E format for numbers < 1e-3 or >= 1e17.
2288             */
2289
2290            *dst++ = *p++;
2291            c = *p;
2292            if (c != '\0') {
2293                *dst++ = '.';
2294                while (c != '\0') {
2295                    *dst++ = c;
2296                    c = *++p;
2297                }
2298            }
2299            sprintf(dst, "e%+d", exp-1);
2300        } else {
2301            /*
2302             * F format for others.
2303             */
2304
2305            if (exp <= 0) {
2306                *dst++ = '0';
2307            }
2308            c = *p;
2309            while (exp-- > 0) {
2310                if (c != '\0') {
2311                    *dst++ = c;
2312                    c = *++p;
2313                } else {
2314                    *dst++ = '0';
2315                }
2316            }
2317            *dst++ = '.';
2318            if (c == '\0') {
2319                *dst++ = '0';
2320            } else {
2321                while (++exp < 0) {
2322                    *dst++ = '0';
2323                }
2324                while (c != '\0') {
2325                    *dst++ = c;
2326                    c = *++p;
2327                }
2328            }
2329            *dst++ = '\0';
2330        }
2331    } else {
2332        /*
2333         * tcl_precision is supplied, pass it to the native sprintf.
2334         */
2335
2336        sprintf(dst, "%.*g", *precisionPtr, value);
2337
2338        /*
2339         * If the ASCII result looks like an integer, add ".0" so that it
2340         * doesn't look like an integer anymore. This prevents floating-point
2341         * values from being converted to integers unintentionally. Check for
2342         * ASCII specifically to speed up the function.
2343         */
2344
2345        for (p = dst; *p != 0;) {
2346            if (UCHAR(*p) < 0x80) {
2347                c = *p++;
2348            } else {
2349                p += Tcl_UtfToUniChar(p, &ch);
2350                c = UCHAR(ch);
2351            }
2352            if ((c == '.') || isalpha(UCHAR(c))) {      /* INTL: ISO only. */
2353                return;
2354            }
2355        }
2356        p[0] = '.';
2357        p[1] = '0';
2358        p[2] = 0;
2359    }
2360}
2361
2362/*
2363 *----------------------------------------------------------------------
2364 *
2365 * TclPrecTraceProc --
2366 *
2367 *      This function is invoked whenever the variable "tcl_precision" is
2368 *      written.
2369 *
2370 * Results:
2371 *      Returns NULL if all went well, or an error message if the new value
2372 *      for the variable doesn't make sense.
2373 *
2374 * Side effects:
2375 *      If the new value doesn't make sense then this function undoes the
2376 *      effect of the variable modification. Otherwise it modifies the format
2377 *      string that's used by Tcl_PrintDouble.
2378 *
2379 *----------------------------------------------------------------------
2380 */
2381
2382        /* ARGSUSED */
2383char *
2384TclPrecTraceProc(
2385    ClientData clientData,      /* Not used. */
2386    Tcl_Interp *interp,         /* Interpreter containing variable. */
2387    CONST char *name1,          /* Name of variable. */
2388    CONST char *name2,          /* Second part of variable name. */
2389    int flags)                  /* Information about what happened. */
2390{
2391    Tcl_Obj* value;
2392    int prec;
2393    int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int));
2394
2395    /*
2396     * If the variable is unset, then recreate the trace.
2397     */
2398
2399    if (flags & TCL_TRACE_UNSETS) {
2400        if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) {
2401            Tcl_TraceVar2(interp, name1, name2,
2402                    TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
2403                    |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData);
2404        }
2405        return NULL;
2406    }
2407
2408    /*
2409     * When the variable is read, reset its value from our shared value. This
2410     * is needed in case the variable was modified in some other interpreter
2411     * so that this interpreter's value is out of date.
2412     */
2413
2414
2415    if (flags & TCL_TRACE_READS) {
2416        Tcl_SetVar2Ex(interp, name1, name2, Tcl_NewIntObj(*precisionPtr),
2417                flags & TCL_GLOBAL_ONLY);
2418        return NULL;
2419    }
2420
2421    /*
2422     * The variable is being written. Check the new value and disallow it if
2423     * it isn't reasonable or if this is a safe interpreter (we don't want
2424     * safe interpreters messing up the precision of other interpreters).
2425     */
2426
2427    if (Tcl_IsSafe(interp)) {
2428        return "can't modify precision from a safe interpreter";
2429    }
2430    value = Tcl_GetVar2Ex(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
2431    if (value == NULL
2432            || Tcl_GetIntFromObj((Tcl_Interp*) NULL, value, &prec) != TCL_OK
2433            || prec < 0 || prec > TCL_MAX_PREC) {
2434        return "improper value for precision";
2435    }
2436    *precisionPtr = prec;
2437    return NULL;
2438}
2439
2440/*
2441 *----------------------------------------------------------------------
2442 *
2443 * TclNeedSpace --
2444 *
2445 *      This function checks to see whether it is appropriate to add a space
2446 *      before appending a new list element to an existing string.
2447 *
2448 * Results:
2449 *      The return value is 1 if a space is appropriate, 0 otherwise.
2450 *
2451 * Side effects:
2452 *      None.
2453 *
2454 *----------------------------------------------------------------------
2455 */
2456
2457int
2458TclNeedSpace(
2459    CONST char *start,          /* First character in string. */
2460    CONST char *end)            /* End of string (place where space will be
2461                                 * added, if appropriate). */
2462{
2463    /*
2464     * A space is needed unless either:
2465     * (a) we're at the start of the string, or
2466     */
2467
2468    if (end == start) {
2469        return 0;
2470    }
2471
2472    /*
2473     * (b) we're at the start of a nested list-element, quoted with an open
2474     *     curly brace; we can be nested arbitrarily deep, so long as the
2475     *     first curly brace starts an element, so backtrack over open curly
2476     *     braces that are trailing characters of the string; and
2477     */
2478
2479    end = Tcl_UtfPrev(end, start);
2480    while (*end == '{') {
2481        if (end == start) {
2482            return 0;
2483        }
2484        end = Tcl_UtfPrev(end, start);
2485    }
2486
2487    /*
2488     * (c) the trailing character of the string is already a list-element
2489     *     separator (according to TclFindElement); that is, one of these
2490     *     characters:
2491     *          \u0009  \t      TAB
2492     *          \u000A  \n      NEWLINE
2493     *          \u000B  \v      VERTICAL TAB
2494     *          \u000C  \f      FORM FEED
2495     *          \u000D  \r      CARRIAGE RETURN
2496     *          \u0020          SPACE
2497     *     with the condition that the penultimate character is not a
2498     *     backslash.
2499     */
2500
2501    if (*end > 0x20) {
2502        /*
2503         * Performance tweak. All ASCII spaces are <= 0x20. So get a quick
2504         * answer for most characters before comparing against all spaces in
2505         * the switch below.
2506         *
2507         * NOTE: Remove this if other Unicode spaces ever get accepted as
2508         * list-element separators.
2509         */
2510        return 1;
2511    }
2512    switch (*end) {
2513    case ' ':
2514    case '\t':
2515    case '\n':
2516    case '\r':
2517    case '\v':
2518    case '\f':
2519        if ((end == start) || (end[-1] != '\\')) {
2520            return 0;
2521        }
2522    }
2523    return 1;
2524}
2525
2526/*
2527 *----------------------------------------------------------------------
2528 *
2529 * TclGetIntForIndex --
2530 *
2531 *      This function returns an integer corresponding to the list index held
2532 *      in a Tcl object. The Tcl object's value is expected to be in the
2533 *      format integer([+-]integer)? or the format end([+-]integer)?.
2534 *
2535 * Results:
2536 *      The return value is normally TCL_OK, which means that the index was
2537 *      successfully stored into the location referenced by "indexPtr". If the
2538 *      Tcl object referenced by "objPtr" has the value "end", the value
2539 *      stored is "endValue". If "objPtr"s values is not of one of the
2540 *      expected formats, TCL_ERROR is returned and, if "interp" is non-NULL,
2541 *      an error message is left in the interpreter's result object.
2542 *
2543 * Side effects:
2544 *      The object referenced by "objPtr" might be converted to an integer,
2545 *      wide integer, or end-based-index object.
2546 *
2547 *----------------------------------------------------------------------
2548 */
2549
2550int
2551TclGetIntForIndex(
2552    Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
2553                                 * NULL, then no error message is left after
2554                                 * errors. */
2555    Tcl_Obj *objPtr,            /* Points to an object containing either "end"
2556                                 * or an integer. */
2557    int endValue,               /* The value to be stored at "indexPtr" if
2558                                 * "objPtr" holds "end". */
2559    int *indexPtr)              /* Location filled in with an integer
2560                                 * representing an index. */
2561{
2562    int length;
2563    char *opPtr, *bytes;
2564
2565    if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
2566        return TCL_OK;
2567    }
2568
2569    if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
2570        /*
2571         * If the object is already an offset from the end of the list, or can
2572         * be converted to one, use it.
2573         */
2574
2575        *indexPtr = endValue + objPtr->internalRep.longValue;
2576        return TCL_OK;
2577    }
2578
2579    bytes = TclGetStringFromObj(objPtr, &length);
2580
2581    /*
2582     * Leading whitespace is acceptable in an index.
2583     */
2584
2585    while (length && isspace(UCHAR(*bytes))) {          /* INTL: ISO space. */
2586        bytes++;
2587        length--;
2588    }
2589
2590    if (TclParseNumber(NULL, NULL, NULL, bytes, length, (const char **)&opPtr,
2591            TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
2592        int code, first, second;
2593        char savedOp = *opPtr;
2594
2595        if ((savedOp != '+') && (savedOp != '-')) {
2596            goto parseError;
2597        }
2598        if (isspace(UCHAR(opPtr[1]))) {
2599            goto parseError;
2600        }
2601        *opPtr = '\0';
2602        code = Tcl_GetInt(interp, bytes, &first);
2603        *opPtr = savedOp;
2604        if (code == TCL_ERROR) {
2605            goto parseError;
2606        }
2607        if (TCL_ERROR == Tcl_GetInt(interp, opPtr+1, &second)) {
2608            goto parseError;
2609        }
2610        if (savedOp == '+') {
2611            *indexPtr = first + second;
2612        } else {
2613            *indexPtr = first - second;
2614        }
2615        return TCL_OK;
2616    }
2617
2618    /*
2619     * Report a parse error.
2620     */
2621
2622  parseError:
2623    if (interp != NULL) {
2624        char *bytes = Tcl_GetString(objPtr);
2625
2626        /*
2627         * The result might not be empty; this resets it which should be both
2628         * a cheap operation, and of little problem because this is an
2629         * error-generation path anyway.
2630         */
2631
2632        Tcl_ResetResult(interp);
2633        Tcl_AppendResult(interp, "bad index \"", bytes,
2634                "\": must be integer?[+-]integer? or end?[+-]integer?", NULL);
2635        if (!strncmp(bytes, "end-", 4)) {
2636            bytes += 4;
2637        }
2638        TclCheckBadOctal(interp, bytes);
2639    }
2640
2641    return TCL_ERROR;
2642}
2643
2644/*
2645 *----------------------------------------------------------------------
2646 *
2647 * UpdateStringOfEndOffset --
2648 *
2649 *      Update the string rep of a Tcl object holding an "end-offset"
2650 *      expression.
2651 *
2652 * Results:
2653 *      None.
2654 *
2655 * Side effects:
2656 *      Stores a valid string in the object's string rep.
2657 *
2658 * This function does NOT free any earlier string rep. If it is called on an
2659 * object that already has a valid string rep, it will leak memory.
2660 *
2661 *----------------------------------------------------------------------
2662 */
2663
2664static void
2665UpdateStringOfEndOffset(
2666    register Tcl_Obj* objPtr)
2667{
2668    char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1];
2669    register int len;
2670
2671    strcpy(buffer, "end");
2672    len = sizeof("end") - 1;
2673    if (objPtr->internalRep.longValue != 0) {
2674        buffer[len++] = '-';
2675        len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
2676    }
2677    objPtr->bytes = ckalloc((unsigned) len+1);
2678    memcpy(objPtr->bytes, buffer, (unsigned) len+1);
2679    objPtr->length = len;
2680}
2681
2682/*
2683 *----------------------------------------------------------------------
2684 *
2685 * SetEndOffsetFromAny --
2686 *
2687 *      Look for a string of the form "end[+-]offset" and convert it to an
2688 *      internal representation holding the offset.
2689 *
2690 * Results:
2691 *      Returns TCL_OK if ok, TCL_ERROR if the string was badly formed.
2692 *
2693 * Side effects:
2694 *      If interp is not NULL, stores an error message in the interpreter
2695 *      result.
2696 *
2697 *----------------------------------------------------------------------
2698 */
2699
2700static int
2701SetEndOffsetFromAny(
2702    Tcl_Interp *interp,         /* Tcl interpreter or NULL */
2703    Tcl_Obj *objPtr)            /* Pointer to the object to parse */
2704{
2705    int offset;                 /* Offset in the "end-offset" expression */
2706    register char* bytes;       /* String rep of the object */
2707    int length;                 /* Length of the object's string rep */
2708
2709    /*
2710     * If it's already the right type, we're fine.
2711     */
2712
2713    if (objPtr->typePtr == &tclEndOffsetType) {
2714        return TCL_OK;
2715    }
2716
2717    /*
2718     * Check for a string rep of the right form.
2719     */
2720
2721    bytes = TclGetStringFromObj(objPtr, &length);
2722    if ((*bytes != 'e') || (strncmp(bytes, "end",
2723            (size_t)((length > 3) ? 3 : length)) != 0)) {
2724        if (interp != NULL) {
2725            Tcl_ResetResult(interp);
2726            Tcl_AppendResult(interp, "bad index \"", bytes,
2727                    "\": must be end?[+-]integer?", NULL);
2728        }
2729        return TCL_ERROR;
2730    }
2731
2732    /*
2733     * Convert the string rep.
2734     */
2735
2736    if (length <= 3) {
2737        offset = 0;
2738    } else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) {
2739        /*
2740         * This is our limited string expression evaluator. Pass everything
2741         * after "end-" to Tcl_GetInt, then reverse for offset.
2742         */
2743
2744        if (isspace(UCHAR(bytes[4]))) {
2745            return TCL_ERROR;
2746        }
2747        if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
2748            return TCL_ERROR;
2749        }
2750        if (bytes[3] == '-') {
2751            offset = -offset;
2752        }
2753    } else {
2754        /*
2755         * Conversion failed. Report the error.
2756         */
2757
2758        if (interp != NULL) {
2759            Tcl_ResetResult(interp);
2760            Tcl_AppendResult(interp, "bad index \"", bytes,
2761                    "\": must be end?[+-]integer?", NULL);
2762        }
2763        return TCL_ERROR;
2764    }
2765
2766    /*
2767     * The conversion succeeded. Free the old internal rep and set the new
2768     * one.
2769     */
2770
2771    TclFreeIntRep(objPtr);
2772    objPtr->internalRep.longValue = offset;
2773    objPtr->typePtr = &tclEndOffsetType;
2774
2775    return TCL_OK;
2776}
2777
2778/*
2779 *----------------------------------------------------------------------
2780 *
2781 * TclCheckBadOctal --
2782 *
2783 *      This function checks for a bad octal value and appends a meaningful
2784 *      error to the interp's result.
2785 *
2786 * Results:
2787 *      1 if the argument was a bad octal, else 0.
2788 *
2789 * Side effects:
2790 *      The interpreter's result is modified.
2791 *
2792 *----------------------------------------------------------------------
2793 */
2794
2795int
2796TclCheckBadOctal(
2797    Tcl_Interp *interp,         /* Interpreter to use for error reporting. If
2798                                 * NULL, then no error message is left after
2799                                 * errors. */
2800    CONST char *value)          /* String to check. */
2801{
2802    register CONST char *p = value;
2803
2804    /*
2805     * A frequent mistake is invalid octal values due to an unwanted leading
2806     * zero. Try to generate a meaningful error message.
2807     */
2808
2809    while (isspace(UCHAR(*p))) {        /* INTL: ISO space. */
2810        p++;
2811    }
2812    if (*p == '+' || *p == '-') {
2813        p++;
2814    }
2815    if (*p == '0') {
2816        if ((p[1] == 'o') || p[1] == 'O') {
2817            p+=2;
2818        }
2819        while (isdigit(UCHAR(*p))) {    /* INTL: digit. */
2820            p++;
2821        }
2822        while (isspace(UCHAR(*p))) {    /* INTL: ISO space. */
2823            p++;
2824        }
2825        if (*p == '\0') {
2826            /*
2827             * Reached end of string.
2828             */
2829
2830            if (interp != NULL) {
2831                /*
2832                 * Don't reset the result here because we want this result to
2833                 * be added to an existing error message as extra info.
2834                 */
2835
2836                Tcl_AppendResult(interp, " (looks like invalid octal number)",
2837                        NULL);
2838            }
2839            return 1;
2840        }
2841    }
2842    return 0;
2843}
2844
2845/*
2846 *----------------------------------------------------------------------
2847 *
2848 * ClearHash --
2849 *
2850 *      Remove all the entries in the hash table *tablePtr.
2851 *
2852 *----------------------------------------------------------------------
2853 */
2854
2855static void
2856ClearHash(
2857    Tcl_HashTable *tablePtr)
2858{
2859    Tcl_HashSearch search;
2860    Tcl_HashEntry *hPtr;
2861
2862    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
2863            hPtr = Tcl_NextHashEntry(&search)) {
2864        Tcl_Obj *objPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
2865        Tcl_DecrRefCount(objPtr);
2866        Tcl_DeleteHashEntry(hPtr);
2867    }
2868}
2869
2870/*
2871 *----------------------------------------------------------------------
2872 *
2873 * GetThreadHash --
2874 *
2875 *      Get a thread-specific (Tcl_HashTable *) associated with a thread data
2876 *      key.
2877 *
2878 * Results:
2879 *      The Tcl_HashTable * corresponding to *keyPtr.
2880 *
2881 * Side effects:
2882 *      The first call on a keyPtr in each thread creates a new Tcl_HashTable,
2883 *      and registers a thread exit handler to dispose of it.
2884 *
2885 *----------------------------------------------------------------------
2886 */
2887
2888static Tcl_HashTable *
2889GetThreadHash(
2890    Tcl_ThreadDataKey *keyPtr)
2891{
2892    Tcl_HashTable **tablePtrPtr = (Tcl_HashTable **)
2893            Tcl_GetThreadData(keyPtr, (int) sizeof(Tcl_HashTable *));
2894
2895    if (NULL == *tablePtrPtr) {
2896        *tablePtrPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
2897        Tcl_CreateThreadExitHandler(FreeThreadHash, (ClientData)*tablePtrPtr);
2898        Tcl_InitHashTable(*tablePtrPtr, TCL_ONE_WORD_KEYS);
2899    }
2900    return *tablePtrPtr;
2901}
2902
2903/*
2904 *----------------------------------------------------------------------
2905 *
2906 * FreeThreadHash --
2907 *
2908 *      Thread exit handler used by GetThreadHash to dispose of a thread hash
2909 *      table.
2910 *
2911 * Side effects:
2912 *      Frees a Tcl_HashTable.
2913 *
2914 *----------------------------------------------------------------------
2915 */
2916
2917static void
2918FreeThreadHash(
2919    ClientData clientData)
2920{
2921    Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData;
2922
2923    ClearHash(tablePtr);
2924    Tcl_DeleteHashTable(tablePtr);
2925    ckfree((char *) tablePtr);
2926}
2927
2928/*
2929 *----------------------------------------------------------------------
2930 *
2931 * FreeProcessGlobalValue --
2932 *
2933 *      Exit handler used by Tcl(Set|Get)ProcessGlobalValue to cleanup a
2934 *      ProcessGlobalValue at exit.
2935 *
2936 *----------------------------------------------------------------------
2937 */
2938
2939static void
2940FreeProcessGlobalValue(
2941    ClientData clientData)
2942{
2943    ProcessGlobalValue *pgvPtr = (ProcessGlobalValue *) clientData;
2944
2945    pgvPtr->epoch++;
2946    pgvPtr->numBytes = 0;
2947    ckfree(pgvPtr->value);
2948    pgvPtr->value = NULL;
2949    if (pgvPtr->encoding) {
2950        Tcl_FreeEncoding(pgvPtr->encoding);
2951        pgvPtr->encoding = NULL;
2952    }
2953    Tcl_MutexFinalize(&pgvPtr->mutex);
2954}
2955
2956/*
2957 *----------------------------------------------------------------------
2958 *
2959 * TclSetProcessGlobalValue --
2960 *
2961 *      Utility routine to set a global value shared by all threads in the
2962 *      process while keeping a thread-local copy as well.
2963 *
2964 *----------------------------------------------------------------------
2965 */
2966
2967void
2968TclSetProcessGlobalValue(
2969    ProcessGlobalValue *pgvPtr,
2970    Tcl_Obj *newValue,
2971    Tcl_Encoding encoding)
2972{
2973    CONST char *bytes;
2974    Tcl_HashTable *cacheMap;
2975    Tcl_HashEntry *hPtr;
2976    int dummy;
2977
2978    Tcl_MutexLock(&pgvPtr->mutex);
2979
2980    /*
2981     * Fill the global string value.
2982     */
2983
2984    pgvPtr->epoch++;
2985    if (NULL != pgvPtr->value) {
2986        ckfree(pgvPtr->value);
2987    } else {
2988        Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData) pgvPtr);
2989    }
2990    bytes = Tcl_GetStringFromObj(newValue, &pgvPtr->numBytes);
2991    pgvPtr->value = ckalloc((unsigned) pgvPtr->numBytes + 1);
2992    memcpy(pgvPtr->value, bytes, (unsigned) pgvPtr->numBytes + 1);
2993    if (pgvPtr->encoding) {
2994        Tcl_FreeEncoding(pgvPtr->encoding);
2995    }
2996    pgvPtr->encoding = encoding;
2997
2998    /*
2999     * Fill the local thread copy directly with the Tcl_Obj value to avoid
3000     * loss of the intrep. Increment newValue refCount early to handle case
3001     * where we set a PGV to itself.
3002     */
3003
3004    Tcl_IncrRefCount(newValue);
3005    cacheMap = GetThreadHash(&pgvPtr->key);
3006    ClearHash(cacheMap);
3007    hPtr = Tcl_CreateHashEntry(cacheMap,
3008            (char *) INT2PTR(pgvPtr->epoch), &dummy);
3009    Tcl_SetHashValue(hPtr, (ClientData) newValue);
3010    Tcl_MutexUnlock(&pgvPtr->mutex);
3011}
3012
3013/*
3014 *----------------------------------------------------------------------
3015 *
3016 * TclGetProcessGlobalValue --
3017 *
3018 *      Retrieve a global value shared among all threads of the process,
3019 *      preferring a thread-local copy as long as it remains valid.
3020 *
3021 * Results:
3022 *      Returns a (Tcl_Obj *) that holds a copy of the global value.
3023 *
3024 *----------------------------------------------------------------------
3025 */
3026
3027Tcl_Obj *
3028TclGetProcessGlobalValue(
3029    ProcessGlobalValue *pgvPtr)
3030{
3031    Tcl_Obj *value = NULL;
3032    Tcl_HashTable *cacheMap;
3033    Tcl_HashEntry *hPtr;
3034    int epoch = pgvPtr->epoch;
3035
3036    if (pgvPtr->encoding) {
3037        Tcl_Encoding current = Tcl_GetEncoding(NULL, NULL);
3038
3039        if (pgvPtr->encoding != current) {
3040            /*
3041             * The system encoding has changed since the master string value
3042             * was saved. Convert the master value to be based on the new
3043             * system encoding.
3044             */
3045
3046            Tcl_DString native, newValue;
3047
3048            Tcl_MutexLock(&pgvPtr->mutex);
3049            pgvPtr->epoch++;
3050            epoch = pgvPtr->epoch;
3051            Tcl_UtfToExternalDString(pgvPtr->encoding, pgvPtr->value,
3052                    pgvPtr->numBytes, &native);
3053            Tcl_ExternalToUtfDString(current, Tcl_DStringValue(&native),
3054            Tcl_DStringLength(&native), &newValue);
3055            Tcl_DStringFree(&native);
3056            ckfree(pgvPtr->value);
3057            pgvPtr->value = ckalloc((unsigned int)
3058                    Tcl_DStringLength(&newValue) + 1);
3059            memcpy(pgvPtr->value, Tcl_DStringValue(&newValue),
3060                    (size_t) Tcl_DStringLength(&newValue) + 1);
3061            Tcl_DStringFree(&newValue);
3062            Tcl_FreeEncoding(pgvPtr->encoding);
3063            pgvPtr->encoding = current;
3064            Tcl_MutexUnlock(&pgvPtr->mutex);
3065        } else {
3066            Tcl_FreeEncoding(current);
3067        }
3068    }
3069    cacheMap = GetThreadHash(&pgvPtr->key);
3070    hPtr = Tcl_FindHashEntry(cacheMap, (char *) INT2PTR(epoch));
3071    if (NULL == hPtr) {
3072        int dummy;
3073
3074        /*
3075         * No cache for the current epoch - must be a new one.
3076         *
3077         * First, clear the cacheMap, as anything in it must refer to some
3078         * expired epoch.
3079         */
3080
3081        ClearHash(cacheMap);
3082
3083        /*
3084         * If no thread has set the shared value, call the initializer.
3085         */
3086
3087        Tcl_MutexLock(&pgvPtr->mutex);
3088        if ((NULL == pgvPtr->value) && (pgvPtr->proc)) {
3089            pgvPtr->epoch++;
3090            (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes,
3091                    &pgvPtr->encoding);
3092            if (pgvPtr->value == NULL) {
3093                Tcl_Panic("PGV Initializer did not initialize");
3094            }
3095            Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData)pgvPtr);
3096        }
3097
3098        /*
3099         * Store a copy of the shared value in our epoch-indexed cache.
3100         */
3101
3102        value = Tcl_NewStringObj(pgvPtr->value, pgvPtr->numBytes);
3103        hPtr = Tcl_CreateHashEntry(cacheMap,
3104                (char *) INT2PTR(pgvPtr->epoch), &dummy);
3105        Tcl_MutexUnlock(&pgvPtr->mutex);
3106        Tcl_SetHashValue(hPtr, (ClientData) value);
3107        Tcl_IncrRefCount(value);
3108    }
3109    return (Tcl_Obj *) Tcl_GetHashValue(hPtr);
3110}
3111
3112/*
3113 *----------------------------------------------------------------------
3114 *
3115 * TclSetObjNameOfExecutable --
3116 *
3117 *      This function stores the absolute pathname of the executable file
3118 *      (normally as computed by TclpFindExecutable).
3119 *
3120 * Results:
3121 *      None.
3122 *
3123 * Side effects:
3124 *      Stores the executable name.
3125 *
3126 *----------------------------------------------------------------------
3127 */
3128
3129void
3130TclSetObjNameOfExecutable(
3131    Tcl_Obj *name,
3132    Tcl_Encoding encoding)
3133{
3134    TclSetProcessGlobalValue(&executableName, name, encoding);
3135}
3136
3137/*
3138 *----------------------------------------------------------------------
3139 *
3140 * TclGetObjNameOfExecutable --
3141 *
3142 *      This function retrieves the absolute pathname of the application in
3143 *      which the Tcl library is running, usually as previously stored by
3144 *      TclpFindExecutable(). This function call is the C API equivalent to
3145 *      the "info nameofexecutable" command.
3146 *
3147 * Results:
3148 *      A pointer to an "fsPath" Tcl_Obj, or to an empty Tcl_Obj if the
3149 *      pathname of the application is unknown.
3150 *
3151 * Side effects:
3152 *      None.
3153 *
3154 *----------------------------------------------------------------------
3155 */
3156
3157Tcl_Obj *
3158TclGetObjNameOfExecutable(void)
3159{
3160    return TclGetProcessGlobalValue(&executableName);
3161}
3162
3163/*
3164 *----------------------------------------------------------------------
3165 *
3166 * Tcl_GetNameOfExecutable --
3167 *
3168 *      This function retrieves the absolute pathname of the application in
3169 *      which the Tcl library is running, and returns it in string form.
3170 *
3171 *      The returned string belongs to Tcl and should be copied if the caller
3172 *      plans to keep it, to guard against it becoming invalid.
3173 *
3174 * Results:
3175 *      A pointer to the internal string or NULL if the internal full path
3176 *      name has not been computed or unknown.
3177 *
3178 * Side effects:
3179 *      None.
3180 *
3181 *----------------------------------------------------------------------
3182 */
3183
3184CONST char *
3185Tcl_GetNameOfExecutable(void)
3186{
3187    int numBytes;
3188    const char *bytes =
3189            Tcl_GetStringFromObj(TclGetObjNameOfExecutable(), &numBytes);
3190
3191    if (numBytes == 0) {
3192        return NULL;
3193    }
3194    return bytes;
3195}
3196
3197/*
3198 *----------------------------------------------------------------------
3199 *
3200 * TclpGetTime --
3201 *
3202 *      Deprecated synonym for Tcl_GetTime. This function is provided for the
3203 *      benefit of extensions written before Tcl_GetTime was exported from the
3204 *      library.
3205 *
3206 * Results:
3207 *      None.
3208 *
3209 * Side effects:
3210 *      Stores current time in the buffer designated by "timePtr"
3211 *
3212 *----------------------------------------------------------------------
3213 */
3214
3215void
3216TclpGetTime(
3217    Tcl_Time *timePtr)
3218{
3219    Tcl_GetTime(timePtr);
3220}
3221
3222/*
3223 *----------------------------------------------------------------------
3224 *
3225 * TclGetPlatform --
3226 *
3227 *      This is a kludge that allows the test library to get access the
3228 *      internal tclPlatform variable.
3229 *
3230 * Results:
3231 *      Returns a pointer to the tclPlatform variable.
3232 *
3233 * Side effects:
3234 *      None.
3235 *
3236 *----------------------------------------------------------------------
3237 */
3238
3239TclPlatformType *
3240TclGetPlatform(void)
3241{
3242    return &tclPlatform;
3243}
3244
3245/*
3246 *----------------------------------------------------------------------
3247 *
3248 * TclReToGlob --
3249 *
3250 *      Attempt to convert a regular expression to an equivalent glob pattern.
3251 *
3252 * Results:
3253 *      Returns TCL_OK on success, TCL_ERROR on failure. If interp is not
3254 *      NULL, an error message is placed in the result. On success, the
3255 *      DString will contain an exact equivalent glob pattern. The caller is
3256 *      responsible for calling Tcl_DStringFree on success. If exactPtr is not
3257 *      NULL, it will be 1 if an exact match qualifies.
3258 *
3259 * Side effects:
3260 *      None.
3261 *
3262 *----------------------------------------------------------------------
3263 */
3264
3265int
3266TclReToGlob(
3267    Tcl_Interp *interp,
3268    const char *reStr,
3269    int reStrLen,
3270    Tcl_DString *dsPtr,
3271    int *exactPtr)
3272{
3273    int anchorLeft, anchorRight, lastIsStar;
3274    char *dsStr, *dsStrStart, *msg;
3275    const char *p, *strEnd;
3276
3277    strEnd = reStr + reStrLen;
3278    Tcl_DStringInit(dsPtr);
3279
3280    /*
3281     * "***=xxx" == "*xxx*"
3282     */
3283
3284    if ((reStrLen >= 4) && (memcmp("***=", reStr, 4) == 0)) {
3285        if (exactPtr) {
3286            *exactPtr = 1;
3287        }
3288        Tcl_DStringAppend(dsPtr, reStr + 4, reStrLen - 4);
3289        return TCL_OK;
3290    }
3291
3292    /*
3293     * Write to the ds directly without the function overhead.
3294     * An equivalent glob pattern can be no more than reStrLen+2 in size.
3295     */
3296
3297    Tcl_DStringSetLength(dsPtr, reStrLen + 2);
3298    dsStrStart = Tcl_DStringValue(dsPtr);
3299
3300    /*
3301     * Check for anchored REs (ie ^foo$), so we can use string equal if
3302     * possible. Do not alter the start of str so we can free it correctly.
3303     *
3304     * Keep track of the last char being an unescaped star to prevent
3305     * multiple instances.  Simpler than checking that the last star
3306     * may be escaped.
3307     */
3308
3309    msg = NULL;
3310    p = reStr;
3311    anchorRight = 0;
3312    lastIsStar = 0;
3313    dsStr = dsStrStart;
3314    if (*p == '^') {
3315        anchorLeft = 1;
3316        p++;
3317    } else {
3318        anchorLeft = 0;
3319        *dsStr++ = '*';
3320        lastIsStar = 1;
3321    }
3322
3323    for ( ; p < strEnd; p++) {
3324        switch (*p) {
3325        case '\\':
3326            p++;
3327            switch (*p) {
3328            case 'a':
3329                *dsStr++ = '\a';
3330                break;
3331            case 'b':
3332                *dsStr++ = '\b';
3333                break;
3334            case 'f':
3335                *dsStr++ = '\f';
3336                break;
3337            case 'n':
3338                *dsStr++ = '\n';
3339                break;
3340            case 'r':
3341                *dsStr++ = '\r';
3342                break;
3343            case 't':
3344                *dsStr++ = '\t';
3345                break;
3346            case 'v':
3347                *dsStr++ = '\v';
3348                break;
3349            case 'B': case '\\':
3350                *dsStr++ = '\\';
3351                *dsStr++ = '\\';
3352                anchorLeft = 0; /* prevent exact match */
3353                break;
3354            case '*': case '[': case ']': case '?':
3355                /* Only add \ where necessary for glob */
3356                *dsStr++ = '\\';
3357                anchorLeft = 0; /* prevent exact match */
3358                /* fall through */
3359            case '{': case '}': case '(': case ')': case '+':
3360            case '.': case '|': case '^': case '$':
3361                *dsStr++ = *p;
3362                break;
3363            default:
3364                msg = "invalid escape sequence";
3365                goto invalidGlob;
3366            }
3367            break;
3368        case '.':
3369            anchorLeft = 0; /* prevent exact match */
3370            if (p+1 < strEnd) {
3371                if (p[1] == '*') {
3372                    p++;
3373                    if (!lastIsStar) {
3374                        *dsStr++ = '*';
3375                        lastIsStar = 1;
3376                    }
3377                    continue;
3378                } else if (p[1] == '+') {
3379                    p++;
3380                    *dsStr++ = '?';
3381                    *dsStr++ = '*';
3382                    lastIsStar = 1;
3383                    continue;
3384                }
3385            }
3386            *dsStr++ = '?';
3387            break;
3388        case '$':
3389            if (p+1 != strEnd) {
3390                msg = "$ not anchor";
3391                goto invalidGlob;
3392            }
3393            anchorRight = 1;
3394            break;
3395        case '*': case '+': case '?': case '|': case '^':
3396        case '{': case '}': case '(': case ')': case '[': case ']':
3397            msg = "unhandled RE special char";
3398            goto invalidGlob;
3399            break;
3400        default:
3401            *dsStr++ = *p;
3402            break;
3403        }
3404        lastIsStar = 0;
3405    }
3406    if (!anchorRight && !lastIsStar) {
3407        *dsStr++ = '*';
3408    }
3409    Tcl_DStringSetLength(dsPtr, dsStr - dsStrStart);
3410
3411    if (exactPtr) {
3412        *exactPtr = (anchorLeft && anchorRight);
3413    }
3414
3415#if 0
3416    fprintf(stderr, "INPUT RE '%.*s' OUTPUT GLOB '%s' anchor %d:%d \n",
3417            reStrLen, reStr,
3418            Tcl_DStringValue(dsPtr), anchorLeft, anchorRight);
3419    fflush(stderr);
3420#endif
3421    return TCL_OK;
3422
3423  invalidGlob:
3424#if 0
3425    fprintf(stderr, "INPUT RE '%.*s' NO OUTPUT GLOB %s (%c)\n",
3426            reStrLen, reStr, msg, *p);
3427    fflush(stderr);
3428#endif
3429    if (interp != NULL) {
3430        Tcl_AppendResult(interp, msg, NULL);
3431    }
3432    Tcl_DStringFree(dsPtr);
3433    return TCL_ERROR;
3434}
3435
3436/*
3437 * Local Variables:
3438 * mode: c
3439 * c-basic-offset: 4
3440 * fill-column: 78
3441 * End:
3442 */
Note: See TracBrowser for help on using the repository browser.