Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added tcl to libs

File size: 54.1 KB
Line 
1/*
2 * tclListObj.c --
3 *
4 *      This file contains functions that implement the Tcl list object type.
5 *
6 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
7 * Copyright (c) 1998 by Scriptics Corporation.
8 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
9 *
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
13 * RCS: @(#) $Id: tclListObj.c,v 1.49 2007/12/13 15:23:18 dgp Exp $
14 */
15
16#include "tclInt.h"
17
18/*
19 * Prototypes for functions defined later in this file:
20 */
21
22static List *           NewListIntRep(int objc, Tcl_Obj *CONST objv[]);
23static void             DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
24static void             FreeListInternalRep(Tcl_Obj *listPtr);
25static int              SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
26static void             UpdateStringOfList(Tcl_Obj *listPtr);
27
28/*
29 * The structure below defines the list Tcl object type by means of functions
30 * that can be invoked by generic object code.
31 *
32 * The internal representation of a list object is a two-pointer
33 * representation. The first pointer designates a List structure that contains
34 * an array of pointers to the element objects, together with integers that
35 * represent the current element count and the allocated size of the array.
36 * The second pointer is normally NULL; during execution of functions in this
37 * file that operate on nested sublists, it is occasionally used as working
38 * storage to avoid an auxiliary stack.
39 */
40
41Tcl_ObjType tclListType = {
42    "list",                     /* name */
43    FreeListInternalRep,        /* freeIntRepProc */
44    DupListInternalRep,         /* dupIntRepProc */
45    UpdateStringOfList,         /* updateStringProc */
46    SetListFromAny              /* setFromAnyProc */
47};
48
49/*
50 *----------------------------------------------------------------------
51 *
52 * NewListIntRep --
53 *
54 *      If objc>0 and objv!=NULL, this function creates a list internal rep
55 *      with objc elements given in the array objv. If objc>0 and objv==NULL
56 *      it creates the list internal rep of a list with 0 elements, where
57 *      enough space has been preallocated to store objc elements. If objc<=0,
58 *      it returns NULL.
59 *
60 * Results:
61 *      A new List struct is returned. If objc<=0 or if the allocation fails
62 *      for lack of memory, NULL is returned. The list returned has refCount
63 *      0.
64 *
65 * Side effects:
66 *      The ref counts of the elements in objv are incremented since the
67 *      resulting list now refers to them.
68 *
69 *----------------------------------------------------------------------
70 */
71
72static List *
73NewListIntRep(
74    int objc,
75    Tcl_Obj *CONST objv[])
76{
77    List *listRepPtr;
78
79    if (objc <= 0) {
80        return NULL;
81    }
82
83    /*
84     * First check to see if we'd overflow and try to allocate an object
85     * larger than our memory allocator allows. Note that this is actually a
86     * fairly small value when you're on a serious 64-bit machine, but that
87     * requires API changes to fix. See [Bug 219196] for a discussion.
88     */
89
90    if ((size_t)objc > INT_MAX/sizeof(Tcl_Obj *)) {
91        return NULL;
92    }
93
94    listRepPtr = (List *)
95            attemptckalloc(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *)));
96    if (listRepPtr == NULL) {
97        return NULL;
98    }
99
100    listRepPtr->canonicalFlag = 0;
101    listRepPtr->refCount = 0;
102    listRepPtr->maxElemCount = objc;
103
104    if (objv) {
105        Tcl_Obj **elemPtrs;
106        int i;
107
108        listRepPtr->elemCount = objc;
109        elemPtrs = &listRepPtr->elements;
110        for (i = 0;  i < objc;  i++) {
111            elemPtrs[i] = objv[i];
112            Tcl_IncrRefCount(elemPtrs[i]);
113        }
114    } else {
115        listRepPtr->elemCount = 0;
116    }
117    return listRepPtr;
118}
119
120/*
121 *----------------------------------------------------------------------
122 *
123 * Tcl_NewListObj --
124 *
125 *      This function is normally called when not debugging: i.e., when
126 *      TCL_MEM_DEBUG is not defined. It creates a new list object from an
127 *      (objc,objv) array: that is, each of the objc elements of the array
128 *      referenced by objv is inserted as an element into a new Tcl object.
129 *
130 *      When TCL_MEM_DEBUG is defined, this function just returns the result
131 *      of calling the debugging version Tcl_DbNewListObj.
132 *
133 * Results:
134 *      A new list object is returned that is initialized from the object
135 *      pointers in objv. If objc is less than or equal to zero, an empty
136 *      object is returned. The new object's string representation is left
137 *      NULL. The resulting new list object has ref count 0.
138 *
139 * Side effects:
140 *      The ref counts of the elements in objv are incremented since the
141 *      resulting list now refers to them.
142 *
143 *----------------------------------------------------------------------
144 */
145
146#ifdef TCL_MEM_DEBUG
147#undef Tcl_NewListObj
148
149Tcl_Obj *
150Tcl_NewListObj(
151    int objc,                   /* Count of objects referenced by objv. */
152    Tcl_Obj *CONST objv[])      /* An array of pointers to Tcl objects. */
153{
154    return Tcl_DbNewListObj(objc, objv, "unknown", 0);
155}
156
157#else /* if not TCL_MEM_DEBUG */
158
159Tcl_Obj *
160Tcl_NewListObj(
161    int objc,                   /* Count of objects referenced by objv. */
162    Tcl_Obj *CONST objv[])      /* An array of pointers to Tcl objects. */
163{
164    List *listRepPtr;
165    Tcl_Obj *listPtr;
166
167    TclNewObj(listPtr);
168
169    if (objc <= 0) {
170        return listPtr;
171    }
172
173    /*
174     * Create the internal rep.
175     */
176
177    listRepPtr = NewListIntRep(objc, objv);
178    if (!listRepPtr) {
179        Tcl_Panic("Not enough memory to allocate list");
180    }
181
182    /*
183     * Now create the object.
184     */
185
186    Tcl_InvalidateStringRep(listPtr);
187    listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
188    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
189    listPtr->typePtr = &tclListType;
190    listRepPtr->refCount++;
191
192    return listPtr;
193}
194#endif /* if TCL_MEM_DEBUG */
195
196/*
197 *----------------------------------------------------------------------
198 *
199 * Tcl_DbNewListObj --
200 *
201 *      This function is normally called when debugging: i.e., when
202 *      TCL_MEM_DEBUG is defined. It creates new list objects. It is the same
203 *      as the Tcl_NewListObj function above except that it calls
204 *      Tcl_DbCkalloc directly with the file name and line number from its
205 *      caller. This simplifies debugging since then the [memory active]
206 *      command will report the correct file name and line number when
207 *      reporting objects that haven't been freed.
208 *
209 *      When TCL_MEM_DEBUG is not defined, this function just returns the
210 *      result of calling Tcl_NewListObj.
211 *
212 * Results:
213 *      A new list object is returned that is initialized from the object
214 *      pointers in objv. If objc is less than or equal to zero, an empty
215 *      object is returned. The new object's string representation is left
216 *      NULL. The new list object has ref count 0.
217 *
218 * Side effects:
219 *      The ref counts of the elements in objv are incremented since the
220 *      resulting list now refers to them.
221 *
222 *----------------------------------------------------------------------
223 */
224
225#ifdef TCL_MEM_DEBUG
226
227Tcl_Obj *
228Tcl_DbNewListObj(
229    int objc,                   /* Count of objects referenced by objv. */
230    Tcl_Obj *CONST objv[],      /* An array of pointers to Tcl objects. */
231    CONST char *file,           /* The name of the source file calling this
232                                 * function; used for debugging. */
233    int line)                   /* Line number in the source file; used for
234                                 * debugging. */
235{
236    Tcl_Obj *listPtr;
237    List *listRepPtr;
238
239    TclDbNewObj(listPtr, file, line);
240
241    if (objc <= 0) {
242        return listPtr;
243    }
244
245    /*
246     * Create the internal rep.
247     */
248
249    listRepPtr = NewListIntRep(objc, objv);
250    if (!listRepPtr) {
251        Tcl_Panic("Not enough memory to allocate list");
252    }
253
254    /*
255     * Now create the object.
256     */
257
258    Tcl_InvalidateStringRep(listPtr);
259    listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
260    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
261    listPtr->typePtr = &tclListType;
262    listRepPtr->refCount++;
263
264    return listPtr;
265}
266
267#else /* if not TCL_MEM_DEBUG */
268
269Tcl_Obj *
270Tcl_DbNewListObj(
271    int objc,                   /* Count of objects referenced by objv. */
272    Tcl_Obj *CONST objv[],      /* An array of pointers to Tcl objects. */
273    CONST char *file,           /* The name of the source file calling this
274                                 * function; used for debugging. */
275    int line)                   /* Line number in the source file; used for
276                                 * debugging. */
277{
278    return Tcl_NewListObj(objc, objv);
279}
280#endif /* TCL_MEM_DEBUG */
281
282/*
283 *----------------------------------------------------------------------
284 *
285 * Tcl_SetListObj --
286 *
287 *      Modify an object to be a list containing each of the objc elements of
288 *      the object array referenced by objv.
289 *
290 * Results:
291 *      None.
292 *
293 * Side effects:
294 *      The object is made a list object and is initialized from the object
295 *      pointers in objv. If objc is less than or equal to zero, an empty
296 *      object is returned. The new object's string representation is left
297 *      NULL. The ref counts of the elements in objv are incremented since the
298 *      list now refers to them. The object's old string and internal
299 *      representations are freed and its type is set NULL.
300 *
301 *----------------------------------------------------------------------
302 */
303
304void
305Tcl_SetListObj(
306    Tcl_Obj *objPtr,            /* Object whose internal rep to init. */
307    int objc,                   /* Count of objects referenced by objv. */
308    Tcl_Obj *CONST objv[])      /* An array of pointers to Tcl objects. */
309{
310    List *listRepPtr;
311
312    if (Tcl_IsShared(objPtr)) {
313        Tcl_Panic("%s called with shared object", "Tcl_SetListObj");
314    }
315
316    /*
317     * Free any old string rep and any internal rep for the old type.
318     */
319
320    TclFreeIntRep(objPtr);
321    objPtr->typePtr = NULL;
322    Tcl_InvalidateStringRep(objPtr);
323
324    /*
325     * Set the object's type to "list" and initialize the internal rep.
326     * However, if there are no elements to put in the list, just give the
327     * object an empty string rep and a NULL type.
328     */
329
330    if (objc > 0) {
331        listRepPtr = NewListIntRep(objc, objv);
332        if (!listRepPtr) {
333            Tcl_Panic("Cannot allocate enough memory for Tcl_SetListObj");
334        }
335        objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
336        objPtr->internalRep.twoPtrValue.ptr2 = NULL;
337        objPtr->typePtr = &tclListType;
338        listRepPtr->refCount++;
339    } else {
340        objPtr->bytes = tclEmptyStringRep;
341        objPtr->length = 0;
342    }
343}
344
345/*
346 *----------------------------------------------------------------------
347 *
348 * TclListObjCopy --
349 *
350 *      Makes a "pure list" copy of a list value. This provides for the C
351 *      level a counterpart of the [lrange $list 0 end] command, while using
352 *      internals details to be as efficient as possible.
353 *
354 * Results:
355 *      Normally returns a pointer to a new Tcl_Obj, that contains the same
356 *      list value as *listPtr does. The returned Tcl_Obj has a refCount of
357 *      zero. If *listPtr does not hold a list, NULL is returned, and if
358 *      interp is non-NULL, an error message is recorded there.
359 *
360 * Side effects:
361 *      None.
362 *
363 *----------------------------------------------------------------------
364 */
365
366Tcl_Obj *
367TclListObjCopy(
368    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
369    Tcl_Obj *listPtr)           /* List object for which an element array is
370                                 * to be returned. */
371{
372    Tcl_Obj *copyPtr;
373
374    if (listPtr->typePtr != &tclListType) {
375        if (SetListFromAny(interp, listPtr) != TCL_OK) {
376            return NULL;
377        }
378    }
379
380    TclNewObj(copyPtr);
381    TclInvalidateStringRep(copyPtr);
382    DupListInternalRep(listPtr, copyPtr);
383    return copyPtr;
384}
385
386/*
387 *----------------------------------------------------------------------
388 *
389 * Tcl_ListObjGetElements --
390 *
391 *      This function returns an (objc,objv) array of the elements in a list
392 *      object.
393 *
394 * Results:
395 *      The return value is normally TCL_OK; in this case *objcPtr is set to
396 *      the count of list elements and *objvPtr is set to a pointer to an
397 *      array of (*objcPtr) pointers to each list element. If listPtr does not
398 *      refer to a list object and the object can not be converted to one,
399 *      TCL_ERROR is returned and an error message will be left in the
400 *      interpreter's result if interp is not NULL.
401 *
402 *      The objects referenced by the returned array should be treated as
403 *      readonly and their ref counts are _not_ incremented; the caller must
404 *      do that if it holds on to a reference. Furthermore, the pointer and
405 *      length returned by this function may change as soon as any function is
406 *      called on the list object; be careful about retaining the pointer in a
407 *      local data structure.
408 *
409 * Side effects:
410 *      The possible conversion of the object referenced by listPtr
411 *      to a list object.
412 *
413 *----------------------------------------------------------------------
414 */
415
416int
417Tcl_ListObjGetElements(
418    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
419    register Tcl_Obj *listPtr,  /* List object for which an element array is
420                                 * to be returned. */
421    int *objcPtr,               /* Where to store the count of objects
422                                 * referenced by objv. */
423    Tcl_Obj ***objvPtr)         /* Where to store the pointer to an array of
424                                 * pointers to the list's objects. */
425{
426    register List *listRepPtr;
427
428    if (listPtr->typePtr != &tclListType) {
429        int result, length;
430
431        (void) TclGetStringFromObj(listPtr, &length);
432        if (!length) {
433            *objcPtr = 0;
434            *objvPtr = NULL;
435            return TCL_OK;
436        }
437
438        result = SetListFromAny(interp, listPtr);
439        if (result != TCL_OK) {
440            return result;
441        }
442    }
443    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
444    *objcPtr = listRepPtr->elemCount;
445    *objvPtr = &listRepPtr->elements;
446    return TCL_OK;
447}
448
449/*
450 *----------------------------------------------------------------------
451 *
452 * Tcl_ListObjAppendList --
453 *
454 *      This function appends the objects in the list referenced by
455 *      elemListPtr to the list object referenced by listPtr. If listPtr is
456 *      not already a list object, an attempt will be made to convert it to
457 *      one.
458 *
459 * Results:
460 *      The return value is normally TCL_OK. If listPtr or elemListPtr do not
461 *      refer to list objects and they can not be converted to one, TCL_ERROR
462 *      is returned and an error message is left in the interpreter's result
463 *      if interp is not NULL.
464 *
465 * Side effects:
466 *      The reference counts of the elements in elemListPtr are incremented
467 *      since the list now refers to them. listPtr and elemListPtr are
468 *      converted, if necessary, to list objects. Also, appending the new
469 *      elements may cause listObj's array of element pointers to grow.
470 *      listPtr's old string representation, if any, is invalidated.
471 *
472 *----------------------------------------------------------------------
473 */
474
475int
476Tcl_ListObjAppendList(
477    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
478    register Tcl_Obj *listPtr,  /* List object to append elements to. */
479    Tcl_Obj *elemListPtr)       /* List obj with elements to append. */
480{
481    int listLen, objc, result;
482    Tcl_Obj **objv;
483
484    if (Tcl_IsShared(listPtr)) {
485        Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendList");
486    }
487
488    result = TclListObjLength(interp, listPtr, &listLen);
489    if (result != TCL_OK) {
490        return result;
491    }
492
493    result = TclListObjGetElements(interp, elemListPtr, &objc, &objv);
494    if (result != TCL_OK) {
495        return result;
496    }
497
498    /*
499     * Insert objc new elements starting after the lists's last element.
500     * Delete zero existing elements.
501     */
502
503    return Tcl_ListObjReplace(interp, listPtr, listLen, 0, objc, objv);
504}
505
506/*
507 *----------------------------------------------------------------------
508 *
509 * Tcl_ListObjAppendElement --
510 *
511 *      This function is a special purpose version of Tcl_ListObjAppendList:
512 *      it appends a single object referenced by objPtr to the list object
513 *      referenced by listPtr. If listPtr is not already a list object, an
514 *      attempt will be made to convert it to one.
515 *
516 * Results:
517 *      The return value is normally TCL_OK; in this case objPtr is added to
518 *      the end of listPtr's list. If listPtr does not refer to a list object
519 *      and the object can not be converted to one, TCL_ERROR is returned and
520 *      an error message will be left in the interpreter's result if interp is
521 *      not NULL.
522 *
523 * Side effects:
524 *      The ref count of objPtr is incremented since the list now refers to
525 *      it. listPtr will be converted, if necessary, to a list object. Also,
526 *      appending the new element may cause listObj's array of element
527 *      pointers to grow. listPtr's old string representation, if any, is
528 *      invalidated.
529 *
530 *----------------------------------------------------------------------
531 */
532
533int
534Tcl_ListObjAppendElement(
535    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
536    Tcl_Obj *listPtr,           /* List object to append objPtr to. */
537    Tcl_Obj *objPtr)            /* Object to append to listPtr's list. */
538{
539    register List *listRepPtr;
540    register Tcl_Obj **elemPtrs;
541    int numElems, numRequired, newMax, newSize, i;
542
543    if (Tcl_IsShared(listPtr)) {
544        Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendElement");
545    }
546    if (listPtr->typePtr != &tclListType) {
547        int result, length;
548
549        (void) TclGetStringFromObj(listPtr, &length);
550        if (!length) {
551            Tcl_SetListObj(listPtr, 1, &objPtr);
552            return TCL_OK;
553        }
554
555        result = SetListFromAny(interp, listPtr);
556        if (result != TCL_OK) {
557            return result;
558        }
559    }
560
561    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
562    numElems = listRepPtr->elemCount;
563    numRequired = numElems + 1 ;
564
565    /*
566     * If there is no room in the current array of element pointers, allocate
567     * a new, larger array and copy the pointers to it. If the List struct is
568     * shared, allocate a new one.
569     */
570
571    if (numRequired > listRepPtr->maxElemCount){
572        newMax = 2 * numRequired;
573        newSize = sizeof(List) + ((newMax-1) * sizeof(Tcl_Obj *));
574    } else {
575        newMax = listRepPtr->maxElemCount;
576        newSize = 0;
577    }
578
579    if (listRepPtr->refCount > 1) {
580        List *oldListRepPtr = listRepPtr;
581        Tcl_Obj **oldElems;
582
583        listRepPtr = NewListIntRep(newMax, NULL);
584        if (!listRepPtr) {
585            Tcl_Panic("Not enough memory to allocate list");
586        }
587        oldElems = &oldListRepPtr->elements;
588        elemPtrs = &listRepPtr->elements;
589        for (i=0; i<numElems; i++) {
590            elemPtrs[i] = oldElems[i];
591            Tcl_IncrRefCount(elemPtrs[i]);
592        }
593        listRepPtr->elemCount = numElems;
594        listRepPtr->refCount++;
595        oldListRepPtr->refCount--;
596        listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
597    } else if (newSize) {
598        listRepPtr = (List *) ckrealloc((char *)listRepPtr, (size_t)newSize);
599        listRepPtr->maxElemCount = newMax;
600        listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
601    }
602
603    /*
604     * Add objPtr to the end of listPtr's array of element pointers. Increment
605     * the ref count for the (now shared) objPtr.
606     */
607
608    elemPtrs = &listRepPtr->elements;
609    elemPtrs[numElems] = objPtr;
610    Tcl_IncrRefCount(objPtr);
611    listRepPtr->elemCount++;
612
613    /*
614     * Invalidate any old string representation since the list's internal
615     * representation has changed.
616     */
617
618    Tcl_InvalidateStringRep(listPtr);
619    return TCL_OK;
620}
621
622/*
623 *----------------------------------------------------------------------
624 *
625 * Tcl_ListObjIndex --
626 *
627 *      This function returns a pointer to the index'th object from the list
628 *      referenced by listPtr. The first element has index 0. If index is
629 *      negative or greater than or equal to the number of elements in the
630 *      list, a NULL is returned. If listPtr is not a list object, an attempt
631 *      will be made to convert it to a list.
632 *
633 * Results:
634 *      The return value is normally TCL_OK; in this case objPtrPtr is set to
635 *      the Tcl_Obj pointer for the index'th list element or NULL if index is
636 *      out of range. This object should be treated as readonly and its ref
637 *      count is _not_ incremented; the caller must do that if it holds on to
638 *      the reference. If listPtr does not refer to a list and can't be
639 *      converted to one, TCL_ERROR is returned and an error message is left
640 *      in the interpreter's result if interp is not NULL.
641 *
642 * Side effects:
643 *      listPtr will be converted, if necessary, to a list object.
644 *
645 *----------------------------------------------------------------------
646 */
647
648int
649Tcl_ListObjIndex(
650    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
651    register Tcl_Obj *listPtr,  /* List object to index into. */
652    register int index,         /* Index of element to return. */
653    Tcl_Obj **objPtrPtr)        /* The resulting Tcl_Obj* is stored here. */
654{
655    register List *listRepPtr;
656
657    if (listPtr->typePtr != &tclListType) {
658        int result, length;
659
660        (void) TclGetStringFromObj(listPtr, &length);
661        if (!length) {
662            *objPtrPtr = NULL;
663            return TCL_OK;
664        }
665
666        result = SetListFromAny(interp, listPtr);
667        if (result != TCL_OK) {
668            return result;
669        }
670    }
671
672    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
673    if ((index < 0) || (index >= listRepPtr->elemCount)) {
674        *objPtrPtr = NULL;
675    } else {
676        *objPtrPtr = (&listRepPtr->elements)[index];
677    }
678
679    return TCL_OK;
680}
681
682/*
683 *----------------------------------------------------------------------
684 *
685 * Tcl_ListObjLength --
686 *
687 *      This function returns the number of elements in a list object. If the
688 *      object is not already a list object, an attempt will be made to
689 *      convert it to one.
690 *
691 * Results:
692 *      The return value is normally TCL_OK; in this case *intPtr will be set
693 *      to the integer count of list elements. If listPtr does not refer to a
694 *      list object and the object can not be converted to one, TCL_ERROR is
695 *      returned and an error message will be left in the interpreter's result
696 *      if interp is not NULL.
697 *
698 * Side effects:
699 *      The possible conversion of the argument object to a list object.
700 *
701 *----------------------------------------------------------------------
702 */
703
704int
705Tcl_ListObjLength(
706    Tcl_Interp *interp,         /* Used to report errors if not NULL. */
707    register Tcl_Obj *listPtr,  /* List object whose #elements to return. */
708    register int *intPtr)       /* The resulting int is stored here. */
709{
710    register List *listRepPtr;
711
712    if (listPtr->typePtr != &tclListType) {
713        int result, length;
714
715        (void) TclGetStringFromObj(listPtr, &length);
716        if (!length) {
717            *intPtr = 0;
718            return TCL_OK;
719        }
720
721        result = SetListFromAny(interp, listPtr);
722        if (result != TCL_OK) {
723            return result;
724        }
725    }
726
727    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
728    *intPtr = listRepPtr->elemCount;
729    return TCL_OK;
730}
731
732/*
733 *----------------------------------------------------------------------
734 *
735 * Tcl_ListObjReplace --
736 *
737 *      This function replaces zero or more elements of the list referenced by
738 *      listPtr with the objects from an (objc,objv) array. The objc elements
739 *      of the array referenced by objv replace the count elements in listPtr
740 *      starting at first.
741 *
742 *      If the argument first is zero or negative, it refers to the first
743 *      element. If first is greater than or equal to the number of elements
744 *      in the list, then no elements are deleted; the new elements are
745 *      appended to the list. Count gives the number of elements to replace.
746 *      If count is zero or negative then no elements are deleted; the new
747 *      elements are simply inserted before first.
748 *
749 *      The argument objv refers to an array of objc pointers to the new
750 *      elements to be added to listPtr in place of those that were deleted.
751 *      If objv is NULL, no new elements are added. If listPtr is not a list
752 *      object, an attempt will be made to convert it to one.
753 *
754 * Results:
755 *      The return value is normally TCL_OK. If listPtr does not refer to a
756 *      list object and can not be converted to one, TCL_ERROR is returned and
757 *      an error message will be left in the interpreter's result if interp is
758 *      not NULL.
759 *
760 * Side effects:
761 *      The ref counts of the objc elements in objv are incremented since the
762 *      resulting list now refers to them. Similarly, the ref counts for
763 *      replaced objects are decremented. listPtr is converted, if necessary,
764 *      to a list object. listPtr's old string representation, if any, is
765 *      freed.
766 *
767 *----------------------------------------------------------------------
768 */
769
770int
771Tcl_ListObjReplace(
772    Tcl_Interp *interp,         /* Used for error reporting if not NULL. */
773    Tcl_Obj *listPtr,           /* List object whose elements to replace. */
774    int first,                  /* Index of first element to replace. */
775    int count,                  /* Number of elements to replace. */
776    int objc,                   /* Number of objects to insert. */
777    Tcl_Obj *CONST objv[])      /* An array of objc pointers to Tcl objects to
778                                 * insert. */
779{
780    List *listRepPtr;
781    register Tcl_Obj **elemPtrs;
782    int numElems, numRequired, numAfterLast, start, i, j, isShared;
783
784    if (Tcl_IsShared(listPtr)) {
785        Tcl_Panic("%s called with shared object", "Tcl_ListObjReplace");
786    }
787    if (listPtr->typePtr != &tclListType) {
788        int length;
789
790        (void) TclGetStringFromObj(listPtr, &length);
791        if (!length) {
792            if (objc) {
793                Tcl_SetListObj(listPtr, objc, NULL);
794            } else {
795                return TCL_OK;
796            }
797        } else {
798            int result = SetListFromAny(interp, listPtr);
799
800            if (result != TCL_OK) {
801                return result;
802            }
803        }
804    }
805
806    /*
807     * Note that when count == 0 and objc == 0, this routine is logically a
808     * no-op, removing and adding no elements to the list. However, by flowing
809     * through this routine anyway, we get the important side effect that the
810     * resulting listPtr is a list in canoncial form. This is important.
811     * Resist any temptation to optimize this case.
812     */
813
814    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
815    elemPtrs = &listRepPtr->elements;
816    numElems = listRepPtr->elemCount;
817
818    if (first < 0) {
819        first = 0;
820    }
821    if (first >= numElems) {
822        first = numElems;       /* So we'll insert after last element. */
823    }
824    if (count < 0) {
825        count = 0;
826    } else if (numElems < first+count) {
827        count = numElems - first;
828    }
829
830    isShared = (listRepPtr->refCount > 1);
831    numRequired = numElems - count + objc;
832
833    if ((numRequired <= listRepPtr->maxElemCount) && !isShared) {
834        int shift;
835
836        /*
837         * Can use the current List struct. First "delete" count elements
838         * starting at first.
839         */
840
841        for (j = first;  j < first + count;  j++) {
842            Tcl_Obj *victimPtr = elemPtrs[j];
843
844            TclDecrRefCount(victimPtr);
845        }
846
847        /*
848         * Shift the elements after the last one removed to their new
849         * locations.
850         */
851
852        start = first + count;
853        numAfterLast = numElems - start;
854        shift = objc - count;   /* numNewElems - numDeleted */
855        if ((numAfterLast > 0) && (shift != 0)) {
856            Tcl_Obj **src = elemPtrs + start;
857
858            memmove(src+shift, src, (size_t) numAfterLast * sizeof(Tcl_Obj*));
859        }
860    } else {
861        /*
862         * Cannot use the current List struct; it is shared, too small, or
863         * both. Allocate a new struct and insert elements into it.
864         */
865
866        List *oldListRepPtr = listRepPtr;
867        Tcl_Obj **oldPtrs = elemPtrs;
868        int newMax;
869
870        if (numRequired > listRepPtr->maxElemCount){
871            newMax = 2 * numRequired;
872        } else {
873            newMax = listRepPtr->maxElemCount;
874        }
875
876        listRepPtr = NewListIntRep(newMax, NULL);
877        if (!listRepPtr) {
878            Tcl_Panic("Not enough memory to allocate list");
879        }
880
881        listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
882        listRepPtr->refCount++;
883
884        elemPtrs = &listRepPtr->elements;
885
886        if (isShared) {
887            /*
888             * The old struct will remain in place; need new refCounts for the
889             * new List struct references. Copy over only the surviving
890             * elements.
891             */
892
893            for (i=0; i < first; i++) {
894                elemPtrs[i] = oldPtrs[i];
895                Tcl_IncrRefCount(elemPtrs[i]);
896            }
897            for (i = first + count, j = first + objc;
898                    j < numRequired; i++, j++) {
899                elemPtrs[j] = oldPtrs[i];
900                Tcl_IncrRefCount(elemPtrs[j]);
901            }
902
903            oldListRepPtr->refCount--;
904        } else {
905            /*
906             * The old struct will be removed; use its inherited refCounts.
907             */
908
909            if (first > 0) {
910                memcpy(elemPtrs, oldPtrs, (size_t) first * sizeof(Tcl_Obj *));
911            }
912
913            /*
914             * "Delete" count elements starting at first.
915             */
916
917            for (j = first;  j < first + count;  j++) {
918                Tcl_Obj *victimPtr = oldPtrs[j];
919
920                TclDecrRefCount(victimPtr);
921            }
922
923            /*
924             * Copy the elements after the last one removed, shifted to their
925             * new locations.
926             */
927
928            start = first + count;
929            numAfterLast = numElems - start;
930            if (numAfterLast > 0) {
931                memcpy(elemPtrs + first + objc, oldPtrs + start,
932                        (size_t) numAfterLast * sizeof(Tcl_Obj *));
933            }
934
935            ckfree((char *) oldListRepPtr);
936        }
937    }
938
939    /*
940     * Insert the new elements into elemPtrs before "first". We don't do a
941     * memcpy here because we must increment the reference counts for the
942     * added elements, so we must explicitly loop anyway.
943     */
944
945    for (i=0,j=first ; i<objc ; i++,j++) {
946        elemPtrs[j] = objv[i];
947        Tcl_IncrRefCount(objv[i]);
948    }
949
950    /*
951     * Update the count of elements.
952     */
953
954    listRepPtr->elemCount = numRequired;
955
956    /*
957     * Invalidate and free any old string representation since it no longer
958     * reflects the list's internal representation.
959     */
960
961    Tcl_InvalidateStringRep(listPtr);
962    return TCL_OK;
963}
964
965/*
966 *----------------------------------------------------------------------
967 *
968 * TclLindexList --
969 *
970 *      This procedure handles the 'lindex' command when objc==3.
971 *
972 * Results:
973 *      Returns a pointer to the object extracted, or NULL if an error
974 *      occurred. The returned object already includes one reference count for
975 *      the pointer returned.
976 *
977 * Side effects:
978 *      None.
979 *
980 * Notes:
981 *      This procedure is implemented entirely as a wrapper around
982 *      TclLindexFlat. All it does is reconfigure the argument format into the
983 *      form required by TclLindexFlat, while taking care to manage shimmering
984 *      in such a way that we tend to keep the most useful intreps and/or
985 *      avoid the most expensive conversions.
986 *
987 *----------------------------------------------------------------------
988 */
989
990Tcl_Obj *
991TclLindexList(
992    Tcl_Interp *interp,         /* Tcl interpreter. */
993    Tcl_Obj *listPtr,           /* List being unpacked. */
994    Tcl_Obj *argPtr)            /* Index or index list. */
995{
996
997    int index;                  /* Index into the list. */
998    Tcl_Obj **indices;          /* Array of list indices. */
999    int indexCount;             /* Size of the array of list indices. */
1000    Tcl_Obj *indexListCopy;
1001
1002    /*
1003     * Determine whether argPtr designates a list or a single index. We have
1004     * to be careful about the order of the checks to avoid repeated
1005     * shimmering; see TIP#22 and TIP#33 for the details.
1006     */
1007
1008    if (argPtr->typePtr != &tclListType
1009            && TclGetIntForIndexM(NULL , argPtr, 0, &index) == TCL_OK) {
1010        /*
1011         * argPtr designates a single index.
1012         */
1013
1014        return TclLindexFlat(interp, listPtr, 1, &argPtr);
1015    }
1016
1017    /*
1018     * Here we make a private copy of the index list argument to avoid any
1019     * shimmering issues that might invalidate the indices array below while
1020     * we are still using it. This is probably unnecessary. It does not appear
1021     * that any damaging shimmering is possible, and no test has been devised
1022     * to show any error when this private copy is not made. But it's cheap,
1023     * and it offers some future-proofing insurance in case the TclLindexFlat
1024     * implementation changes in some unexpected way, or some new form of
1025     * trace or callback permits things to happen that the current
1026     * implementation does not.
1027     */
1028
1029    indexListCopy = TclListObjCopy(NULL, argPtr);
1030    if (indexListCopy == NULL) {
1031        /*
1032         * argPtr designates something that is neither an index nor a
1033         * well-formed list. Report the error via TclLindexFlat.
1034         */
1035
1036        return TclLindexFlat(interp, listPtr, 1, &argPtr);
1037    }
1038
1039    TclListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
1040    listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);
1041    Tcl_DecrRefCount(indexListCopy);
1042    return listPtr;
1043}
1044
1045/*
1046 *----------------------------------------------------------------------
1047 *
1048 * TclLindexFlat --
1049 *
1050 *      This procedure is the core of the 'lindex' command, with all index
1051 *      arguments presented as a flat list.
1052 *
1053 * Results:
1054 *      Returns a pointer to the object extracted, or NULL if an error
1055 *      occurred. The returned object already includes one reference count for
1056 *      the pointer returned.
1057 *
1058 * Side effects:
1059 *      None.
1060 *
1061 * Notes:
1062 *      The reference count of the returned object includes one reference
1063 *      corresponding to the pointer returned. Thus, the calling code will
1064 *      usually do something like:
1065 *              Tcl_SetObjResult(interp, result);
1066 *              Tcl_DecrRefCount(result);
1067 *
1068 *----------------------------------------------------------------------
1069 */
1070
1071Tcl_Obj *
1072TclLindexFlat(
1073    Tcl_Interp *interp,         /* Tcl interpreter. */
1074    Tcl_Obj *listPtr,           /* Tcl object representing the list. */
1075    int indexCount,             /* Count of indices. */
1076    Tcl_Obj *const indexArray[])/* Array of pointers to Tcl objects that
1077                                 * represent the indices in the list. */
1078{
1079    int i;
1080
1081    Tcl_IncrRefCount(listPtr);
1082
1083    for (i=0 ; i<indexCount && listPtr ; i++) {
1084        int index, listLen;
1085        Tcl_Obj **elemPtrs, *sublistCopy;
1086
1087        /*
1088         * Here we make a private copy of the current sublist, so we avoid any
1089         * shimmering issues that might invalidate the elemPtr array below
1090         * while we are still using it. See test lindex-8.4.
1091         */
1092
1093        sublistCopy = TclListObjCopy(interp, listPtr);
1094        Tcl_DecrRefCount(listPtr);
1095        listPtr = NULL;
1096
1097        if (sublistCopy == NULL) {
1098            /*
1099             * The sublist is not a list at all => error.
1100             */
1101
1102            break;
1103        }
1104        TclListObjGetElements(NULL, sublistCopy, &listLen, &elemPtrs);
1105
1106        if (TclGetIntForIndexM(interp, indexArray[i], /*endValue*/ listLen-1,
1107                &index) == TCL_OK) {
1108            if (index<0 || index>=listLen) {
1109                /*
1110                 * Index is out of range. Break out of loop with empty result.
1111                 * First check remaining indices for validity
1112                 */
1113
1114                while (++i < indexCount) {
1115                    if (TclGetIntForIndexM(interp, indexArray[i], -1, &index)
1116                        != TCL_OK) {
1117                        Tcl_DecrRefCount(sublistCopy);
1118                        return NULL;
1119                    }
1120                }
1121                listPtr = Tcl_NewObj();
1122            } else {
1123                /*
1124                 * Extract the pointer to the appropriate element.
1125                 */
1126
1127                listPtr = elemPtrs[index];
1128            }
1129            Tcl_IncrRefCount(listPtr);
1130        }
1131        Tcl_DecrRefCount(sublistCopy);
1132    }
1133
1134    return listPtr;
1135}
1136
1137/*
1138 *----------------------------------------------------------------------
1139 *
1140 * TclLsetList --
1141 *
1142 *      Core of the 'lset' command when objc == 4. Objv[2] may be either a
1143 *      scalar index or a list of indices.
1144 *
1145 * Results:
1146 *      Returns the new value of the list variable, or NULL if there was an
1147 *      error. The returned object includes one reference count for the
1148 *      pointer returned.
1149 *
1150 * Side effects:
1151 *      None.
1152 *
1153 * Notes:
1154 *      This procedure is implemented entirely as a wrapper around
1155 *      TclLsetFlat. All it does is reconfigure the argument format into the
1156 *      form required by TclLsetFlat, while taking care to manage shimmering
1157 *      in such a way that we tend to keep the most useful intreps and/or
1158 *      avoid the most expensive conversions.
1159 *
1160 *----------------------------------------------------------------------
1161 */
1162
1163Tcl_Obj *
1164TclLsetList(
1165    Tcl_Interp *interp,         /* Tcl interpreter. */
1166    Tcl_Obj *listPtr,           /* Pointer to the list being modified. */
1167    Tcl_Obj *indexArgPtr,       /* Index or index-list arg to 'lset'. */
1168    Tcl_Obj *valuePtr)          /* Value arg to 'lset'. */
1169{
1170    int indexCount;             /* Number of indices in the index list. */
1171    Tcl_Obj **indices;          /* Vector of indices in the index list. */
1172    Tcl_Obj *retValuePtr;       /* Pointer to the list to be returned. */
1173    int index;                  /* Current index in the list - discarded. */
1174    Tcl_Obj *indexListCopy;
1175
1176    /*
1177     * Determine whether the index arg designates a list or a single index.
1178     * We have to be careful about the order of the checks to avoid repeated
1179     * shimmering; see TIP #22 and #23 for details.
1180     */
1181
1182    if (indexArgPtr->typePtr != &tclListType
1183            && TclGetIntForIndexM(NULL, indexArgPtr, 0, &index) == TCL_OK) {
1184        /*
1185         * indexArgPtr designates a single index.
1186         */
1187
1188        return TclLsetFlat(interp, listPtr, 1, &indexArgPtr, valuePtr);
1189
1190    }
1191
1192    indexListCopy = TclListObjCopy(NULL, indexArgPtr);
1193    if (indexListCopy == NULL) {
1194        /*
1195         * indexArgPtr designates something that is neither an index nor a
1196         * well formed list. Report the error via TclLsetFlat.
1197         */
1198
1199        return TclLsetFlat(interp, listPtr, 1, &indexArgPtr, valuePtr);
1200    }
1201    TclListObjGetElements(NULL, indexArgPtr, &indexCount, &indices);
1202
1203    /*
1204     * Let TclLsetFlat handle the actual lset'ting.
1205     */
1206
1207    retValuePtr = TclLsetFlat(interp, listPtr, indexCount, indices, valuePtr);
1208
1209    Tcl_DecrRefCount(indexListCopy);
1210    return retValuePtr;
1211}
1212
1213/*
1214 *----------------------------------------------------------------------
1215 *
1216 * TclLsetFlat --
1217 *
1218 *      Core engine of the 'lset' command.
1219 *
1220 * Results:
1221 *      Returns the new value of the list variable, or NULL if an error
1222 *      occurred. The returned object includes one reference count for
1223 *      the pointer returned.
1224 *
1225 * Side effects:
1226 *      On entry, the reference count of the variable value does not reflect
1227 *      any references held on the stack. The first action of this function is
1228 *      to determine whether the object is shared, and to duplicate it if it
1229 *      is. The reference count of the duplicate is incremented. At this
1230 *      point, the reference count will be 1 for either case, so that the
1231 *      object will appear to be unshared.
1232 *
1233 *      If an error occurs, and the object has been duplicated, the reference
1234 *      count on the duplicate is decremented so that it is now 0: this
1235 *      dismisses any memory that was allocated by this function.
1236 *
1237 *      If no error occurs, the reference count of the original object is
1238 *      incremented if the object has not been duplicated, and nothing is done
1239 *      to a reference count of the duplicate. Now the reference count of an
1240 *      unduplicated object is 2 (the returned pointer, plus the one stored in
1241 *      the variable). The reference count of a duplicate object is 1,
1242 *      reflecting that the returned pointer is the only active reference. The
1243 *      caller is expected to store the returned value back in the variable
1244 *      and decrement its reference count. (INST_STORE_* does exactly this.)
1245 *
1246 *      Surgery is performed on the unshared list value to produce the result.
1247 *      TclLsetFlat maintains a linked list of Tcl_Obj's whose string
1248 *      representations must be spoilt by threading via 'ptr2' of the
1249 *      two-pointer internal representation. On entry to TclLsetFlat, the
1250 *      values of 'ptr2' are immaterial; on exit, the 'ptr2' field of any
1251 *      Tcl_Obj that has been modified is set to NULL.
1252 *
1253 *----------------------------------------------------------------------
1254 */
1255
1256Tcl_Obj *
1257TclLsetFlat(
1258    Tcl_Interp *interp,         /* Tcl interpreter. */
1259    Tcl_Obj *listPtr,           /* Pointer to the list being modified. */
1260    int indexCount,             /* Number of index args. */
1261    Tcl_Obj *const indexArray[],
1262                                /* Index args. */
1263    Tcl_Obj *valuePtr)          /* Value arg to 'lset'. */
1264{
1265    int index, result;
1266    Tcl_Obj *subListPtr, *retValuePtr, *chainPtr;
1267
1268    /*
1269     * If there are no indices, simply return the new value.
1270     * (Without indices, [lset] is a synonym for [set].
1271     */
1272
1273    if (indexCount == 0) {
1274        Tcl_IncrRefCount(valuePtr);
1275        return valuePtr;
1276    }
1277
1278    /*
1279     * If the list is shared, make a copy we can modify (copy-on-write).
1280     * We use Tcl_DuplicateObj() instead of TclListObjCopy() for a few
1281     * reasons: 1) we have not yet confirmed listPtr is actually a list;
1282     * 2) We make a verbatim copy of any existing string rep, and when
1283     * we combine that with the delayed invalidation of string reps of
1284     * modified Tcl_Obj's implemented below, the outcome is that any
1285     * error condition that causes this routine to return NULL, will
1286     * leave the string rep of listPtr and all elements to be unchanged.
1287     */
1288
1289    subListPtr = Tcl_IsShared(listPtr) ? Tcl_DuplicateObj(listPtr) : listPtr;
1290
1291    /*
1292     * Anchor the linked list of Tcl_Obj's whose string reps must be
1293     * invalidated if the operation succeeds.
1294     */
1295
1296    retValuePtr = subListPtr;
1297    chainPtr = NULL;
1298
1299    /*
1300     * Loop through all the index arguments, and for each one dive
1301     * into the appropriate sublist.
1302     */
1303
1304    do {
1305        int elemCount;
1306        Tcl_Obj *parentList, **elemPtrs;
1307
1308        /* Check for the possible error conditions... */
1309        result = TCL_ERROR;
1310        if (TclListObjGetElements(interp, subListPtr, &elemCount, &elemPtrs)
1311                != TCL_OK) {
1312            /* ...the sublist we're indexing into isn't a list at all. */
1313            break;
1314        }
1315
1316        /*
1317         * WARNING: the macro TclGetIntForIndexM is not safe for
1318         * post-increments, avoid '*indexArray++' here.
1319         */
1320       
1321        if (TclGetIntForIndexM(interp, *indexArray, elemCount - 1, &index)
1322                != TCL_OK)  {
1323            /* ...the index we're trying to use isn't an index at all. */
1324            indexArray++;
1325            break;
1326        }
1327        indexArray++;
1328
1329        if (index < 0 || index >= elemCount) {
1330            /* ...the index points outside the sublist. */
1331            Tcl_SetObjResult(interp,
1332                    Tcl_NewStringObj("list index out of range", -1));
1333            break;
1334        }
1335
1336        /*
1337         * No error conditions.  As long as we're not yet on the last
1338         * index, determine the next sublist for the next pass through
1339         * the loop, and take steps to make sure it is an unshared copy,
1340         * as we intend to modify it.
1341         */
1342
1343        result = TCL_OK;
1344        if (--indexCount) {
1345            parentList = subListPtr;
1346            subListPtr = elemPtrs[index];
1347            if (Tcl_IsShared(subListPtr)) {
1348                subListPtr = Tcl_DuplicateObj(subListPtr);
1349            }
1350
1351            /*
1352             * Replace the original elemPtr[index] in parentList with a copy
1353             * we know to be unshared.  This call will also deal with the
1354             * situation where parentList shares its intrep with other
1355             * Tcl_Obj's.  Dealing with the shared intrep case can cause
1356             * subListPtr to become shared again, so detect that case and
1357             * make and store another copy.
1358             */
1359
1360            TclListObjSetElement(NULL, parentList, index, subListPtr);
1361            if (Tcl_IsShared(subListPtr)) {
1362                subListPtr = Tcl_DuplicateObj(subListPtr);
1363                TclListObjSetElement(NULL, parentList, index, subListPtr);
1364            }
1365
1366            /*
1367             * The TclListObjSetElement() calls do not spoil the string
1368             * rep of parentList, and that's fine for now, since all we've
1369             * done so far is replace a list element with an unshared copy.
1370             * The list value remains the same, so the string rep. is still
1371             * valid, and unchanged, which is good because if this whole
1372             * routine returns NULL, we'd like to leave no change to the
1373             * value of the lset variable.  Later on, when we set valuePtr
1374             * in its proper place, then all containing lists will have
1375             * their values changed, and will need their string reps spoiled.
1376             * We maintain a list of all those Tcl_Obj's (via a little intrep
1377             * surgery) so we can spoil them at that time.
1378             */
1379
1380            parentList->internalRep.twoPtrValue.ptr2 = (void *) chainPtr;
1381            chainPtr = parentList;
1382        }
1383    } while (indexCount > 0);
1384
1385    /*
1386     * Either we've detected and error condition, and exited the loop
1387     * with result == TCL_ERROR, or we've successfully reached the last
1388     * index, and we're ready to store valuePtr.  In either case, we
1389     * need to clean up our string spoiling list of Tcl_Obj's.
1390     */
1391
1392    while (chainPtr) {
1393        Tcl_Obj *objPtr = chainPtr;
1394
1395        if (result == TCL_OK) {
1396
1397            /*
1398             * We're going to store valuePtr, so spoil string reps
1399             * of all containing lists.
1400             */
1401
1402            Tcl_InvalidateStringRep(objPtr);
1403        }
1404
1405        /* Clear away our intrep surgery mess */
1406        chainPtr = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr2;
1407        objPtr->internalRep.twoPtrValue.ptr2 = NULL;
1408    }
1409
1410    if (result != TCL_OK) {
1411        /*
1412         * Error return; message is already in interp. Clean up
1413         * any excess memory.
1414         */
1415        if (retValuePtr != listPtr) {
1416            Tcl_DecrRefCount(retValuePtr);
1417        }
1418        return NULL;
1419    }
1420
1421    /* Store valuePtr in proper sublist and return */
1422    TclListObjSetElement(NULL, subListPtr, index, valuePtr);
1423    Tcl_InvalidateStringRep(subListPtr);
1424    Tcl_IncrRefCount(retValuePtr);
1425    return retValuePtr;
1426}
1427
1428/*
1429 *----------------------------------------------------------------------
1430 *
1431 * TclListObjSetElement --
1432 *
1433 *      Set a single element of a list to a specified value
1434 *
1435 * Results:
1436 *      The return value is normally TCL_OK. If listPtr does not refer to a
1437 *      list object and cannot be converted to one, TCL_ERROR is returned and
1438 *      an error message will be left in the interpreter result if interp is
1439 *      not NULL. Similarly, if index designates an element outside the range
1440 *      [0..listLength-1], where listLength is the count of elements in the
1441 *      list object designated by listPtr, TCL_ERROR is returned and an error
1442 *      message is left in the interpreter result.
1443 *
1444 * Side effects:
1445 *      Tcl_Panic if listPtr designates a shared object. Otherwise, attempts
1446 *      to convert it to a list with a non-shared internal rep. Decrements the
1447 *      ref count of the object at the specified index within the list,
1448 *      replaces with the object designated by valuePtr, and increments the
1449 *      ref count of the replacement object.
1450 *
1451 *      It is the caller's responsibility to invalidate the string
1452 *      representation of the object.
1453 *
1454 *----------------------------------------------------------------------
1455 */
1456
1457int
1458TclListObjSetElement(
1459    Tcl_Interp *interp,         /* Tcl interpreter; used for error reporting
1460                                 * if not NULL. */
1461    Tcl_Obj *listPtr,           /* List object in which element should be
1462                                 * stored. */
1463    int index,                  /* Index of element to store. */
1464    Tcl_Obj *valuePtr)          /* Tcl object to store in the designated list
1465                                 * element. */
1466{
1467    List *listRepPtr;           /* Internal representation of the list being
1468                                 * modified. */
1469    Tcl_Obj **elemPtrs;         /* Pointers to elements of the list. */
1470    int elemCount;              /* Number of elements in the list. */
1471
1472    /*
1473     * Ensure that the listPtr parameter designates an unshared list.
1474     */
1475
1476    if (Tcl_IsShared(listPtr)) {
1477        Tcl_Panic("%s called with shared object", "TclListObjSetElement");
1478    }
1479    if (listPtr->typePtr != &tclListType) {
1480        int length, result;
1481
1482        (void) TclGetStringFromObj(listPtr, &length);
1483        if (!length) {
1484            Tcl_SetObjResult(interp,
1485                    Tcl_NewStringObj("list index out of range", -1));
1486            return TCL_ERROR;
1487        }
1488        result = SetListFromAny(interp, listPtr);
1489        if (result != TCL_OK) {
1490            return result;
1491        }
1492    }
1493
1494    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
1495    elemCount = listRepPtr->elemCount;
1496    elemPtrs = &listRepPtr->elements;
1497
1498    /*
1499     * Ensure that the index is in bounds.
1500     */
1501
1502    if (index<0 || index>=elemCount) {
1503        if (interp != NULL) {
1504            Tcl_SetObjResult(interp,
1505                    Tcl_NewStringObj("list index out of range", -1));
1506        }
1507        return TCL_ERROR;
1508    }
1509
1510    /*
1511     * If the internal rep is shared, replace it with an unshared copy.
1512     */
1513
1514    if (listRepPtr->refCount > 1) {
1515        List *oldListRepPtr = listRepPtr;
1516        Tcl_Obj **oldElemPtrs = elemPtrs;
1517        int i;
1518
1519        listRepPtr = NewListIntRep(listRepPtr->maxElemCount, NULL);
1520        if (listRepPtr == NULL) {
1521            Tcl_Panic("Not enough memory to allocate list");
1522        }
1523        listRepPtr->canonicalFlag = oldListRepPtr->canonicalFlag;
1524        elemPtrs = &listRepPtr->elements;
1525        for (i=0; i < elemCount; i++) {
1526            elemPtrs[i] = oldElemPtrs[i];
1527            Tcl_IncrRefCount(elemPtrs[i]);
1528        }
1529        listRepPtr->refCount++;
1530        listRepPtr->elemCount = elemCount;
1531        listPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
1532        oldListRepPtr->refCount--;
1533    }
1534
1535    /*
1536     * Add a reference to the new list element.
1537     */
1538
1539    Tcl_IncrRefCount(valuePtr);
1540
1541    /*
1542     * Remove a reference from the old list element.
1543     */
1544
1545    Tcl_DecrRefCount(elemPtrs[index]);
1546
1547    /*
1548     * Stash the new object in the list.
1549     */
1550
1551    elemPtrs[index] = valuePtr;
1552
1553    return TCL_OK;
1554}
1555
1556/*
1557 *----------------------------------------------------------------------
1558 *
1559 * FreeListInternalRep --
1560 *
1561 *      Deallocate the storage associated with a list object's internal
1562 *      representation.
1563 *
1564 * Results:
1565 *      None.
1566 *
1567 * Side effects:
1568 *      Frees listPtr's List* internal representation and sets listPtr's
1569 *      internalRep.twoPtrValue.ptr1 to NULL. Decrements the ref counts of all
1570 *      element objects, which may free them.
1571 *
1572 *----------------------------------------------------------------------
1573 */
1574
1575static void
1576FreeListInternalRep(
1577    Tcl_Obj *listPtr)           /* List object with internal rep to free. */
1578{
1579    register List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
1580    register Tcl_Obj **elemPtrs = &listRepPtr->elements;
1581    register Tcl_Obj *objPtr;
1582    int numElems = listRepPtr->elemCount;
1583    int i;
1584
1585    if (--listRepPtr->refCount <= 0) {
1586        for (i = 0;  i < numElems;  i++) {
1587            objPtr = elemPtrs[i];
1588            Tcl_DecrRefCount(objPtr);
1589        }
1590        ckfree((char *) listRepPtr);
1591    }
1592
1593    listPtr->internalRep.twoPtrValue.ptr1 = NULL;
1594    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
1595}
1596
1597/*
1598 *----------------------------------------------------------------------
1599 *
1600 * DupListInternalRep --
1601 *
1602 *      Initialize the internal representation of a list Tcl_Obj to share the
1603 *      internal representation of an existing list object.
1604 *
1605 * Results:
1606 *      None.
1607 *
1608 * Side effects:
1609 *      The reference count of the List internal rep is incremented.
1610 *
1611 *----------------------------------------------------------------------
1612 */
1613
1614static void
1615DupListInternalRep(
1616    Tcl_Obj *srcPtr,            /* Object with internal rep to copy. */
1617    Tcl_Obj *copyPtr)           /* Object with internal rep to set. */
1618{
1619    List *listRepPtr = (List *) srcPtr->internalRep.twoPtrValue.ptr1;
1620
1621    listRepPtr->refCount++;
1622    copyPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
1623    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
1624    copyPtr->typePtr = &tclListType;
1625}
1626
1627/*
1628 *----------------------------------------------------------------------
1629 *
1630 * SetListFromAny --
1631 *
1632 *      Attempt to generate a list internal form for the Tcl object "objPtr".
1633 *
1634 * Results:
1635 *      The return value is TCL_OK or TCL_ERROR. If an error occurs during
1636 *      conversion, an error message is left in the interpreter's result
1637 *      unless "interp" is NULL.
1638 *
1639 * Side effects:
1640 *      If no error occurs, a list is stored as "objPtr"s internal
1641 *      representation.
1642 *
1643 *----------------------------------------------------------------------
1644 */
1645
1646static int
1647SetListFromAny(
1648    Tcl_Interp *interp,         /* Used for error reporting if not NULL. */
1649    Tcl_Obj *objPtr)            /* The object to convert. */
1650{
1651    char *string, *s;
1652    const char *elemStart, *nextElem;
1653    int lenRemain, length, estCount, elemSize, hasBrace, i, j, result;
1654    const char *limit;          /* Points just after string's last byte. */
1655    register const char *p;
1656    register Tcl_Obj **elemPtrs;
1657    register Tcl_Obj *elemPtr;
1658    List *listRepPtr;
1659
1660    /*
1661     * Get the string representation. Make it up-to-date if necessary.
1662     */
1663
1664    string = TclGetStringFromObj(objPtr, &length);
1665
1666    /*
1667     * Parse the string into separate string objects, and create a List
1668     * structure that points to the element string objects. We use a modified
1669     * version of Tcl_SplitList's implementation to avoid one malloc and a
1670     * string copy for each list element. First, estimate the number of
1671     * elements by counting the number of space characters in the list.
1672     */
1673
1674    limit = string + length;
1675    estCount = 1;
1676    for (p = string;  p < limit;  p++) {
1677        if (isspace(UCHAR(*p))) { /* INTL: ISO space. */
1678            estCount++;
1679        }
1680    }
1681
1682    /*
1683     * Allocate a new List structure with enough room for "estCount" elements.
1684     * Each element is a pointer to a Tcl_Obj with the appropriate string rep.
1685     * The initial "estCount" elements are set using the corresponding "argv"
1686     * strings.
1687     */
1688
1689    listRepPtr = NewListIntRep(estCount, NULL);
1690    if (!listRepPtr) {
1691        Tcl_SetObjResult(interp, Tcl_NewStringObj(
1692                "Not enough memory to allocate the list internal rep", -1));
1693        return TCL_ERROR;
1694    }
1695    elemPtrs = &listRepPtr->elements;
1696
1697    for (p=string, lenRemain=length, i=0;
1698            lenRemain > 0;
1699            p=nextElem, lenRemain=limit-nextElem, i++) {
1700        result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
1701                &elemSize, &hasBrace);
1702        if (result != TCL_OK) {
1703            for (j = 0;  j < i;  j++) {
1704                elemPtr = elemPtrs[j];
1705                Tcl_DecrRefCount(elemPtr);
1706            }
1707            ckfree((char *) listRepPtr);
1708            return result;
1709        }
1710        if (elemStart >= limit) {
1711            break;
1712        }
1713        if (i > estCount) {
1714            Tcl_Panic("SetListFromAny: bad size estimate for list");
1715        }
1716
1717        /*
1718         * Allocate a Tcl object for the element and initialize it from the
1719         * "elemSize" bytes starting at "elemStart".
1720         */
1721
1722        s = ckalloc((unsigned) elemSize + 1);
1723        if (hasBrace) {
1724            memcpy(s, elemStart, (size_t) elemSize);
1725            s[elemSize] = 0;
1726        } else {
1727            elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
1728        }
1729
1730        TclNewObj(elemPtr);
1731        elemPtr->bytes = s;
1732        elemPtr->length = elemSize;
1733        elemPtrs[i] = elemPtr;
1734        Tcl_IncrRefCount(elemPtr);      /* Since list now holds ref to it. */
1735    }
1736
1737    listRepPtr->elemCount = i;
1738
1739    /*
1740     * Free the old internalRep before setting the new one. We do this as late
1741     * as possible to allow the conversion code, in particular
1742     * Tcl_GetStringFromObj, to use that old internalRep.
1743     */
1744
1745    listRepPtr->refCount++;
1746    TclFreeIntRep(objPtr);
1747    objPtr->internalRep.twoPtrValue.ptr1 = (void *) listRepPtr;
1748    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
1749    objPtr->typePtr = &tclListType;
1750    return TCL_OK;
1751}
1752
1753/*
1754 *----------------------------------------------------------------------
1755 *
1756 * UpdateStringOfList --
1757 *
1758 *      Update the string representation for a list object. Note: This
1759 *      function does not invalidate an existing old string rep so storage
1760 *      will be lost if this has not already been done.
1761 *
1762 * Results:
1763 *      None.
1764 *
1765 * Side effects:
1766 *      The object's string is set to a valid string that results from the
1767 *      list-to-string conversion. This string will be empty if the list has
1768 *      no elements. The list internal representation should not be NULL and
1769 *      we assume it is not NULL.
1770 *
1771 *----------------------------------------------------------------------
1772 */
1773
1774static void
1775UpdateStringOfList(
1776    Tcl_Obj *listPtr)           /* List object with string rep to update. */
1777{
1778#   define LOCAL_SIZE 20
1779    int localFlags[LOCAL_SIZE], *flagPtr;
1780    List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
1781    int numElems = listRepPtr->elemCount;
1782    register int i;
1783    char *elem, *dst;
1784    int length;
1785    Tcl_Obj **elemPtrs;
1786
1787    /*
1788     * Convert each element of the list to string form and then convert it to
1789     * proper list element form, adding it to the result buffer.
1790     */
1791
1792    /*
1793     * Pass 1: estimate space, gather flags.
1794     */
1795
1796    if (numElems <= LOCAL_SIZE) {
1797        flagPtr = localFlags;
1798    } else {
1799        flagPtr = (int *) ckalloc((unsigned) numElems * sizeof(int));
1800    }
1801    listPtr->length = 1;
1802    elemPtrs = &listRepPtr->elements;
1803    for (i = 0; i < numElems; i++) {
1804        elem = TclGetStringFromObj(elemPtrs[i], &length);
1805        listPtr->length += Tcl_ScanCountedElement(elem, length, flagPtr+i)+1;
1806
1807        /*
1808         * Check for continued sanity. [Bug 1267380]
1809         */
1810
1811        if (listPtr->length < 1) {
1812            Tcl_Panic("string representation size exceeds sane bounds");
1813        }
1814    }
1815
1816    /*
1817     * Pass 2: copy into string rep buffer.
1818     */
1819
1820    listPtr->bytes = ckalloc((unsigned) listPtr->length);
1821    dst = listPtr->bytes;
1822    for (i = 0; i < numElems; i++) {
1823        elem = TclGetStringFromObj(elemPtrs[i], &length);
1824        dst += Tcl_ConvertCountedElement(elem, length, dst,
1825                flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
1826        *dst = ' ';
1827        dst++;
1828    }
1829    if (flagPtr != localFlags) {
1830        ckfree((char *) flagPtr);
1831    }
1832    if (dst == listPtr->bytes) {
1833        *dst = 0;
1834    } else {
1835        dst--;
1836        *dst = 0;
1837    }
1838    listPtr->length = dst - listPtr->bytes;
1839
1840    /*
1841     * Mark the list as being canonical; although it has a string rep, it is
1842     * one we derived through proper "canonical" quoting and so it's known to
1843     * be free from nasties relating to [concat] and [eval].
1844     */
1845
1846    listRepPtr->canonicalFlag = 1;
1847}
1848
1849/*
1850 * Local Variables:
1851 * mode: c
1852 * c-basic-offset: 4
1853 * fill-column: 78
1854 * End:
1855 */
Note: See TracBrowser for help on using the repository browser.