Fork me on GitHub

source: git/external/tcl/tclStringObj.c@ 1c1c9c2

Last change on this file since 1c1c9c2 was adeddd8, checked in by Pavel Demin <pavel-demin@…>, 6 years ago

remove debug code from Tcl

  • Property mode set to 100644
File size: 13.8 KB
RevLine 
[d7d2da3]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
26static void ConvertToStringType _ANSI_ARGS_((Tcl_Obj *objPtr));
27static void DupStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
28 Tcl_Obj *copyPtr));
29static int SetStringFromAny _ANSI_ARGS_((Tcl_Interp *interp,
30 Tcl_Obj *objPtr));
31static 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
38Tcl_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 --
[adeddd8]51 *
52 * This procedure creates a new string object and initializes it from
[d7d2da3]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
69Tcl_Obj *
70Tcl_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
110void
111Tcl_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
172void
173Tcl_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
228void
229Tcl_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
290void
291Tcl_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
391static void
392ConvertToStringType(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
432static void
433DupStringInternalRep(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
469static int
470SetStringFromAny(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
495static void
496UpdateStringOfString(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}
Note: See TracBrowser for help on using the repository browser.