1 | /*
|
---|
2 | * tclStringObj.c --
|
---|
3 | *
|
---|
4 | * This file contains procedures that implement string operations
|
---|
5 | * on Tcl objects. To do this efficiently (i.e. to allow many
|
---|
6 | * appends to be done to an object without constantly reallocating
|
---|
7 | * the space for the string representation) we overallocate the
|
---|
8 | * space for the string and use the internal representation to keep
|
---|
9 | * track of the extra space. Objects with this internal
|
---|
10 | * representation are called "expandable string objects".
|
---|
11 | *
|
---|
12 | * Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
---|
13 | *
|
---|
14 | * See the file "license.terms" for information on usage and redistribution
|
---|
15 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
---|
16 | *
|
---|
17 | * RCS: @(#) $Id: tclStringObj.c,v 1.1 2008-06-04 13:58:10 demin Exp $
|
---|
18 | */
|
---|
19 |
|
---|
20 | #include "tclInt.h"
|
---|
21 |
|
---|
22 | /*
|
---|
23 | * Prototypes for procedures defined later in this file:
|
---|
24 | */
|
---|
25 |
|
---|
26 | static void ConvertToStringType _ANSI_ARGS_((Tcl_Obj *objPtr));
|
---|
27 | static void DupStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
|
---|
28 | Tcl_Obj *copyPtr));
|
---|
29 | static int SetStringFromAny _ANSI_ARGS_((Tcl_Interp *interp,
|
---|
30 | Tcl_Obj *objPtr));
|
---|
31 | static void UpdateStringOfString _ANSI_ARGS_((Tcl_Obj *objPtr));
|
---|
32 |
|
---|
33 | /*
|
---|
34 | * The structure below defines the string Tcl object type by means of
|
---|
35 | * procedures that can be invoked by generic object code.
|
---|
36 | */
|
---|
37 |
|
---|
38 | Tcl_ObjType tclStringType = {
|
---|
39 | "string", /* name */
|
---|
40 | (Tcl_FreeInternalRepProc *) NULL, /* freeIntRepProc */
|
---|
41 | DupStringInternalRep, /* dupIntRepProc */
|
---|
42 | UpdateStringOfString, /* updateStringProc */
|
---|
43 | SetStringFromAny /* setFromAnyProc */
|
---|
44 | };
|
---|
45 | |
---|
46 |
|
---|
47 | /*
|
---|
48 | *----------------------------------------------------------------------
|
---|
49 | *
|
---|
50 | * Tcl_NewStringObj --
|
---|
51 | *
|
---|
52 | * This procedure creates a new string object and initializes it from
|
---|
53 | * the byte pointer and length arguments.
|
---|
54 | *
|
---|
55 | * Results:
|
---|
56 | * A newly created string object is returned that has ref count zero.
|
---|
57 | *
|
---|
58 | * Side effects:
|
---|
59 | * The new object's internal string representation will be set to a
|
---|
60 | * copy of the length bytes starting at "bytes". If "length" is
|
---|
61 | * negative, use bytes up to the first NULL byte; i.e., assume "bytes"
|
---|
62 | * points to a C-style NULL-terminated string. The object's type is set
|
---|
63 | * to NULL. An extra NULL is added to the end of the new object's byte
|
---|
64 | * array.
|
---|
65 | *
|
---|
66 | *----------------------------------------------------------------------
|
---|
67 | */
|
---|
68 |
|
---|
69 | Tcl_Obj *
|
---|
70 | Tcl_NewStringObj(bytes, length)
|
---|
71 | register char *bytes; /* Points to the first of the length bytes
|
---|
72 | * used to initialize the new object. */
|
---|
73 | register int length; /* The number of bytes to copy from "bytes"
|
---|
74 | * when initializing the new object. If
|
---|
75 | * negative, use bytes up to the first
|
---|
76 | * NULL byte. */
|
---|
77 | {
|
---|
78 | register Tcl_Obj *objPtr;
|
---|
79 |
|
---|
80 | if (length < 0) {
|
---|
81 | length = (bytes? strlen(bytes) : 0);
|
---|
82 | }
|
---|
83 | TclNewObj(objPtr);
|
---|
84 | TclInitStringRep(objPtr, bytes, length);
|
---|
85 | return objPtr;
|
---|
86 | }
|
---|
87 | |
---|
88 |
|
---|
89 | /*
|
---|
90 | *----------------------------------------------------------------------
|
---|
91 | *
|
---|
92 | * Tcl_SetStringObj --
|
---|
93 | *
|
---|
94 | * Modify an object to hold a string that is a copy of the bytes
|
---|
95 | * indicated by the byte pointer and length arguments.
|
---|
96 | *
|
---|
97 | * Results:
|
---|
98 | * None.
|
---|
99 | *
|
---|
100 | * Side effects:
|
---|
101 | * The object's string representation will be set to a copy of
|
---|
102 | * the "length" bytes starting at "bytes". If "length" is negative, use
|
---|
103 | * bytes up to the first NULL byte; i.e., assume "bytes" points to a
|
---|
104 | * C-style NULL-terminated string. The object's old string and internal
|
---|
105 | * representations are freed and the object's type is set NULL.
|
---|
106 | *
|
---|
107 | *----------------------------------------------------------------------
|
---|
108 | */
|
---|
109 |
|
---|
110 | void
|
---|
111 | Tcl_SetStringObj(objPtr, bytes, length)
|
---|
112 | register Tcl_Obj *objPtr; /* Object whose internal rep to init. */
|
---|
113 | char *bytes; /* Points to the first of the length bytes
|
---|
114 | * used to initialize the object. */
|
---|
115 | register int length; /* The number of bytes to copy from "bytes"
|
---|
116 | * when initializing the object. If
|
---|
117 | * negative, use bytes up to the first
|
---|
118 | * NULL byte.*/
|
---|
119 | {
|
---|
120 | register Tcl_ObjType *oldTypePtr = objPtr->typePtr;
|
---|
121 |
|
---|
122 | /*
|
---|
123 | * Free any old string rep, then set the string rep to a copy of
|
---|
124 | * the length bytes starting at "bytes".
|
---|
125 | */
|
---|
126 |
|
---|
127 | if (Tcl_IsShared(objPtr)) {
|
---|
128 | panic("Tcl_SetStringObj called with shared object");
|
---|
129 | }
|
---|
130 |
|
---|
131 | Tcl_InvalidateStringRep(objPtr);
|
---|
132 | if (length < 0) {
|
---|
133 | length = strlen(bytes);
|
---|
134 | }
|
---|
135 | TclInitStringRep(objPtr, bytes, length);
|
---|
136 |
|
---|
137 | /*
|
---|
138 | * Set the type to NULL and free any internal rep for the old type.
|
---|
139 | */
|
---|
140 |
|
---|
141 | if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
|
---|
142 | oldTypePtr->freeIntRepProc(objPtr);
|
---|
143 | }
|
---|
144 | objPtr->typePtr = NULL;
|
---|
145 | }
|
---|
146 | |
---|
147 |
|
---|
148 | /*
|
---|
149 | *----------------------------------------------------------------------
|
---|
150 | *
|
---|
151 | * Tcl_SetObjLength --
|
---|
152 | *
|
---|
153 | * This procedure changes the length of the string representation
|
---|
154 | * of an object.
|
---|
155 | *
|
---|
156 | * Results:
|
---|
157 | * None.
|
---|
158 | *
|
---|
159 | * Side effects:
|
---|
160 | * If the size of objPtr's string representation is greater than
|
---|
161 | * length, then it is reduced to length and a new terminating null
|
---|
162 | * byte is stored in the strength. If the length of the string
|
---|
163 | * representation is greater than length, the storage space is
|
---|
164 | * reallocated to the given length; a null byte is stored at the
|
---|
165 | * end, but other bytes past the end of the original string
|
---|
166 | * representation are undefined. The object's internal
|
---|
167 | * representation is changed to "expendable string".
|
---|
168 | *
|
---|
169 | *----------------------------------------------------------------------
|
---|
170 | */
|
---|
171 |
|
---|
172 | void
|
---|
173 | Tcl_SetObjLength(objPtr, length)
|
---|
174 | register Tcl_Obj *objPtr; /* Pointer to object. This object must
|
---|
175 | * not currently be shared. */
|
---|
176 | register int length; /* Number of bytes desired for string
|
---|
177 | * representation of object, not including
|
---|
178 | * terminating null byte. */
|
---|
179 | {
|
---|
180 | char *new;
|
---|
181 |
|
---|
182 | if (Tcl_IsShared(objPtr)) {
|
---|
183 | panic("Tcl_SetObjLength called with shared object");
|
---|
184 | }
|
---|
185 | if (objPtr->typePtr != &tclStringType) {
|
---|
186 | ConvertToStringType(objPtr);
|
---|
187 | }
|
---|
188 |
|
---|
189 | if ((long)length > objPtr->internalRep.longValue) {
|
---|
190 | /*
|
---|
191 | * Not enough space in current string. Reallocate the string
|
---|
192 | * space and free the old string.
|
---|
193 | */
|
---|
194 |
|
---|
195 | new = (char *) ckalloc((unsigned) (length+1));
|
---|
196 | if (objPtr->bytes != NULL) {
|
---|
197 | memcpy((VOID *) new, (VOID *) objPtr->bytes,
|
---|
198 | (size_t) objPtr->length);
|
---|
199 | Tcl_InvalidateStringRep(objPtr);
|
---|
200 | }
|
---|
201 | objPtr->bytes = new;
|
---|
202 | objPtr->internalRep.longValue = (long) length;
|
---|
203 | }
|
---|
204 | objPtr->length = length;
|
---|
205 | if ((objPtr->bytes != NULL) && (objPtr->bytes != tclEmptyStringRep)) {
|
---|
206 | objPtr->bytes[length] = 0;
|
---|
207 | }
|
---|
208 | }
|
---|
209 | |
---|
210 |
|
---|
211 | /*
|
---|
212 | *----------------------------------------------------------------------
|
---|
213 | *
|
---|
214 | * Tcl_AppendToObj --
|
---|
215 | *
|
---|
216 | * This procedure appends a sequence of bytes to an object.
|
---|
217 | *
|
---|
218 | * Results:
|
---|
219 | * None.
|
---|
220 | *
|
---|
221 | * Side effects:
|
---|
222 | * The bytes at *bytes are appended to the string representation
|
---|
223 | * of objPtr.
|
---|
224 | *
|
---|
225 | *----------------------------------------------------------------------
|
---|
226 | */
|
---|
227 |
|
---|
228 | void
|
---|
229 | Tcl_AppendToObj(objPtr, bytes, length)
|
---|
230 | register Tcl_Obj *objPtr; /* Points to the object to append to. */
|
---|
231 | char *bytes; /* Points to the bytes to append to the
|
---|
232 | * object. */
|
---|
233 | register int length; /* The number of bytes to append from
|
---|
234 | * "bytes". If < 0, then append all bytes
|
---|
235 | * up to NULL byte. */
|
---|
236 | {
|
---|
237 | int newLength, oldLength;
|
---|
238 |
|
---|
239 | if (Tcl_IsShared(objPtr)) {
|
---|
240 | panic("Tcl_AppendToObj called with shared object");
|
---|
241 | }
|
---|
242 | if (objPtr->typePtr != &tclStringType) {
|
---|
243 | ConvertToStringType(objPtr);
|
---|
244 | }
|
---|
245 | if (length < 0) {
|
---|
246 | length = strlen(bytes);
|
---|
247 | }
|
---|
248 | if (length == 0) {
|
---|
249 | return;
|
---|
250 | }
|
---|
251 | oldLength = objPtr->length;
|
---|
252 | newLength = length + oldLength;
|
---|
253 | if ((long)newLength > objPtr->internalRep.longValue) {
|
---|
254 | /*
|
---|
255 | * There isn't currently enough space in the string
|
---|
256 | * representation so allocate additional space. In fact,
|
---|
257 | * overallocate so that there is room for future growth without
|
---|
258 | * having to reallocate again.
|
---|
259 | */
|
---|
260 |
|
---|
261 | Tcl_SetObjLength(objPtr, 2*newLength);
|
---|
262 | }
|
---|
263 | if (length > 0) {
|
---|
264 | memcpy((VOID *) (objPtr->bytes + oldLength), (VOID *) bytes,
|
---|
265 | (size_t) length);
|
---|
266 | objPtr->length = newLength;
|
---|
267 | objPtr->bytes[objPtr->length] = 0;
|
---|
268 | }
|
---|
269 | }
|
---|
270 | |
---|
271 |
|
---|
272 | /*
|
---|
273 | *----------------------------------------------------------------------
|
---|
274 | *
|
---|
275 | * Tcl_AppendStringsToObj --
|
---|
276 | *
|
---|
277 | * This procedure appends one or more null-terminated strings
|
---|
278 | * to an object.
|
---|
279 | *
|
---|
280 | * Results:
|
---|
281 | * None.
|
---|
282 | *
|
---|
283 | * Side effects:
|
---|
284 | * The contents of all the string arguments are appended to the
|
---|
285 | * string representation of objPtr.
|
---|
286 | *
|
---|
287 | *----------------------------------------------------------------------
|
---|
288 | */
|
---|
289 |
|
---|
290 | void
|
---|
291 | Tcl_AppendStringsToObj TCL_VARARGS_DEF(Tcl_Obj *,arg1)
|
---|
292 | {
|
---|
293 | va_list argList;
|
---|
294 | register Tcl_Obj *objPtr;
|
---|
295 | int newLength, oldLength;
|
---|
296 | register char *string, *dst;
|
---|
297 |
|
---|
298 | objPtr = (Tcl_Obj *) TCL_VARARGS_START(Tcl_Obj *,arg1,argList);
|
---|
299 | if (Tcl_IsShared(objPtr)) {
|
---|
300 | panic("Tcl_AppendStringsToObj called with shared object");
|
---|
301 | }
|
---|
302 | if (objPtr->typePtr != &tclStringType) {
|
---|
303 | ConvertToStringType(objPtr);
|
---|
304 | }
|
---|
305 |
|
---|
306 | /*
|
---|
307 | * Figure out how much space is needed for all the strings, and
|
---|
308 | * expand the string representation if it isn't big enough. If no
|
---|
309 | * bytes would be appended, just return.
|
---|
310 | */
|
---|
311 |
|
---|
312 | newLength = oldLength = objPtr->length;
|
---|
313 | while (1) {
|
---|
314 | string = va_arg(argList, char *);
|
---|
315 | if (string == NULL) {
|
---|
316 | break;
|
---|
317 | }
|
---|
318 | newLength += strlen(string);
|
---|
319 | }
|
---|
320 | if (newLength == oldLength) {
|
---|
321 | return;
|
---|
322 | }
|
---|
323 |
|
---|
324 | if ((long)newLength > objPtr->internalRep.longValue) {
|
---|
325 | /*
|
---|
326 | * There isn't currently enough space in the string
|
---|
327 | * representation so allocate additional space. If the current
|
---|
328 | * string representation isn't empty (i.e. it looks like we're
|
---|
329 | * doing a series of appends) then overallocate the space so
|
---|
330 | * that we won't have to do as much reallocation in the future.
|
---|
331 | */
|
---|
332 |
|
---|
333 | Tcl_SetObjLength(objPtr,
|
---|
334 | (objPtr->length == 0) ? newLength : 2*newLength);
|
---|
335 | }
|
---|
336 |
|
---|
337 | /*
|
---|
338 | * Make a second pass through the arguments, appending all the
|
---|
339 | * strings to the object.
|
---|
340 | */
|
---|
341 |
|
---|
342 | TCL_VARARGS_START(Tcl_Obj *,arg1,argList);
|
---|
343 | dst = objPtr->bytes + oldLength;
|
---|
344 | while (1) {
|
---|
345 | string = va_arg(argList, char *);
|
---|
346 | if (string == NULL) {
|
---|
347 | break;
|
---|
348 | }
|
---|
349 | while (*string != 0) {
|
---|
350 | *dst = *string;
|
---|
351 | dst++;
|
---|
352 | string++;
|
---|
353 | }
|
---|
354 | }
|
---|
355 |
|
---|
356 | /*
|
---|
357 | * Add a null byte to terminate the string. However, be careful:
|
---|
358 | * it's possible that the object is totally empty (if it was empty
|
---|
359 | * originally and there was nothing to append). In this case dst is
|
---|
360 | * NULL; just leave everything alone.
|
---|
361 | */
|
---|
362 |
|
---|
363 | if (dst != NULL) {
|
---|
364 | *dst = 0;
|
---|
365 | }
|
---|
366 | objPtr->length = newLength;
|
---|
367 | va_end(argList);
|
---|
368 | }
|
---|
369 | |
---|
370 |
|
---|
371 | /*
|
---|
372 | *----------------------------------------------------------------------
|
---|
373 | *
|
---|
374 | * ConvertToStringType --
|
---|
375 | *
|
---|
376 | * This procedure converts the internal representation of an object
|
---|
377 | * to "expandable string" type.
|
---|
378 | *
|
---|
379 | * Results:
|
---|
380 | * None.
|
---|
381 | *
|
---|
382 | * Side effects:
|
---|
383 | * Any old internal reputation for objPtr is freed and the
|
---|
384 | * internal representation is set to that for an expandable string
|
---|
385 | * (the field internalRep.longValue holds 1 less than the allocated
|
---|
386 | * length of objPtr's string representation).
|
---|
387 | *
|
---|
388 | *----------------------------------------------------------------------
|
---|
389 | */
|
---|
390 |
|
---|
391 | static void
|
---|
392 | ConvertToStringType(objPtr)
|
---|
393 | register Tcl_Obj *objPtr; /* Pointer to object. Must have a
|
---|
394 | * typePtr that isn't &tclStringType. */
|
---|
395 | {
|
---|
396 | if (objPtr->typePtr != NULL) {
|
---|
397 | if (objPtr->bytes == NULL) {
|
---|
398 | objPtr->typePtr->updateStringProc(objPtr);
|
---|
399 | }
|
---|
400 | if (objPtr->typePtr->freeIntRepProc != NULL) {
|
---|
401 | objPtr->typePtr->freeIntRepProc(objPtr);
|
---|
402 | }
|
---|
403 | }
|
---|
404 | objPtr->typePtr = &tclStringType;
|
---|
405 | if (objPtr->bytes != NULL) {
|
---|
406 | objPtr->internalRep.longValue = (long)objPtr->length;
|
---|
407 | } else {
|
---|
408 | objPtr->internalRep.longValue = 0;
|
---|
409 | objPtr->length = 0;
|
---|
410 | }
|
---|
411 | }
|
---|
412 | |
---|
413 |
|
---|
414 | /*
|
---|
415 | *----------------------------------------------------------------------
|
---|
416 | *
|
---|
417 | * DupStringInternalRep --
|
---|
418 | *
|
---|
419 | * Initialize the internal representation of a new Tcl_Obj to a
|
---|
420 | * copy of the internal representation of an existing string object.
|
---|
421 | *
|
---|
422 | * Results:
|
---|
423 | * None.
|
---|
424 | *
|
---|
425 | * Side effects:
|
---|
426 | * copyPtr's internal rep is set to a copy of srcPtr's internal
|
---|
427 | * representation.
|
---|
428 | *
|
---|
429 | *----------------------------------------------------------------------
|
---|
430 | */
|
---|
431 |
|
---|
432 | static void
|
---|
433 | DupStringInternalRep(srcPtr, copyPtr)
|
---|
434 | register Tcl_Obj *srcPtr; /* Object with internal rep to copy. Must
|
---|
435 | * have an internal representation of type
|
---|
436 | * "expandable string". */
|
---|
437 | register Tcl_Obj *copyPtr; /* Object with internal rep to set. Must
|
---|
438 | * not currently have an internal rep.*/
|
---|
439 | {
|
---|
440 | /*
|
---|
441 | * Tricky point: the string value was copied by generic object
|
---|
442 | * management code, so it doesn't contain any extra bytes that
|
---|
443 | * might exist in the source object.
|
---|
444 | */
|
---|
445 |
|
---|
446 | copyPtr->internalRep.longValue = (long)copyPtr->length;
|
---|
447 | copyPtr->typePtr = &tclStringType;
|
---|
448 | }
|
---|
449 | |
---|
450 |
|
---|
451 | /*
|
---|
452 | *----------------------------------------------------------------------
|
---|
453 | *
|
---|
454 | * SetStringFromAny --
|
---|
455 | *
|
---|
456 | * Create an internal representation of type "expandable string"
|
---|
457 | * for an object.
|
---|
458 | *
|
---|
459 | * Results:
|
---|
460 | * This operation always succeeds and returns TCL_OK.
|
---|
461 | *
|
---|
462 | * Side effects:
|
---|
463 | * This procedure does nothing; there is no advantage in converting
|
---|
464 | * the internal representation now, so we just defer it.
|
---|
465 | *
|
---|
466 | *----------------------------------------------------------------------
|
---|
467 | */
|
---|
468 |
|
---|
469 | static int
|
---|
470 | SetStringFromAny(interp, objPtr)
|
---|
471 | Tcl_Interp *interp; /* Used for error reporting if not NULL. */
|
---|
472 | Tcl_Obj *objPtr; /* The object to convert. */
|
---|
473 | {
|
---|
474 | return TCL_OK;
|
---|
475 | }
|
---|
476 | |
---|
477 |
|
---|
478 | /*
|
---|
479 | *----------------------------------------------------------------------
|
---|
480 | *
|
---|
481 | * UpdateStringOfString --
|
---|
482 | *
|
---|
483 | * Update the string representation for an object whose internal
|
---|
484 | * representation is "expandable string".
|
---|
485 | *
|
---|
486 | * Results:
|
---|
487 | * None.
|
---|
488 | *
|
---|
489 | * Side effects:
|
---|
490 | * None.
|
---|
491 | *
|
---|
492 | *----------------------------------------------------------------------
|
---|
493 | */
|
---|
494 |
|
---|
495 | static void
|
---|
496 | UpdateStringOfString(objPtr)
|
---|
497 | Tcl_Obj *objPtr; /* Object with string rep to update. */
|
---|
498 | {
|
---|
499 | /*
|
---|
500 | * The string is almost always valid already, in which case there's
|
---|
501 | * nothing for us to do. The only case we have to worry about is if
|
---|
502 | * the object is totally null. In this case, set the string rep to
|
---|
503 | * an empty string.
|
---|
504 | */
|
---|
505 |
|
---|
506 | if (objPtr->bytes == NULL) {
|
---|
507 | objPtr->bytes = tclEmptyStringRep;
|
---|
508 | objPtr->length = 0;
|
---|
509 | }
|
---|
510 | return;
|
---|
511 | }
|
---|