| [25] | 1 | /* | 
|---|
 | 2 |  * tclStringObj.c -- | 
|---|
 | 3 |  * | 
|---|
 | 4 |  *      This file contains functions that implement string operations on Tcl | 
|---|
 | 5 |  *      objects. Some string operations work with UTF strings and others | 
|---|
 | 6 |  *      require Unicode format. Functions that require knowledge of the width | 
|---|
 | 7 |  *      of each character, such as indexing, operate on Unicode data. | 
|---|
 | 8 |  * | 
|---|
 | 9 |  *      A Unicode string is an internationalized string. Conceptually, a | 
|---|
 | 10 |  *      Unicode string is an array of 16-bit quantities organized as a | 
|---|
 | 11 |  *      sequence of properly formed UTF-8 characters. There is a one-to-one | 
|---|
 | 12 |  *      map between Unicode and UTF characters. Because Unicode characters | 
|---|
 | 13 |  *      have a fixed width, operations such as indexing operate on Unicode | 
|---|
 | 14 |  *      data. The String object is optimized for the case where each UTF char | 
|---|
 | 15 |  *      in a string is only one byte. In this case, we store the value of | 
|---|
 | 16 |  *      numChars, but we don't store the Unicode data (unless Tcl_GetUnicode | 
|---|
 | 17 |  *      is explicitly called). | 
|---|
 | 18 |  * | 
|---|
 | 19 |  *      The String object type stores one or both formats. The default | 
|---|
 | 20 |  *      behavior is to store UTF. Once Unicode is calculated by a function, it | 
|---|
 | 21 |  *      is stored in the internal rep for future access (without an additional | 
|---|
 | 22 |  *      O(n) cost). | 
|---|
 | 23 |  * | 
|---|
 | 24 |  *      To allow many appends to be done to an object without constantly | 
|---|
 | 25 |  *      reallocating the space for the string or Unicode representation, we | 
|---|
 | 26 |  *      allocate double the space for the string or Unicode and use the | 
|---|
 | 27 |  *      internal representation to keep track of how much space is used vs. | 
|---|
 | 28 |  *      allocated. | 
|---|
 | 29 |  * | 
|---|
 | 30 |  * Copyright (c) 1995-1997 Sun Microsystems, Inc. | 
|---|
 | 31 |  * Copyright (c) 1999 by Scriptics Corporation. | 
|---|
 | 32 |  * | 
|---|
 | 33 |  * See the file "license.terms" for information on usage and redistribution of | 
|---|
 | 34 |  * this file, and for a DISCLAIMER OF ALL WARRANTIES. | 
|---|
 | 35 |  * | 
|---|
 | 36 |  * RCS: @(#) $Id: tclStringObj.c,v 1.70 2008/02/28 17:36:49 dgp Exp $ */ | 
|---|
 | 37 |  | 
|---|
 | 38 | #include "tclInt.h" | 
|---|
 | 39 | #include "tommath.h" | 
|---|
 | 40 |  | 
|---|
 | 41 | /* | 
|---|
 | 42 |  * Prototypes for functions defined later in this file: | 
|---|
 | 43 |  */ | 
|---|
 | 44 |  | 
|---|
 | 45 | static void             AppendUnicodeToUnicodeRep(Tcl_Obj *objPtr, | 
|---|
 | 46 |                             const Tcl_UniChar *unicode, int appendNumChars); | 
|---|
 | 47 | static void             AppendUnicodeToUtfRep(Tcl_Obj *objPtr, | 
|---|
 | 48 |                             const Tcl_UniChar *unicode, int numChars); | 
|---|
 | 49 | static void             AppendUtfToUnicodeRep(Tcl_Obj *objPtr, | 
|---|
 | 50 |                             const char *bytes, int numBytes); | 
|---|
 | 51 | static void             AppendUtfToUtfRep(Tcl_Obj *objPtr, | 
|---|
 | 52 |                             const char *bytes, int numBytes); | 
|---|
 | 53 | static void             FillUnicodeRep(Tcl_Obj *objPtr); | 
|---|
 | 54 | static void             AppendPrintfToObjVA(Tcl_Obj *objPtr, | 
|---|
 | 55 |                             const char *format, va_list argList); | 
|---|
 | 56 | static void             FreeStringInternalRep(Tcl_Obj *objPtr); | 
|---|
 | 57 | static void             DupStringInternalRep(Tcl_Obj *objPtr, | 
|---|
 | 58 |                             Tcl_Obj *copyPtr); | 
|---|
 | 59 | static int              SetStringFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); | 
|---|
 | 60 | static void             UpdateStringOfString(Tcl_Obj *objPtr); | 
|---|
 | 61 |  | 
|---|
 | 62 | /* | 
|---|
 | 63 |  * The structure below defines the string Tcl object type by means of | 
|---|
 | 64 |  * functions that can be invoked by generic object code. | 
|---|
 | 65 |  */ | 
|---|
 | 66 |  | 
|---|
 | 67 | Tcl_ObjType tclStringType = { | 
|---|
 | 68 |     "string",                   /* name */ | 
|---|
 | 69 |     FreeStringInternalRep,      /* freeIntRepPro */ | 
|---|
 | 70 |     DupStringInternalRep,       /* dupIntRepProc */ | 
|---|
 | 71 |     UpdateStringOfString,       /* updateStringProc */ | 
|---|
 | 72 |     SetStringFromAny            /* setFromAnyProc */ | 
|---|
 | 73 | }; | 
|---|
 | 74 |  | 
|---|
 | 75 | /* | 
|---|
 | 76 |  * The following structure is the internal rep for a String object. It keeps | 
|---|
 | 77 |  * track of how much memory has been used and how much has been allocated for | 
|---|
 | 78 |  * the Unicode and UTF string to enable growing and shrinking of the UTF and | 
|---|
 | 79 |  * Unicode reps of the String object with fewer mallocs. To optimize string | 
|---|
 | 80 |  * length and indexing operations, this structure also stores the number of | 
|---|
 | 81 |  * characters (same of UTF and Unicode!) once that value has been computed. | 
|---|
 | 82 |  * | 
|---|
 | 83 |  * Under normal configurations, what Tcl calls "Unicode" is actually UTF-16 | 
|---|
 | 84 |  * restricted to the Basic Multilingual Plane (i.e. U+00000 to U+0FFFF). This | 
|---|
 | 85 |  * can be officially modified by altering the definition of Tcl_UniChar in | 
|---|
 | 86 |  * tcl.h, but do not do that unless you are sure what you're doing! | 
|---|
 | 87 |  */ | 
|---|
 | 88 |  | 
|---|
 | 89 | typedef struct String { | 
|---|
 | 90 |     int numChars;               /* The number of chars in the string. -1 means | 
|---|
 | 91 |                                  * this value has not been calculated. >= 0 | 
|---|
 | 92 |                                  * means that there is a valid Unicode rep, or | 
|---|
 | 93 |                                  * that the number of UTF bytes == the number | 
|---|
 | 94 |                                  * of chars. */ | 
|---|
 | 95 |     size_t allocated;           /* The amount of space actually allocated for | 
|---|
 | 96 |                                  * the UTF string (minus 1 byte for the | 
|---|
 | 97 |                                  * termination char). */ | 
|---|
 | 98 |     size_t uallocated;          /* The amount of space actually allocated for | 
|---|
 | 99 |                                  * the Unicode string (minus 2 bytes for the | 
|---|
 | 100 |                                  * termination char). */ | 
|---|
 | 101 |     int hasUnicode;             /* Boolean determining whether the string has | 
|---|
 | 102 |                                  * a Unicode representation. */ | 
|---|
 | 103 |     Tcl_UniChar unicode[2];     /* The array of Unicode chars. The actual size | 
|---|
 | 104 |                                  * of this field depends on the 'uallocated' | 
|---|
 | 105 |                                  * field above. */ | 
|---|
 | 106 | } String; | 
|---|
 | 107 |  | 
|---|
 | 108 | #define STRING_UALLOC(numChars) \ | 
|---|
 | 109 |         (numChars * sizeof(Tcl_UniChar)) | 
|---|
 | 110 | #define STRING_SIZE(ualloc) \ | 
|---|
 | 111 |         ((unsigned) ((ualloc) \ | 
|---|
 | 112 |                  ? sizeof(String) - sizeof(Tcl_UniChar) + (ualloc) \ | 
|---|
 | 113 |                  : sizeof(String))) | 
|---|
 | 114 | #define GET_STRING(objPtr) \ | 
|---|
 | 115 |         ((String *) (objPtr)->internalRep.otherValuePtr) | 
|---|
 | 116 | #define SET_STRING(objPtr, stringPtr) \ | 
|---|
 | 117 |         ((objPtr)->internalRep.otherValuePtr = (void *) (stringPtr)) | 
|---|
 | 118 |  | 
|---|
 | 119 | /* | 
|---|
 | 120 |  * TCL STRING GROWTH ALGORITHM | 
|---|
 | 121 |  * | 
|---|
 | 122 |  * When growing strings (during an append, for example), the following growth | 
|---|
 | 123 |  * algorithm is used: | 
|---|
 | 124 |  * | 
|---|
 | 125 |  *   Attempt to allocate 2 * (originalLength + appendLength) | 
|---|
 | 126 |  *   On failure: | 
|---|
 | 127 |  *      attempt to allocate originalLength + 2*appendLength + | 
|---|
 | 128 |  *                      TCL_GROWTH_MIN_ALLOC | 
|---|
 | 129 |  * | 
|---|
 | 130 |  * This algorithm allows very good performance, as it rapidly increases the | 
|---|
 | 131 |  * memory allocated for a given string, which minimizes the number of | 
|---|
 | 132 |  * reallocations that must be performed. However, using only the doubling | 
|---|
 | 133 |  * algorithm can lead to a significant waste of memory. In particular, it may | 
|---|
 | 134 |  * fail even when there is sufficient memory available to complete the append | 
|---|
 | 135 |  * request (but there is not 2*totalLength memory available). So when the | 
|---|
 | 136 |  * doubling fails (because there is not enough memory available), the | 
|---|
 | 137 |  * algorithm requests a smaller amount of memory, which is still enough to | 
|---|
 | 138 |  * cover the request, but which hopefully will be less than the total | 
|---|
 | 139 |  * available memory. | 
|---|
 | 140 |  * | 
|---|
 | 141 |  * The addition of TCL_GROWTH_MIN_ALLOC allows for efficient handling of very | 
|---|
 | 142 |  * small appends. Without this extra slush factor, a sequence of several small | 
|---|
 | 143 |  * appends would cause several memory allocations. As long as | 
|---|
 | 144 |  * TCL_GROWTH_MIN_ALLOC is a reasonable size, we can avoid that behavior. | 
|---|
 | 145 |  * | 
|---|
 | 146 |  * The growth algorithm can be tuned by adjusting the following parameters: | 
|---|
 | 147 |  * | 
|---|
 | 148 |  * TCL_GROWTH_MIN_ALLOC         Additional space, in bytes, to allocate when | 
|---|
 | 149 |  *                              the double allocation has failed. Default is | 
|---|
 | 150 |  *                              1024 (1 kilobyte). | 
|---|
 | 151 |  */ | 
|---|
 | 152 |  | 
|---|
 | 153 | #ifndef TCL_GROWTH_MIN_ALLOC | 
|---|
 | 154 | #define TCL_GROWTH_MIN_ALLOC    1024 | 
|---|
 | 155 | #endif | 
|---|
 | 156 |  | 
|---|
 | 157 | /* | 
|---|
 | 158 |  *---------------------------------------------------------------------- | 
|---|
 | 159 |  * | 
|---|
 | 160 |  * Tcl_NewStringObj -- | 
|---|
 | 161 |  * | 
|---|
 | 162 |  *      This function is normally called when not debugging: i.e., when | 
|---|
 | 163 |  *      TCL_MEM_DEBUG is not defined. It creates a new string object and | 
|---|
 | 164 |  *      initializes it from the byte pointer and length arguments. | 
|---|
 | 165 |  * | 
|---|
 | 166 |  *      When TCL_MEM_DEBUG is defined, this function just returns the result | 
|---|
 | 167 |  *      of calling the debugging version Tcl_DbNewStringObj. | 
|---|
 | 168 |  * | 
|---|
 | 169 |  * Results: | 
|---|
 | 170 |  *      A newly created string object is returned that has ref count zero. | 
|---|
 | 171 |  * | 
|---|
 | 172 |  * Side effects: | 
|---|
 | 173 |  *      The new object's internal string representation will be set to a copy | 
|---|
 | 174 |  *      of the length bytes starting at "bytes". If "length" is negative, use | 
|---|
 | 175 |  *      bytes up to the first NUL byte; i.e., assume "bytes" points to a | 
|---|
 | 176 |  *      C-style NUL-terminated string. The object's type is set to NULL. An | 
|---|
 | 177 |  *      extra NUL is added to the end of the new object's byte array. | 
|---|
 | 178 |  * | 
|---|
 | 179 |  *---------------------------------------------------------------------- | 
|---|
 | 180 |  */ | 
|---|
 | 181 |  | 
|---|
 | 182 | #ifdef TCL_MEM_DEBUG | 
|---|
 | 183 | #undef Tcl_NewStringObj | 
|---|
 | 184 | Tcl_Obj * | 
|---|
 | 185 | Tcl_NewStringObj( | 
|---|
 | 186 |     const char *bytes,          /* Points to the first of the length bytes | 
|---|
 | 187 |                                  * used to initialize the new object. */ | 
|---|
 | 188 |     int length)                 /* The number of bytes to copy from "bytes" | 
|---|
 | 189 |                                  * when initializing the new object. If | 
|---|
 | 190 |                                  * negative, use bytes up to the first NUL | 
|---|
 | 191 |                                  * byte. */ | 
|---|
 | 192 | { | 
|---|
 | 193 |     return Tcl_DbNewStringObj(bytes, length, "unknown", 0); | 
|---|
 | 194 | } | 
|---|
 | 195 | #else /* if not TCL_MEM_DEBUG */ | 
|---|
 | 196 | Tcl_Obj * | 
|---|
 | 197 | Tcl_NewStringObj( | 
|---|
 | 198 |     const char *bytes,          /* Points to the first of the length bytes | 
|---|
 | 199 |                                  * used to initialize the new object. */ | 
|---|
 | 200 |     int length)                 /* The number of bytes to copy from "bytes" | 
|---|
 | 201 |                                  * when initializing the new object. If | 
|---|
 | 202 |                                  * negative, use bytes up to the first NUL | 
|---|
 | 203 |                                  * byte. */ | 
|---|
 | 204 | { | 
|---|
 | 205 |     register Tcl_Obj *objPtr; | 
|---|
 | 206 |  | 
|---|
 | 207 |     if (length < 0) { | 
|---|
 | 208 |         length = (bytes? strlen(bytes) : 0); | 
|---|
 | 209 |     } | 
|---|
 | 210 |     TclNewStringObj(objPtr, bytes, length); | 
|---|
 | 211 |     return objPtr; | 
|---|
 | 212 | } | 
|---|
 | 213 | #endif /* TCL_MEM_DEBUG */ | 
|---|
 | 214 |  | 
|---|
 | 215 | /* | 
|---|
 | 216 |  *---------------------------------------------------------------------- | 
|---|
 | 217 |  * | 
|---|
 | 218 |  * Tcl_DbNewStringObj -- | 
|---|
 | 219 |  * | 
|---|
 | 220 |  *      This function is normally called when debugging: i.e., when | 
|---|
 | 221 |  *      TCL_MEM_DEBUG is defined. It creates new string objects. It is the | 
|---|
 | 222 |  *      same as the Tcl_NewStringObj function above except that it calls | 
|---|
 | 223 |  *      Tcl_DbCkalloc directly with the file name and line number from its | 
|---|
 | 224 |  *      caller. This simplifies debugging since then the [memory active] | 
|---|
 | 225 |  *      command will report the correct file name and line number when | 
|---|
 | 226 |  *      reporting objects that haven't been freed. | 
|---|
 | 227 |  * | 
|---|
 | 228 |  *      When TCL_MEM_DEBUG is not defined, this function just returns the | 
|---|
 | 229 |  *      result of calling Tcl_NewStringObj. | 
|---|
 | 230 |  * | 
|---|
 | 231 |  * Results: | 
|---|
 | 232 |  *      A newly created string object is returned that has ref count zero. | 
|---|
 | 233 |  * | 
|---|
 | 234 |  * Side effects: | 
|---|
 | 235 |  *      The new object's internal string representation will be set to a copy | 
|---|
 | 236 |  *      of the length bytes starting at "bytes". If "length" is negative, use | 
|---|
 | 237 |  *      bytes up to the first NUL byte; i.e., assume "bytes" points to a | 
|---|
 | 238 |  *      C-style NUL-terminated string. The object's type is set to NULL. An | 
|---|
 | 239 |  *      extra NUL is added to the end of the new object's byte array. | 
|---|
 | 240 |  * | 
|---|
 | 241 |  *---------------------------------------------------------------------- | 
|---|
 | 242 |  */ | 
|---|
 | 243 |  | 
|---|
 | 244 | #ifdef TCL_MEM_DEBUG | 
|---|
 | 245 | Tcl_Obj * | 
|---|
 | 246 | Tcl_DbNewStringObj( | 
|---|
 | 247 |     const char *bytes,          /* Points to the first of the length bytes | 
|---|
 | 248 |                                  * used to initialize the new object. */ | 
|---|
 | 249 |     int length,                 /* The number of bytes to copy from "bytes" | 
|---|
 | 250 |                                  * when initializing the new object. If | 
|---|
 | 251 |                                  * negative, use bytes up to the first NUL | 
|---|
 | 252 |                                  * byte. */ | 
|---|
 | 253 |     const char *file,           /* The name of the source file calling this | 
|---|
 | 254 |                                  * function; used for debugging. */ | 
|---|
 | 255 |     int line)                   /* Line number in the source file; used for | 
|---|
 | 256 |                                  * debugging. */ | 
|---|
 | 257 | { | 
|---|
 | 258 |     register Tcl_Obj *objPtr; | 
|---|
 | 259 |  | 
|---|
 | 260 |     if (length < 0) { | 
|---|
 | 261 |         length = (bytes? strlen(bytes) : 0); | 
|---|
 | 262 |     } | 
|---|
 | 263 |     TclDbNewObj(objPtr, file, line); | 
|---|
 | 264 |     TclInitStringRep(objPtr, bytes, length); | 
|---|
 | 265 |     return objPtr; | 
|---|
 | 266 | } | 
|---|
 | 267 | #else /* if not TCL_MEM_DEBUG */ | 
|---|
 | 268 | Tcl_Obj * | 
|---|
 | 269 | Tcl_DbNewStringObj( | 
|---|
 | 270 |     const char *bytes,          /* Points to the first of the length bytes | 
|---|
 | 271 |                                  * used to initialize the new object. */ | 
|---|
 | 272 |     register int length,        /* The number of bytes to copy from "bytes" | 
|---|
 | 273 |                                  * when initializing the new object. If | 
|---|
 | 274 |                                  * negative, use bytes up to the first NUL | 
|---|
 | 275 |                                  * byte. */ | 
|---|
 | 276 |     const char *file,           /* The name of the source file calling this | 
|---|
 | 277 |                                  * function; used for debugging. */ | 
|---|
 | 278 |     int line)                   /* Line number in the source file; used for | 
|---|
 | 279 |                                  * debugging. */ | 
|---|
 | 280 | { | 
|---|
 | 281 |     return Tcl_NewStringObj(bytes, length); | 
|---|
 | 282 | } | 
|---|
 | 283 | #endif /* TCL_MEM_DEBUG */ | 
|---|
 | 284 |  | 
|---|
 | 285 | /* | 
|---|
 | 286 |  *--------------------------------------------------------------------------- | 
|---|
 | 287 |  * | 
|---|
 | 288 |  * Tcl_NewUnicodeObj -- | 
|---|
 | 289 |  * | 
|---|
 | 290 |  *      This function is creates a new String object and initializes it from | 
|---|
 | 291 |  *      the given Unicode String. If the Utf String is the same size as the | 
|---|
 | 292 |  *      Unicode string, don't duplicate the data. | 
|---|
 | 293 |  * | 
|---|
 | 294 |  * Results: | 
|---|
 | 295 |  *      The newly created object is returned. This object will have no initial | 
|---|
 | 296 |  *      string representation. The returned object has a ref count of 0. | 
|---|
 | 297 |  * | 
|---|
 | 298 |  * Side effects: | 
|---|
 | 299 |  *      Memory allocated for new object and copy of Unicode argument. | 
|---|
 | 300 |  * | 
|---|
 | 301 |  *--------------------------------------------------------------------------- | 
|---|
 | 302 |  */ | 
|---|
 | 303 |  | 
|---|
 | 304 | Tcl_Obj * | 
|---|
 | 305 | Tcl_NewUnicodeObj( | 
|---|
 | 306 |     const Tcl_UniChar *unicode, /* The unicode string used to initialize the | 
|---|
 | 307 |                                  * new object. */ | 
|---|
 | 308 |     int numChars)               /* Number of characters in the unicode | 
|---|
 | 309 |                                  * string. */ | 
|---|
 | 310 | { | 
|---|
 | 311 |     Tcl_Obj *objPtr; | 
|---|
 | 312 |     String *stringPtr; | 
|---|
 | 313 |     size_t uallocated; | 
|---|
 | 314 |  | 
|---|
 | 315 |     if (numChars < 0) { | 
|---|
 | 316 |         numChars = 0; | 
|---|
 | 317 |         if (unicode) { | 
|---|
 | 318 |             while (unicode[numChars] != 0) { | 
|---|
 | 319 |                 numChars++; | 
|---|
 | 320 |             } | 
|---|
 | 321 |         } | 
|---|
 | 322 |     } | 
|---|
 | 323 |     uallocated = STRING_UALLOC(numChars); | 
|---|
 | 324 |  | 
|---|
 | 325 |     /* | 
|---|
 | 326 |      * Create a new obj with an invalid string rep. | 
|---|
 | 327 |      */ | 
|---|
 | 328 |  | 
|---|
 | 329 |     TclNewObj(objPtr); | 
|---|
 | 330 |     Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 331 |     objPtr->typePtr = &tclStringType; | 
|---|
 | 332 |  | 
|---|
 | 333 |     stringPtr = (String *) ckalloc(STRING_SIZE(uallocated)); | 
|---|
 | 334 |     stringPtr->numChars = numChars; | 
|---|
 | 335 |     stringPtr->uallocated = uallocated; | 
|---|
 | 336 |     stringPtr->hasUnicode = (numChars > 0); | 
|---|
 | 337 |     stringPtr->allocated = 0; | 
|---|
 | 338 |     memcpy(stringPtr->unicode, unicode, uallocated); | 
|---|
 | 339 |     stringPtr->unicode[numChars] = 0; | 
|---|
 | 340 |     SET_STRING(objPtr, stringPtr); | 
|---|
 | 341 |     return objPtr; | 
|---|
 | 342 | } | 
|---|
 | 343 |  | 
|---|
 | 344 | /* | 
|---|
 | 345 |  *---------------------------------------------------------------------- | 
|---|
 | 346 |  * | 
|---|
 | 347 |  * Tcl_GetCharLength -- | 
|---|
 | 348 |  * | 
|---|
 | 349 |  *      Get the length of the Unicode string from the Tcl object. | 
|---|
 | 350 |  * | 
|---|
 | 351 |  * Results: | 
|---|
 | 352 |  *      Pointer to unicode string representing the unicode object. | 
|---|
 | 353 |  * | 
|---|
 | 354 |  * Side effects: | 
|---|
 | 355 |  *      Frees old internal rep. Allocates memory for new "String" internal | 
|---|
 | 356 |  *      rep. | 
|---|
 | 357 |  * | 
|---|
 | 358 |  *---------------------------------------------------------------------- | 
|---|
 | 359 |  */ | 
|---|
 | 360 |  | 
|---|
 | 361 | int | 
|---|
 | 362 | Tcl_GetCharLength( | 
|---|
 | 363 |     Tcl_Obj *objPtr)            /* The String object to get the num chars | 
|---|
 | 364 |                                  * of. */ | 
|---|
 | 365 | { | 
|---|
 | 366 |     String *stringPtr; | 
|---|
 | 367 |  | 
|---|
 | 368 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 369 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 370 |  | 
|---|
 | 371 |     /* | 
|---|
 | 372 |      * If numChars is unknown, then calculate the number of characaters while | 
|---|
 | 373 |      * populating the Unicode string. | 
|---|
 | 374 |      */ | 
|---|
 | 375 |  | 
|---|
 | 376 |     if (stringPtr->numChars == -1) { | 
|---|
 | 377 |         register int i = objPtr->length; | 
|---|
 | 378 |         register unsigned char *str = (unsigned char *) objPtr->bytes; | 
|---|
 | 379 |  | 
|---|
 | 380 |         /* | 
|---|
 | 381 |          * This is a speed sensitive function, so run specially over the | 
|---|
 | 382 |          * string to count continuous ascii characters before resorting to the | 
|---|
 | 383 |          * Tcl_NumUtfChars call. This is a long form of: | 
|---|
 | 384 |          stringPtr->numChars = Tcl_NumUtfChars(objPtr->bytes,objPtr->length); | 
|---|
 | 385 |          * | 
|---|
 | 386 |          * TODO: Consider macro-izing this. | 
|---|
 | 387 |          */ | 
|---|
 | 388 |  | 
|---|
 | 389 |         while (i && (*str < 0xC0)) { | 
|---|
 | 390 |             i--; | 
|---|
 | 391 |             str++; | 
|---|
 | 392 |         } | 
|---|
 | 393 |         stringPtr->numChars = objPtr->length - i; | 
|---|
 | 394 |         if (i) { | 
|---|
 | 395 |             stringPtr->numChars += Tcl_NumUtfChars(objPtr->bytes | 
|---|
 | 396 |                     + (objPtr->length - i), i); | 
|---|
 | 397 |         } | 
|---|
 | 398 |  | 
|---|
 | 399 |         if (stringPtr->numChars == objPtr->length) { | 
|---|
 | 400 |             /* | 
|---|
 | 401 |              * Since we've just calculated the number of chars, and all UTF | 
|---|
 | 402 |              * chars are 1-byte long, we don't need to store the unicode | 
|---|
 | 403 |              * string. | 
|---|
 | 404 |              */ | 
|---|
 | 405 |  | 
|---|
 | 406 |             stringPtr->hasUnicode = 0; | 
|---|
 | 407 |         } else { | 
|---|
 | 408 |             /* | 
|---|
 | 409 |              * Since we've just calucalated the number of chars, and not all | 
|---|
 | 410 |              * UTF chars are 1-byte long, go ahead and populate the unicode | 
|---|
 | 411 |              * string. | 
|---|
 | 412 |              */ | 
|---|
 | 413 |  | 
|---|
 | 414 |             FillUnicodeRep(objPtr); | 
|---|
 | 415 |  | 
|---|
 | 416 |             /* | 
|---|
 | 417 |              * We need to fetch the pointer again because we have just | 
|---|
 | 418 |              * reallocated the structure to make room for the Unicode data. | 
|---|
 | 419 |              */ | 
|---|
 | 420 |  | 
|---|
 | 421 |             stringPtr = GET_STRING(objPtr); | 
|---|
 | 422 |         } | 
|---|
 | 423 |     } | 
|---|
 | 424 |     return stringPtr->numChars; | 
|---|
 | 425 | } | 
|---|
 | 426 |  | 
|---|
 | 427 | /* | 
|---|
 | 428 |  *---------------------------------------------------------------------- | 
|---|
 | 429 |  * | 
|---|
 | 430 |  * Tcl_GetUniChar -- | 
|---|
 | 431 |  * | 
|---|
 | 432 |  *      Get the index'th Unicode character from the String object. The index | 
|---|
 | 433 |  *      is assumed to be in the appropriate range. | 
|---|
 | 434 |  * | 
|---|
 | 435 |  * Results: | 
|---|
 | 436 |  *      Returns the index'th Unicode character in the Object. | 
|---|
 | 437 |  * | 
|---|
 | 438 |  * Side effects: | 
|---|
 | 439 |  *      Fills unichar with the index'th Unicode character. | 
|---|
 | 440 |  * | 
|---|
 | 441 |  *---------------------------------------------------------------------- | 
|---|
 | 442 |  */ | 
|---|
 | 443 |  | 
|---|
 | 444 | Tcl_UniChar | 
|---|
 | 445 | Tcl_GetUniChar( | 
|---|
 | 446 |     Tcl_Obj *objPtr,            /* The object to get the Unicode charater | 
|---|
 | 447 |                                  * from. */ | 
|---|
 | 448 |     int index)                  /* Get the index'th Unicode character. */ | 
|---|
 | 449 | { | 
|---|
 | 450 |     Tcl_UniChar unichar; | 
|---|
 | 451 |     String *stringPtr; | 
|---|
 | 452 |  | 
|---|
 | 453 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 454 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 455 |  | 
|---|
 | 456 |     if (stringPtr->numChars == -1) { | 
|---|
 | 457 |         /* | 
|---|
 | 458 |          * We haven't yet calculated the length, so we don't have the Unicode | 
|---|
 | 459 |          * str. We need to know the number of chars before we can do indexing. | 
|---|
 | 460 |          */ | 
|---|
 | 461 |  | 
|---|
 | 462 |         Tcl_GetCharLength(objPtr); | 
|---|
 | 463 |  | 
|---|
 | 464 |         /* | 
|---|
 | 465 |          * We need to fetch the pointer again because we may have just | 
|---|
 | 466 |          * reallocated the structure. | 
|---|
 | 467 |          */ | 
|---|
 | 468 |  | 
|---|
 | 469 |         stringPtr = GET_STRING(objPtr); | 
|---|
 | 470 |     } | 
|---|
 | 471 |     if (stringPtr->hasUnicode == 0) { | 
|---|
 | 472 |         /* | 
|---|
 | 473 |          * All of the characters in the Utf string are 1 byte chars, so we | 
|---|
 | 474 |          * don't store the unicode char. We get the Utf string and convert the | 
|---|
 | 475 |          * index'th byte to a Unicode character. | 
|---|
 | 476 |          */ | 
|---|
 | 477 |  | 
|---|
 | 478 |         unichar = (Tcl_UniChar) objPtr->bytes[index]; | 
|---|
 | 479 |     } else { | 
|---|
 | 480 |         unichar = stringPtr->unicode[index]; | 
|---|
 | 481 |     } | 
|---|
 | 482 |     return unichar; | 
|---|
 | 483 | } | 
|---|
 | 484 |  | 
|---|
 | 485 | /* | 
|---|
 | 486 |  *---------------------------------------------------------------------- | 
|---|
 | 487 |  * | 
|---|
 | 488 |  * Tcl_GetUnicode -- | 
|---|
 | 489 |  * | 
|---|
 | 490 |  *      Get the Unicode form of the String object. If the object is not | 
|---|
 | 491 |  *      already a String object, it will be converted to one. If the String | 
|---|
 | 492 |  *      object does not have a Unicode rep, then one is create from the UTF | 
|---|
 | 493 |  *      string format. | 
|---|
 | 494 |  * | 
|---|
 | 495 |  * Results: | 
|---|
 | 496 |  *      Returns a pointer to the object's internal Unicode string. | 
|---|
 | 497 |  * | 
|---|
 | 498 |  * Side effects: | 
|---|
 | 499 |  *      Converts the object to have the String internal rep. | 
|---|
 | 500 |  * | 
|---|
 | 501 |  *---------------------------------------------------------------------- | 
|---|
 | 502 |  */ | 
|---|
 | 503 |  | 
|---|
 | 504 | Tcl_UniChar * | 
|---|
 | 505 | Tcl_GetUnicode( | 
|---|
 | 506 |     Tcl_Obj *objPtr)            /* The object to find the unicode string | 
|---|
 | 507 |                                  * for. */ | 
|---|
 | 508 | { | 
|---|
 | 509 |     String *stringPtr; | 
|---|
 | 510 |  | 
|---|
 | 511 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 512 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 513 |  | 
|---|
 | 514 |     if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { | 
|---|
 | 515 |         /* | 
|---|
 | 516 |          * We haven't yet calculated the length, or all of the characters in | 
|---|
 | 517 |          * the Utf string are 1 byte chars (so we didn't store the unicode | 
|---|
 | 518 |          * str). Since this function must return a unicode string, and one has | 
|---|
 | 519 |          * not yet been stored, force the Unicode to be calculated and stored | 
|---|
 | 520 |          * now. | 
|---|
 | 521 |          */ | 
|---|
 | 522 |  | 
|---|
 | 523 |         FillUnicodeRep(objPtr); | 
|---|
 | 524 |  | 
|---|
 | 525 |         /* | 
|---|
 | 526 |          * We need to fetch the pointer again because we have just reallocated | 
|---|
 | 527 |          * the structure to make room for the Unicode data. | 
|---|
 | 528 |          */ | 
|---|
 | 529 |  | 
|---|
 | 530 |         stringPtr = GET_STRING(objPtr); | 
|---|
 | 531 |     } | 
|---|
 | 532 |     return stringPtr->unicode; | 
|---|
 | 533 | } | 
|---|
 | 534 |  | 
|---|
 | 535 | /* | 
|---|
 | 536 |  *---------------------------------------------------------------------- | 
|---|
 | 537 |  * | 
|---|
 | 538 |  * Tcl_GetUnicodeFromObj -- | 
|---|
 | 539 |  * | 
|---|
 | 540 |  *      Get the Unicode form of the String object with length. If the object | 
|---|
 | 541 |  *      is not already a String object, it will be converted to one. If the | 
|---|
 | 542 |  *      String object does not have a Unicode rep, then one is create from the | 
|---|
 | 543 |  *      UTF string format. | 
|---|
 | 544 |  * | 
|---|
 | 545 |  * Results: | 
|---|
 | 546 |  *      Returns a pointer to the object's internal Unicode string. | 
|---|
 | 547 |  * | 
|---|
 | 548 |  * Side effects: | 
|---|
 | 549 |  *      Converts the object to have the String internal rep. | 
|---|
 | 550 |  * | 
|---|
 | 551 |  *---------------------------------------------------------------------- | 
|---|
 | 552 |  */ | 
|---|
 | 553 |  | 
|---|
 | 554 | Tcl_UniChar * | 
|---|
 | 555 | Tcl_GetUnicodeFromObj( | 
|---|
 | 556 |     Tcl_Obj *objPtr,            /* The object to find the unicode string | 
|---|
 | 557 |                                  * for. */ | 
|---|
 | 558 |     int *lengthPtr)             /* If non-NULL, the location where the string | 
|---|
 | 559 |                                  * rep's unichar length should be stored. If | 
|---|
 | 560 |                                  * NULL, no length is stored. */ | 
|---|
 | 561 | { | 
|---|
 | 562 |     String *stringPtr; | 
|---|
 | 563 |  | 
|---|
 | 564 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 565 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 566 |  | 
|---|
 | 567 |     if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { | 
|---|
 | 568 |         /* | 
|---|
 | 569 |          * We haven't yet calculated the length, or all of the characters in | 
|---|
 | 570 |          * the Utf string are 1 byte chars (so we didn't store the unicode | 
|---|
 | 571 |          * str). Since this function must return a unicode string, and one has | 
|---|
 | 572 |          * not yet been stored, force the Unicode to be calculated and stored | 
|---|
 | 573 |          * now. | 
|---|
 | 574 |          */ | 
|---|
 | 575 |  | 
|---|
 | 576 |         FillUnicodeRep(objPtr); | 
|---|
 | 577 |  | 
|---|
 | 578 |         /* | 
|---|
 | 579 |          * We need to fetch the pointer again because we have just reallocated | 
|---|
 | 580 |          * the structure to make room for the Unicode data. | 
|---|
 | 581 |          */ | 
|---|
 | 582 |  | 
|---|
 | 583 |         stringPtr = GET_STRING(objPtr); | 
|---|
 | 584 |     } | 
|---|
 | 585 |  | 
|---|
 | 586 |     if (lengthPtr != NULL) { | 
|---|
 | 587 |         *lengthPtr = stringPtr->numChars; | 
|---|
 | 588 |     } | 
|---|
 | 589 |     return stringPtr->unicode; | 
|---|
 | 590 | } | 
|---|
 | 591 |  | 
|---|
 | 592 | /* | 
|---|
 | 593 |  *---------------------------------------------------------------------- | 
|---|
 | 594 |  * | 
|---|
 | 595 |  * Tcl_GetRange -- | 
|---|
 | 596 |  * | 
|---|
 | 597 |  *      Create a Tcl Object that contains the chars between first and last of | 
|---|
 | 598 |  *      the object indicated by "objPtr". If the object is not already a | 
|---|
 | 599 |  *      String object, convert it to one. The first and last indices are | 
|---|
 | 600 |  *      assumed to be in the appropriate range. | 
|---|
 | 601 |  * | 
|---|
 | 602 |  * Results: | 
|---|
 | 603 |  *      Returns a new Tcl Object of the String type. | 
|---|
 | 604 |  * | 
|---|
 | 605 |  * Side effects: | 
|---|
 | 606 |  *      Changes the internal rep of "objPtr" to the String type. | 
|---|
 | 607 |  * | 
|---|
 | 608 |  *---------------------------------------------------------------------- | 
|---|
 | 609 |  */ | 
|---|
 | 610 |  | 
|---|
 | 611 | Tcl_Obj * | 
|---|
 | 612 | Tcl_GetRange( | 
|---|
 | 613 |     Tcl_Obj *objPtr,            /* The Tcl object to find the range of. */ | 
|---|
 | 614 |     int first,                  /* First index of the range. */ | 
|---|
 | 615 |     int last)                   /* Last index of the range. */ | 
|---|
 | 616 | { | 
|---|
 | 617 |     Tcl_Obj *newObjPtr;         /* The Tcl object to find the range of. */ | 
|---|
 | 618 |     String *stringPtr; | 
|---|
 | 619 |  | 
|---|
 | 620 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 621 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 622 |  | 
|---|
 | 623 |     if (stringPtr->numChars == -1) { | 
|---|
 | 624 |         /* | 
|---|
 | 625 |          * We haven't yet calculated the length, so we don't have the Unicode | 
|---|
 | 626 |          * str. We need to know the number of chars before we can do indexing. | 
|---|
 | 627 |          */ | 
|---|
 | 628 |  | 
|---|
 | 629 |         Tcl_GetCharLength(objPtr); | 
|---|
 | 630 |  | 
|---|
 | 631 |         /* | 
|---|
 | 632 |          * We need to fetch the pointer again because we may have just | 
|---|
 | 633 |          * reallocated the structure. | 
|---|
 | 634 |          */ | 
|---|
 | 635 |  | 
|---|
 | 636 |         stringPtr = GET_STRING(objPtr); | 
|---|
 | 637 |     } | 
|---|
 | 638 |  | 
|---|
 | 639 |     if (objPtr->bytes && (stringPtr->numChars == objPtr->length)) { | 
|---|
 | 640 |         char *str = TclGetString(objPtr); | 
|---|
 | 641 |  | 
|---|
 | 642 |         /* | 
|---|
 | 643 |          * All of the characters in the Utf string are 1 byte chars, so we | 
|---|
 | 644 |          * don't store the unicode char. Create a new string object containing | 
|---|
 | 645 |          * the specified range of chars. | 
|---|
 | 646 |          */ | 
|---|
 | 647 |  | 
|---|
 | 648 |         newObjPtr = Tcl_NewStringObj(&str[first], last-first+1); | 
|---|
 | 649 |  | 
|---|
 | 650 |         /* | 
|---|
 | 651 |          * Since we know the new string only has 1-byte chars, we can set it's | 
|---|
 | 652 |          * numChars field. | 
|---|
 | 653 |          */ | 
|---|
 | 654 |  | 
|---|
 | 655 |         SetStringFromAny(NULL, newObjPtr); | 
|---|
 | 656 |         stringPtr = GET_STRING(newObjPtr); | 
|---|
 | 657 |         stringPtr->numChars = last-first+1; | 
|---|
 | 658 |     } else { | 
|---|
 | 659 |         newObjPtr = Tcl_NewUnicodeObj(stringPtr->unicode + first, | 
|---|
 | 660 |                 last-first+1); | 
|---|
 | 661 |     } | 
|---|
 | 662 |     return newObjPtr; | 
|---|
 | 663 | } | 
|---|
 | 664 |  | 
|---|
 | 665 | /* | 
|---|
 | 666 |  *---------------------------------------------------------------------- | 
|---|
 | 667 |  * | 
|---|
 | 668 |  * Tcl_SetStringObj -- | 
|---|
 | 669 |  * | 
|---|
 | 670 |  *      Modify an object to hold a string that is a copy of the bytes | 
|---|
 | 671 |  *      indicated by the byte pointer and length arguments. | 
|---|
 | 672 |  * | 
|---|
 | 673 |  * Results: | 
|---|
 | 674 |  *      None. | 
|---|
 | 675 |  * | 
|---|
 | 676 |  * Side effects: | 
|---|
 | 677 |  *      The object's string representation will be set to a copy of the | 
|---|
 | 678 |  *      "length" bytes starting at "bytes". If "length" is negative, use bytes | 
|---|
 | 679 |  *      up to the first NUL byte; i.e., assume "bytes" points to a C-style | 
|---|
 | 680 |  *      NUL-terminated string. The object's old string and internal | 
|---|
 | 681 |  *      representations are freed and the object's type is set NULL. | 
|---|
 | 682 |  * | 
|---|
 | 683 |  *---------------------------------------------------------------------- | 
|---|
 | 684 |  */ | 
|---|
 | 685 |  | 
|---|
 | 686 | void | 
|---|
 | 687 | Tcl_SetStringObj( | 
|---|
 | 688 |     register Tcl_Obj *objPtr,   /* Object whose internal rep to init. */ | 
|---|
 | 689 |     const char *bytes,          /* Points to the first of the length bytes | 
|---|
 | 690 |                                  * used to initialize the object. */ | 
|---|
 | 691 |     register int length)        /* The number of bytes to copy from "bytes" | 
|---|
 | 692 |                                  * when initializing the object. If negative, | 
|---|
 | 693 |                                  * use bytes up to the first NUL byte.*/ | 
|---|
 | 694 | { | 
|---|
 | 695 |     /* | 
|---|
 | 696 |      * Free any old string rep, then set the string rep to a copy of the | 
|---|
 | 697 |      * length bytes starting at "bytes". | 
|---|
 | 698 |      */ | 
|---|
 | 699 |  | 
|---|
 | 700 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 701 |         Tcl_Panic("%s called with shared object", "Tcl_SetStringObj"); | 
|---|
 | 702 |     } | 
|---|
 | 703 |  | 
|---|
 | 704 |     /* | 
|---|
 | 705 |      * Set the type to NULL and free any internal rep for the old type. | 
|---|
 | 706 |      */ | 
|---|
 | 707 |  | 
|---|
 | 708 |     TclFreeIntRep(objPtr); | 
|---|
 | 709 |     objPtr->typePtr = NULL; | 
|---|
 | 710 |  | 
|---|
 | 711 |     Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 712 |     if (length < 0) { | 
|---|
 | 713 |         length = (bytes? strlen(bytes) : 0); | 
|---|
 | 714 |     } | 
|---|
 | 715 |     TclInitStringRep(objPtr, bytes, length); | 
|---|
 | 716 | } | 
|---|
 | 717 |  | 
|---|
 | 718 | /* | 
|---|
 | 719 |  *---------------------------------------------------------------------- | 
|---|
 | 720 |  * | 
|---|
 | 721 |  * Tcl_SetObjLength -- | 
|---|
 | 722 |  * | 
|---|
 | 723 |  *      This function changes the length of the string representation of an | 
|---|
 | 724 |  *      object. | 
|---|
 | 725 |  * | 
|---|
 | 726 |  * Results: | 
|---|
 | 727 |  *      None. | 
|---|
 | 728 |  * | 
|---|
 | 729 |  * Side effects: | 
|---|
 | 730 |  *      If the size of objPtr's string representation is greater than length, | 
|---|
 | 731 |  *      then it is reduced to length and a new terminating null byte is stored | 
|---|
 | 732 |  *      in the strength. If the length of the string representation is greater | 
|---|
 | 733 |  *      than length, the storage space is reallocated to the given length; a | 
|---|
 | 734 |  *      null byte is stored at the end, but other bytes past the end of the | 
|---|
 | 735 |  *      original string representation are undefined. The object's internal | 
|---|
 | 736 |  *      representation is changed to "expendable string". | 
|---|
 | 737 |  * | 
|---|
 | 738 |  *---------------------------------------------------------------------- | 
|---|
 | 739 |  */ | 
|---|
 | 740 |  | 
|---|
 | 741 | void | 
|---|
 | 742 | Tcl_SetObjLength( | 
|---|
 | 743 |     register Tcl_Obj *objPtr,   /* Pointer to object. This object must not | 
|---|
 | 744 |                                  * currently be shared. */ | 
|---|
 | 745 |     register int length)        /* Number of bytes desired for string | 
|---|
 | 746 |                                  * representation of object, not including | 
|---|
 | 747 |                                  * terminating null byte. */ | 
|---|
 | 748 | { | 
|---|
 | 749 |     String *stringPtr; | 
|---|
 | 750 |  | 
|---|
 | 751 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 752 |         Tcl_Panic("%s called with shared object", "Tcl_SetObjLength"); | 
|---|
 | 753 |     } | 
|---|
 | 754 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 755 |  | 
|---|
 | 756 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 757 |  | 
|---|
 | 758 |     /* | 
|---|
 | 759 |      * Check that we're not extending a pure unicode string. | 
|---|
 | 760 |      */ | 
|---|
 | 761 |  | 
|---|
 | 762 |     if (length > (int) stringPtr->allocated && | 
|---|
 | 763 |             (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) { | 
|---|
 | 764 |         /* | 
|---|
 | 765 |          * Not enough space in current string. Reallocate the string space and | 
|---|
 | 766 |          * free the old string. | 
|---|
 | 767 |          */ | 
|---|
 | 768 |  | 
|---|
 | 769 |         if (objPtr->bytes != tclEmptyStringRep) { | 
|---|
 | 770 |             objPtr->bytes = ckrealloc((char *) objPtr->bytes, | 
|---|
 | 771 |                     (unsigned) (length + 1)); | 
|---|
 | 772 |         } else { | 
|---|
 | 773 |             char *newBytes = ckalloc((unsigned) (length+1)); | 
|---|
 | 774 |  | 
|---|
 | 775 |             if (objPtr->bytes != NULL && objPtr->length != 0) { | 
|---|
 | 776 |                 memcpy(newBytes, objPtr->bytes, (size_t) objPtr->length); | 
|---|
 | 777 |                 Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 778 |             } | 
|---|
 | 779 |             objPtr->bytes = newBytes; | 
|---|
 | 780 |         } | 
|---|
 | 781 |         stringPtr->allocated = length; | 
|---|
 | 782 |  | 
|---|
 | 783 |         /* | 
|---|
 | 784 |          * Invalidate the unicode data. | 
|---|
 | 785 |          */ | 
|---|
 | 786 |  | 
|---|
 | 787 |         stringPtr->hasUnicode = 0; | 
|---|
 | 788 |     } | 
|---|
 | 789 |  | 
|---|
 | 790 |     if (objPtr->bytes != NULL) { | 
|---|
 | 791 |         objPtr->length = length; | 
|---|
 | 792 |         if (objPtr->bytes != tclEmptyStringRep) { | 
|---|
 | 793 |             /* | 
|---|
 | 794 |              * Ensure the string is NUL-terminated. | 
|---|
 | 795 |              */ | 
|---|
 | 796 |  | 
|---|
 | 797 |             objPtr->bytes[length] = 0; | 
|---|
 | 798 |         } | 
|---|
 | 799 |  | 
|---|
 | 800 |         /* | 
|---|
 | 801 |          * Invalidate the unicode data. | 
|---|
 | 802 |          */ | 
|---|
 | 803 |  | 
|---|
 | 804 |         stringPtr->numChars = -1; | 
|---|
 | 805 |         stringPtr->hasUnicode = 0; | 
|---|
 | 806 |     } else { | 
|---|
 | 807 |         /* | 
|---|
 | 808 |          * Changing length of pure unicode string. | 
|---|
 | 809 |          */ | 
|---|
 | 810 |  | 
|---|
 | 811 |         size_t uallocated = STRING_UALLOC(length); | 
|---|
 | 812 |  | 
|---|
 | 813 |         if (uallocated > stringPtr->uallocated) { | 
|---|
 | 814 |             stringPtr = (String *) ckrealloc((char*) stringPtr, | 
|---|
 | 815 |                     STRING_SIZE(uallocated)); | 
|---|
 | 816 |             SET_STRING(objPtr, stringPtr); | 
|---|
 | 817 |             stringPtr->uallocated = uallocated; | 
|---|
 | 818 |         } | 
|---|
 | 819 |         stringPtr->numChars = length; | 
|---|
 | 820 |         stringPtr->hasUnicode = (length > 0); | 
|---|
 | 821 |  | 
|---|
 | 822 |         /* | 
|---|
 | 823 |          * Ensure the string is NUL-terminated. | 
|---|
 | 824 |          */ | 
|---|
 | 825 |  | 
|---|
 | 826 |         stringPtr->unicode[length] = 0; | 
|---|
 | 827 |         stringPtr->allocated = 0; | 
|---|
 | 828 |         objPtr->length = 0; | 
|---|
 | 829 |     } | 
|---|
 | 830 | } | 
|---|
 | 831 |  | 
|---|
 | 832 | /* | 
|---|
 | 833 |  *---------------------------------------------------------------------- | 
|---|
 | 834 |  * | 
|---|
 | 835 |  * Tcl_AttemptSetObjLength -- | 
|---|
 | 836 |  * | 
|---|
 | 837 |  *      This function changes the length of the string representation of an | 
|---|
 | 838 |  *      object. It uses the attempt* (non-panic'ing) memory allocators. | 
|---|
 | 839 |  * | 
|---|
 | 840 |  * Results: | 
|---|
 | 841 |  *      1 if the requested memory was allocated, 0 otherwise. | 
|---|
 | 842 |  * | 
|---|
 | 843 |  * Side effects: | 
|---|
 | 844 |  *      If the size of objPtr's string representation is greater than length, | 
|---|
 | 845 |  *      then it is reduced to length and a new terminating null byte is stored | 
|---|
 | 846 |  *      in the strength. If the length of the string representation is greater | 
|---|
 | 847 |  *      than length, the storage space is reallocated to the given length; a | 
|---|
 | 848 |  *      null byte is stored at the end, but other bytes past the end of the | 
|---|
 | 849 |  *      original string representation are undefined. The object's internal | 
|---|
 | 850 |  *      representation is changed to "expendable string". | 
|---|
 | 851 |  * | 
|---|
 | 852 |  *---------------------------------------------------------------------- | 
|---|
 | 853 |  */ | 
|---|
 | 854 |  | 
|---|
 | 855 | int | 
|---|
 | 856 | Tcl_AttemptSetObjLength( | 
|---|
 | 857 |     register Tcl_Obj *objPtr,   /* Pointer to object. This object must not | 
|---|
 | 858 |                                  * currently be shared. */ | 
|---|
 | 859 |     register int length)        /* Number of bytes desired for string | 
|---|
 | 860 |                                  * representation of object, not including | 
|---|
 | 861 |                                  * terminating null byte. */ | 
|---|
 | 862 | { | 
|---|
 | 863 |     String *stringPtr; | 
|---|
 | 864 |  | 
|---|
 | 865 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 866 |         Tcl_Panic("%s called with shared object", "Tcl_AttemptSetObjLength"); | 
|---|
 | 867 |     } | 
|---|
 | 868 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 869 |  | 
|---|
 | 870 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 871 |  | 
|---|
 | 872 |     /* | 
|---|
 | 873 |      * Check that we're not extending a pure unicode string. | 
|---|
 | 874 |      */ | 
|---|
 | 875 |  | 
|---|
 | 876 |     if (length > (int) stringPtr->allocated && | 
|---|
 | 877 |             (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) { | 
|---|
 | 878 |         char *newBytes; | 
|---|
 | 879 |  | 
|---|
 | 880 |         /* | 
|---|
 | 881 |          * Not enough space in current string. Reallocate the string space and | 
|---|
 | 882 |          * free the old string. | 
|---|
 | 883 |          */ | 
|---|
 | 884 |  | 
|---|
 | 885 |         if (objPtr->bytes != tclEmptyStringRep) { | 
|---|
 | 886 |             newBytes = attemptckrealloc(objPtr->bytes, | 
|---|
 | 887 |                     (unsigned)(length + 1)); | 
|---|
 | 888 |             if (newBytes == NULL) { | 
|---|
 | 889 |                 return 0; | 
|---|
 | 890 |             } | 
|---|
 | 891 |         } else { | 
|---|
 | 892 |             newBytes = attemptckalloc((unsigned) (length + 1)); | 
|---|
 | 893 |             if (newBytes == NULL) { | 
|---|
 | 894 |                 return 0; | 
|---|
 | 895 |             } | 
|---|
 | 896 |             if (objPtr->bytes != NULL && objPtr->length != 0) { | 
|---|
 | 897 |                 memcpy(newBytes, objPtr->bytes, (size_t) objPtr->length); | 
|---|
 | 898 |                 Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 899 |             } | 
|---|
 | 900 |         } | 
|---|
 | 901 |         objPtr->bytes = newBytes; | 
|---|
 | 902 |         stringPtr->allocated = length; | 
|---|
 | 903 |  | 
|---|
 | 904 |         /* | 
|---|
 | 905 |          * Invalidate the unicode data. | 
|---|
 | 906 |          */ | 
|---|
 | 907 |  | 
|---|
 | 908 |         stringPtr->hasUnicode = 0; | 
|---|
 | 909 |     } | 
|---|
 | 910 |  | 
|---|
 | 911 |     if (objPtr->bytes != NULL) { | 
|---|
 | 912 |         objPtr->length = length; | 
|---|
 | 913 |         if (objPtr->bytes != tclEmptyStringRep) { | 
|---|
 | 914 |             /* | 
|---|
 | 915 |              * Ensure the string is NULL-terminated. | 
|---|
 | 916 |              */ | 
|---|
 | 917 |  | 
|---|
 | 918 |             objPtr->bytes[length] = 0; | 
|---|
 | 919 |         } | 
|---|
 | 920 |  | 
|---|
 | 921 |         /* | 
|---|
 | 922 |          * Invalidate the unicode data. | 
|---|
 | 923 |          */ | 
|---|
 | 924 |  | 
|---|
 | 925 |         stringPtr->numChars = -1; | 
|---|
 | 926 |         stringPtr->hasUnicode = 0; | 
|---|
 | 927 |     } else { | 
|---|
 | 928 |         /* | 
|---|
 | 929 |          * Changing length of pure unicode string. | 
|---|
 | 930 |          */ | 
|---|
 | 931 |  | 
|---|
 | 932 |         size_t uallocated = STRING_UALLOC(length); | 
|---|
 | 933 |  | 
|---|
 | 934 |         if (uallocated > stringPtr->uallocated) { | 
|---|
 | 935 |             stringPtr = (String *) attemptckrealloc((char*) stringPtr, | 
|---|
 | 936 |                     STRING_SIZE(uallocated)); | 
|---|
 | 937 |             if (stringPtr == NULL) { | 
|---|
 | 938 |                 return 0; | 
|---|
 | 939 |             } | 
|---|
 | 940 |             SET_STRING(objPtr, stringPtr); | 
|---|
 | 941 |             stringPtr->uallocated = uallocated; | 
|---|
 | 942 |         } | 
|---|
 | 943 |         stringPtr->numChars = length; | 
|---|
 | 944 |         stringPtr->hasUnicode = (length > 0); | 
|---|
 | 945 |  | 
|---|
 | 946 |         /* | 
|---|
 | 947 |          * Ensure the string is NUL-terminated. | 
|---|
 | 948 |          */ | 
|---|
 | 949 |  | 
|---|
 | 950 |         stringPtr->unicode[length] = 0; | 
|---|
 | 951 |         stringPtr->allocated = 0; | 
|---|
 | 952 |         objPtr->length = 0; | 
|---|
 | 953 |     } | 
|---|
 | 954 |     return 1; | 
|---|
 | 955 | } | 
|---|
 | 956 |  | 
|---|
 | 957 | /* | 
|---|
 | 958 |  *--------------------------------------------------------------------------- | 
|---|
 | 959 |  * | 
|---|
 | 960 |  * TclSetUnicodeObj -- | 
|---|
 | 961 |  * | 
|---|
 | 962 |  *      Modify an object to hold the Unicode string indicated by "unicode". | 
|---|
 | 963 |  * | 
|---|
 | 964 |  * Results: | 
|---|
 | 965 |  *      None. | 
|---|
 | 966 |  * | 
|---|
 | 967 |  * Side effects: | 
|---|
 | 968 |  *      Memory allocated for new "String" internal rep. | 
|---|
 | 969 |  * | 
|---|
 | 970 |  *--------------------------------------------------------------------------- | 
|---|
 | 971 |  */ | 
|---|
 | 972 |  | 
|---|
 | 973 | void | 
|---|
 | 974 | Tcl_SetUnicodeObj( | 
|---|
 | 975 |     Tcl_Obj *objPtr,            /* The object to set the string of. */ | 
|---|
 | 976 |     const Tcl_UniChar *unicode, /* The unicode string used to initialize the | 
|---|
 | 977 |                                  * object. */ | 
|---|
 | 978 |     int numChars)               /* Number of characters in the unicode | 
|---|
 | 979 |                                  * string. */ | 
|---|
 | 980 | { | 
|---|
 | 981 |     String *stringPtr; | 
|---|
 | 982 |     size_t uallocated; | 
|---|
 | 983 |  | 
|---|
 | 984 |     if (numChars < 0) { | 
|---|
 | 985 |         numChars = 0; | 
|---|
 | 986 |         if (unicode) { | 
|---|
 | 987 |             while (unicode[numChars] != 0) { | 
|---|
 | 988 |                 numChars++; | 
|---|
 | 989 |             } | 
|---|
 | 990 |         } | 
|---|
 | 991 |     } | 
|---|
 | 992 |     uallocated = STRING_UALLOC(numChars); | 
|---|
 | 993 |  | 
|---|
 | 994 |     /* | 
|---|
 | 995 |      * Free the internal rep if one exists, and invalidate the string rep. | 
|---|
 | 996 |      */ | 
|---|
 | 997 |  | 
|---|
 | 998 |     TclFreeIntRep(objPtr); | 
|---|
 | 999 |     objPtr->typePtr = &tclStringType; | 
|---|
 | 1000 |  | 
|---|
 | 1001 |     /* | 
|---|
 | 1002 |      * Allocate enough space for the String structure + Unicode string. | 
|---|
 | 1003 |      */ | 
|---|
 | 1004 |  | 
|---|
 | 1005 |     stringPtr = (String *) ckalloc(STRING_SIZE(uallocated)); | 
|---|
 | 1006 |     stringPtr->numChars = numChars; | 
|---|
 | 1007 |     stringPtr->uallocated = uallocated; | 
|---|
 | 1008 |     stringPtr->hasUnicode = (numChars > 0); | 
|---|
 | 1009 |     stringPtr->allocated = 0; | 
|---|
 | 1010 |     memcpy(stringPtr->unicode, unicode, uallocated); | 
|---|
 | 1011 |     stringPtr->unicode[numChars] = 0; | 
|---|
 | 1012 |  | 
|---|
 | 1013 |     SET_STRING(objPtr, stringPtr); | 
|---|
 | 1014 |     Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 1015 |     return; | 
|---|
 | 1016 | } | 
|---|
 | 1017 |  | 
|---|
 | 1018 | /* | 
|---|
 | 1019 |  *---------------------------------------------------------------------- | 
|---|
 | 1020 |  * | 
|---|
 | 1021 |  * Tcl_AppendLimitedToObj -- | 
|---|
 | 1022 |  * | 
|---|
 | 1023 |  *      This function appends a limited number of bytes from a sequence of | 
|---|
 | 1024 |  *      bytes to an object, marking any limitation with an ellipsis. | 
|---|
 | 1025 |  * | 
|---|
 | 1026 |  * Results: | 
|---|
 | 1027 |  *      None. | 
|---|
 | 1028 |  * | 
|---|
 | 1029 |  * Side effects: | 
|---|
 | 1030 |  *      The bytes at *bytes are appended to the string representation of | 
|---|
 | 1031 |  *      objPtr. | 
|---|
 | 1032 |  * | 
|---|
 | 1033 |  *---------------------------------------------------------------------- | 
|---|
 | 1034 |  */ | 
|---|
 | 1035 |  | 
|---|
 | 1036 | void | 
|---|
 | 1037 | Tcl_AppendLimitedToObj( | 
|---|
 | 1038 |     register Tcl_Obj *objPtr,   /* Points to the object to append to. */ | 
|---|
 | 1039 |     const char *bytes,          /* Points to the bytes to append to the | 
|---|
 | 1040 |                                  * object. */ | 
|---|
 | 1041 |     register int length,        /* The number of bytes available to be | 
|---|
 | 1042 |                                  * appended from "bytes". If < 0, then all | 
|---|
 | 1043 |                                  * bytes up to a NUL byte are available. */ | 
|---|
 | 1044 |     register int limit,         /* The maximum number of bytes to append to | 
|---|
 | 1045 |                                  * the object. */ | 
|---|
 | 1046 |     const char *ellipsis)       /* Ellipsis marker string, appended to the | 
|---|
 | 1047 |                                  * object to indicate not all available bytes | 
|---|
 | 1048 |                                  * at "bytes" were appended. */ | 
|---|
 | 1049 | { | 
|---|
 | 1050 |     String *stringPtr; | 
|---|
 | 1051 |     int toCopy = 0; | 
|---|
 | 1052 |  | 
|---|
 | 1053 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 1054 |         Tcl_Panic("%s called with shared object", "Tcl_AppendLimitedToObj"); | 
|---|
 | 1055 |     } | 
|---|
 | 1056 |  | 
|---|
 | 1057 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 1058 |  | 
|---|
 | 1059 |     if (length < 0) { | 
|---|
 | 1060 |         length = (bytes ? strlen(bytes) : 0); | 
|---|
 | 1061 |     } | 
|---|
 | 1062 |     if (length == 0) { | 
|---|
 | 1063 |         return; | 
|---|
 | 1064 |     } | 
|---|
 | 1065 |  | 
|---|
 | 1066 |     if (length <= limit) { | 
|---|
 | 1067 |         toCopy = length; | 
|---|
 | 1068 |     } else { | 
|---|
 | 1069 |         if (ellipsis == NULL) { | 
|---|
 | 1070 |             ellipsis = "..."; | 
|---|
 | 1071 |         } | 
|---|
 | 1072 |         toCopy = Tcl_UtfPrev(bytes+limit+1-strlen(ellipsis), bytes) - bytes; | 
|---|
 | 1073 |     } | 
|---|
 | 1074 |  | 
|---|
 | 1075 |     /* | 
|---|
 | 1076 |      * If objPtr has a valid Unicode rep, then append the Unicode conversion | 
|---|
 | 1077 |      * of "bytes" to the objPtr's Unicode rep, otherwise append "bytes" to | 
|---|
 | 1078 |      * objPtr's string rep. | 
|---|
 | 1079 |      */ | 
|---|
 | 1080 |  | 
|---|
 | 1081 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1082 |     if (stringPtr->hasUnicode != 0) { | 
|---|
 | 1083 |         AppendUtfToUnicodeRep(objPtr, bytes, toCopy); | 
|---|
 | 1084 |     } else { | 
|---|
 | 1085 |         AppendUtfToUtfRep(objPtr, bytes, toCopy); | 
|---|
 | 1086 |     } | 
|---|
 | 1087 |  | 
|---|
 | 1088 |     if (length <= limit) { | 
|---|
 | 1089 |         return; | 
|---|
 | 1090 |     } | 
|---|
 | 1091 |  | 
|---|
 | 1092 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1093 |     if (stringPtr->hasUnicode != 0) { | 
|---|
 | 1094 |         AppendUtfToUnicodeRep(objPtr, ellipsis, -1); | 
|---|
 | 1095 |     } else { | 
|---|
 | 1096 |         AppendUtfToUtfRep(objPtr, ellipsis, -1); | 
|---|
 | 1097 |     } | 
|---|
 | 1098 | } | 
|---|
 | 1099 |  | 
|---|
 | 1100 | /* | 
|---|
 | 1101 |  *---------------------------------------------------------------------- | 
|---|
 | 1102 |  * | 
|---|
 | 1103 |  * Tcl_AppendToObj -- | 
|---|
 | 1104 |  * | 
|---|
 | 1105 |  *      This function appends a sequence of bytes to an object. | 
|---|
 | 1106 |  * | 
|---|
 | 1107 |  * Results: | 
|---|
 | 1108 |  *      None. | 
|---|
 | 1109 |  * | 
|---|
 | 1110 |  * Side effects: | 
|---|
 | 1111 |  *      The bytes at *bytes are appended to the string representation of | 
|---|
 | 1112 |  *      objPtr. | 
|---|
 | 1113 |  * | 
|---|
 | 1114 |  *---------------------------------------------------------------------- | 
|---|
 | 1115 |  */ | 
|---|
 | 1116 |  | 
|---|
 | 1117 | void | 
|---|
 | 1118 | Tcl_AppendToObj( | 
|---|
 | 1119 |     register Tcl_Obj *objPtr,   /* Points to the object to append to. */ | 
|---|
 | 1120 |     const char *bytes,          /* Points to the bytes to append to the | 
|---|
 | 1121 |                                  * object. */ | 
|---|
 | 1122 |     register int length)        /* The number of bytes to append from "bytes". | 
|---|
 | 1123 |                                  * If < 0, then append all bytes up to NUL | 
|---|
 | 1124 |                                  * byte. */ | 
|---|
 | 1125 | { | 
|---|
 | 1126 |     Tcl_AppendLimitedToObj(objPtr, bytes, length, INT_MAX, NULL); | 
|---|
 | 1127 | } | 
|---|
 | 1128 |  | 
|---|
 | 1129 | /* | 
|---|
 | 1130 |  *---------------------------------------------------------------------- | 
|---|
 | 1131 |  * | 
|---|
 | 1132 |  * Tcl_AppendUnicodeToObj -- | 
|---|
 | 1133 |  * | 
|---|
 | 1134 |  *      This function appends a Unicode string to an object in the most | 
|---|
 | 1135 |  *      efficient manner possible. Length must be >= 0. | 
|---|
 | 1136 |  * | 
|---|
 | 1137 |  * Results: | 
|---|
 | 1138 |  *      None. | 
|---|
 | 1139 |  * | 
|---|
 | 1140 |  * Side effects: | 
|---|
 | 1141 |  *      Invalidates the string rep and creates a new Unicode string. | 
|---|
 | 1142 |  * | 
|---|
 | 1143 |  *---------------------------------------------------------------------- | 
|---|
 | 1144 |  */ | 
|---|
 | 1145 |  | 
|---|
 | 1146 | void | 
|---|
 | 1147 | Tcl_AppendUnicodeToObj( | 
|---|
 | 1148 |     register Tcl_Obj *objPtr,   /* Points to the object to append to. */ | 
|---|
 | 1149 |     const Tcl_UniChar *unicode, /* The unicode string to append to the | 
|---|
 | 1150 |                                  * object. */ | 
|---|
 | 1151 |     int length)                 /* Number of chars in "unicode". */ | 
|---|
 | 1152 | { | 
|---|
 | 1153 |     String *stringPtr; | 
|---|
 | 1154 |  | 
|---|
 | 1155 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 1156 |         Tcl_Panic("%s called with shared object", "Tcl_AppendUnicodeToObj"); | 
|---|
 | 1157 |     } | 
|---|
 | 1158 |  | 
|---|
 | 1159 |     if (length == 0) { | 
|---|
 | 1160 |         return; | 
|---|
 | 1161 |     } | 
|---|
 | 1162 |  | 
|---|
 | 1163 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 1164 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1165 |  | 
|---|
 | 1166 |     /* | 
|---|
 | 1167 |      * If objPtr has a valid Unicode rep, then append the "unicode" to the | 
|---|
 | 1168 |      * objPtr's Unicode rep, otherwise the UTF conversion of "unicode" to | 
|---|
 | 1169 |      * objPtr's string rep. | 
|---|
 | 1170 |      */ | 
|---|
 | 1171 |  | 
|---|
 | 1172 |     if (stringPtr->hasUnicode != 0) { | 
|---|
 | 1173 |         AppendUnicodeToUnicodeRep(objPtr, unicode, length); | 
|---|
 | 1174 |     } else { | 
|---|
 | 1175 |         AppendUnicodeToUtfRep(objPtr, unicode, length); | 
|---|
 | 1176 |     } | 
|---|
 | 1177 | } | 
|---|
 | 1178 |  | 
|---|
 | 1179 | /* | 
|---|
 | 1180 |  *---------------------------------------------------------------------- | 
|---|
 | 1181 |  * | 
|---|
 | 1182 |  * Tcl_AppendObjToObj -- | 
|---|
 | 1183 |  * | 
|---|
 | 1184 |  *      This function appends the string rep of one object to another. | 
|---|
 | 1185 |  *      "objPtr" cannot be a shared object. | 
|---|
 | 1186 |  * | 
|---|
 | 1187 |  * Results: | 
|---|
 | 1188 |  *      None. | 
|---|
 | 1189 |  * | 
|---|
 | 1190 |  * Side effects: | 
|---|
 | 1191 |  *      The string rep of appendObjPtr is appended to the string | 
|---|
 | 1192 |  *      representation of objPtr. | 
|---|
 | 1193 |  * | 
|---|
 | 1194 |  *---------------------------------------------------------------------- | 
|---|
 | 1195 |  */ | 
|---|
 | 1196 |  | 
|---|
 | 1197 | void | 
|---|
 | 1198 | Tcl_AppendObjToObj( | 
|---|
 | 1199 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1200 |     Tcl_Obj *appendObjPtr)      /* Object to append. */ | 
|---|
 | 1201 | { | 
|---|
 | 1202 |     String *stringPtr; | 
|---|
 | 1203 |     int length, numChars, allOneByteChars; | 
|---|
 | 1204 |     char *bytes; | 
|---|
 | 1205 |  | 
|---|
 | 1206 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 1207 |  | 
|---|
 | 1208 |     /* | 
|---|
 | 1209 |      * If objPtr has a valid Unicode rep, then get a Unicode string from | 
|---|
 | 1210 |      * appendObjPtr and append it. | 
|---|
 | 1211 |      */ | 
|---|
 | 1212 |  | 
|---|
 | 1213 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1214 |     if (stringPtr->hasUnicode != 0) { | 
|---|
 | 1215 |         /* | 
|---|
 | 1216 |          * If appendObjPtr is not of the "String" type, don't convert it. | 
|---|
 | 1217 |          */ | 
|---|
 | 1218 |  | 
|---|
 | 1219 |         if (appendObjPtr->typePtr == &tclStringType) { | 
|---|
 | 1220 |             stringPtr = GET_STRING(appendObjPtr); | 
|---|
 | 1221 |             if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) { | 
|---|
 | 1222 |                 /* | 
|---|
 | 1223 |                  * If appendObjPtr is a string obj with no valid Unicode rep, | 
|---|
 | 1224 |                  * then fill its unicode rep. | 
|---|
 | 1225 |                  */ | 
|---|
 | 1226 |  | 
|---|
 | 1227 |                 FillUnicodeRep(appendObjPtr); | 
|---|
 | 1228 |                 stringPtr = GET_STRING(appendObjPtr); | 
|---|
 | 1229 |             } | 
|---|
 | 1230 |             AppendUnicodeToUnicodeRep(objPtr, stringPtr->unicode, | 
|---|
 | 1231 |                     stringPtr->numChars); | 
|---|
 | 1232 |         } else { | 
|---|
 | 1233 |             bytes = TclGetStringFromObj(appendObjPtr, &length); | 
|---|
 | 1234 |             AppendUtfToUnicodeRep(objPtr, bytes, length); | 
|---|
 | 1235 |         } | 
|---|
 | 1236 |         return; | 
|---|
 | 1237 |     } | 
|---|
 | 1238 |  | 
|---|
 | 1239 |     /* | 
|---|
 | 1240 |      * Append to objPtr's UTF string rep. If we know the number of characters | 
|---|
 | 1241 |      * in both objects before appending, then set the combined number of | 
|---|
 | 1242 |      * characters in the final (appended-to) object. | 
|---|
 | 1243 |      */ | 
|---|
 | 1244 |  | 
|---|
 | 1245 |     bytes = TclGetStringFromObj(appendObjPtr, &length); | 
|---|
 | 1246 |  | 
|---|
 | 1247 |     allOneByteChars = 0; | 
|---|
 | 1248 |     numChars = stringPtr->numChars; | 
|---|
 | 1249 |     if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) { | 
|---|
 | 1250 |         stringPtr = GET_STRING(appendObjPtr); | 
|---|
 | 1251 |         if ((stringPtr->numChars >= 0) && (stringPtr->numChars == length)) { | 
|---|
 | 1252 |             numChars += stringPtr->numChars; | 
|---|
 | 1253 |             allOneByteChars = 1; | 
|---|
 | 1254 |         } | 
|---|
 | 1255 |     } | 
|---|
 | 1256 |  | 
|---|
 | 1257 |     AppendUtfToUtfRep(objPtr, bytes, length); | 
|---|
 | 1258 |  | 
|---|
 | 1259 |     if (allOneByteChars) { | 
|---|
 | 1260 |         stringPtr = GET_STRING(objPtr); | 
|---|
 | 1261 |         stringPtr->numChars = numChars; | 
|---|
 | 1262 |     } | 
|---|
 | 1263 | } | 
|---|
 | 1264 |  | 
|---|
 | 1265 | /* | 
|---|
 | 1266 |  *---------------------------------------------------------------------- | 
|---|
 | 1267 |  * | 
|---|
 | 1268 |  * AppendUnicodeToUnicodeRep -- | 
|---|
 | 1269 |  * | 
|---|
 | 1270 |  *      This function appends the contents of "unicode" to the Unicode rep of | 
|---|
 | 1271 |  *      "objPtr". objPtr must already have a valid Unicode rep. | 
|---|
 | 1272 |  * | 
|---|
 | 1273 |  * Results: | 
|---|
 | 1274 |  *      None. | 
|---|
 | 1275 |  * | 
|---|
 | 1276 |  * Side effects: | 
|---|
 | 1277 |  *      objPtr's internal rep is reallocated. | 
|---|
 | 1278 |  * | 
|---|
 | 1279 |  *---------------------------------------------------------------------- | 
|---|
 | 1280 |  */ | 
|---|
 | 1281 |  | 
|---|
 | 1282 | static void | 
|---|
 | 1283 | AppendUnicodeToUnicodeRep( | 
|---|
 | 1284 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1285 |     const Tcl_UniChar *unicode, /* String to append. */ | 
|---|
 | 1286 |     int appendNumChars)         /* Number of chars of "unicode" to append. */ | 
|---|
 | 1287 | { | 
|---|
 | 1288 |     String *stringPtr, *tmpString; | 
|---|
 | 1289 |     size_t numChars; | 
|---|
 | 1290 |  | 
|---|
 | 1291 |     if (appendNumChars < 0) { | 
|---|
 | 1292 |         appendNumChars = 0; | 
|---|
 | 1293 |         if (unicode) { | 
|---|
 | 1294 |             while (unicode[appendNumChars] != 0) { | 
|---|
 | 1295 |                 appendNumChars++; | 
|---|
 | 1296 |             } | 
|---|
 | 1297 |         } | 
|---|
 | 1298 |     } | 
|---|
 | 1299 |     if (appendNumChars == 0) { | 
|---|
 | 1300 |         return; | 
|---|
 | 1301 |     } | 
|---|
 | 1302 |  | 
|---|
 | 1303 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 1304 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1305 |  | 
|---|
 | 1306 |     /* | 
|---|
 | 1307 |      * If not enough space has been allocated for the unicode rep, reallocate | 
|---|
 | 1308 |      * the internal rep object with additional space. First try to double the | 
|---|
 | 1309 |      * required allocation; if that fails, try a more modest increase. See the | 
|---|
 | 1310 |      * "TCL STRING GROWTH ALGORITHM" comment at the top of this file for an | 
|---|
 | 1311 |      * explanation of this growth algorithm. | 
|---|
 | 1312 |      */ | 
|---|
 | 1313 |  | 
|---|
 | 1314 |     numChars = stringPtr->numChars + appendNumChars; | 
|---|
 | 1315 |  | 
|---|
 | 1316 |     if (STRING_UALLOC(numChars) >= stringPtr->uallocated) { | 
|---|
 | 1317 |         stringPtr->uallocated = STRING_UALLOC(2 * numChars); | 
|---|
 | 1318 |         tmpString = (String *) attemptckrealloc((char *)stringPtr, | 
|---|
 | 1319 |                 STRING_SIZE(stringPtr->uallocated)); | 
|---|
 | 1320 |         if (tmpString == NULL) { | 
|---|
 | 1321 |             stringPtr->uallocated = | 
|---|
 | 1322 |                     STRING_UALLOC(numChars + appendNumChars) | 
|---|
 | 1323 |                     + TCL_GROWTH_MIN_ALLOC; | 
|---|
 | 1324 |             tmpString = (String *) ckrealloc((char *)stringPtr, | 
|---|
 | 1325 |                     STRING_SIZE(stringPtr->uallocated)); | 
|---|
 | 1326 |         } | 
|---|
 | 1327 |         stringPtr = tmpString; | 
|---|
 | 1328 |         SET_STRING(objPtr, stringPtr); | 
|---|
 | 1329 |     } | 
|---|
 | 1330 |  | 
|---|
 | 1331 |     /* | 
|---|
 | 1332 |      * Copy the new string onto the end of the old string, then add the | 
|---|
 | 1333 |      * trailing null. | 
|---|
 | 1334 |      */ | 
|---|
 | 1335 |  | 
|---|
 | 1336 |     memcpy(stringPtr->unicode + stringPtr->numChars, unicode, | 
|---|
 | 1337 |             appendNumChars * sizeof(Tcl_UniChar)); | 
|---|
 | 1338 |     stringPtr->unicode[numChars] = 0; | 
|---|
 | 1339 |     stringPtr->numChars = numChars; | 
|---|
 | 1340 |  | 
|---|
 | 1341 |     Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 1342 | } | 
|---|
 | 1343 |  | 
|---|
 | 1344 | /* | 
|---|
 | 1345 |  *---------------------------------------------------------------------- | 
|---|
 | 1346 |  * | 
|---|
 | 1347 |  * AppendUnicodeToUtfRep -- | 
|---|
 | 1348 |  * | 
|---|
 | 1349 |  *      This function converts the contents of "unicode" to UTF and appends | 
|---|
 | 1350 |  *      the UTF to the string rep of "objPtr". | 
|---|
 | 1351 |  * | 
|---|
 | 1352 |  * Results: | 
|---|
 | 1353 |  *      None. | 
|---|
 | 1354 |  * | 
|---|
 | 1355 |  * Side effects: | 
|---|
 | 1356 |  *      objPtr's internal rep is reallocated. | 
|---|
 | 1357 |  * | 
|---|
 | 1358 |  *---------------------------------------------------------------------- | 
|---|
 | 1359 |  */ | 
|---|
 | 1360 |  | 
|---|
 | 1361 | static void | 
|---|
 | 1362 | AppendUnicodeToUtfRep( | 
|---|
 | 1363 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1364 |     const Tcl_UniChar *unicode, /* String to convert to UTF. */ | 
|---|
 | 1365 |     int numChars)               /* Number of chars of "unicode" to convert. */ | 
|---|
 | 1366 | { | 
|---|
 | 1367 |     Tcl_DString dsPtr; | 
|---|
 | 1368 |     const char *bytes; | 
|---|
 | 1369 |  | 
|---|
 | 1370 |     if (numChars < 0) { | 
|---|
 | 1371 |         numChars = 0; | 
|---|
 | 1372 |         if (unicode) { | 
|---|
 | 1373 |             while (unicode[numChars] != 0) { | 
|---|
 | 1374 |                 numChars++; | 
|---|
 | 1375 |             } | 
|---|
 | 1376 |         } | 
|---|
 | 1377 |     } | 
|---|
 | 1378 |     if (numChars == 0) { | 
|---|
 | 1379 |         return; | 
|---|
 | 1380 |     } | 
|---|
 | 1381 |  | 
|---|
 | 1382 |     Tcl_DStringInit(&dsPtr); | 
|---|
 | 1383 |     bytes = Tcl_UniCharToUtfDString(unicode, numChars, &dsPtr); | 
|---|
 | 1384 |     AppendUtfToUtfRep(objPtr, bytes, Tcl_DStringLength(&dsPtr)); | 
|---|
 | 1385 |     Tcl_DStringFree(&dsPtr); | 
|---|
 | 1386 | } | 
|---|
 | 1387 |  | 
|---|
 | 1388 | /* | 
|---|
 | 1389 |  *---------------------------------------------------------------------- | 
|---|
 | 1390 |  * | 
|---|
 | 1391 |  * AppendUtfToUnicodeRep -- | 
|---|
 | 1392 |  * | 
|---|
 | 1393 |  *      This function converts the contents of "bytes" to Unicode and appends | 
|---|
 | 1394 |  *      the Unicode to the Unicode rep of "objPtr". objPtr must already have a | 
|---|
 | 1395 |  *      valid Unicode rep. | 
|---|
 | 1396 |  * | 
|---|
 | 1397 |  * Results: | 
|---|
 | 1398 |  *      None. | 
|---|
 | 1399 |  * | 
|---|
 | 1400 |  * Side effects: | 
|---|
 | 1401 |  *      objPtr's internal rep is reallocated. | 
|---|
 | 1402 |  * | 
|---|
 | 1403 |  *---------------------------------------------------------------------- | 
|---|
 | 1404 |  */ | 
|---|
 | 1405 |  | 
|---|
 | 1406 | static void | 
|---|
 | 1407 | AppendUtfToUnicodeRep( | 
|---|
 | 1408 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1409 |     const char *bytes,          /* String to convert to Unicode. */ | 
|---|
 | 1410 |     int numBytes)               /* Number of bytes of "bytes" to convert. */ | 
|---|
 | 1411 | { | 
|---|
 | 1412 |     Tcl_DString dsPtr; | 
|---|
 | 1413 |     int numChars; | 
|---|
 | 1414 |     Tcl_UniChar *unicode; | 
|---|
 | 1415 |  | 
|---|
 | 1416 |     if (numBytes < 0) { | 
|---|
 | 1417 |         numBytes = (bytes ? strlen(bytes) : 0); | 
|---|
 | 1418 |     } | 
|---|
 | 1419 |     if (numBytes == 0) { | 
|---|
 | 1420 |         return; | 
|---|
 | 1421 |     } | 
|---|
 | 1422 |  | 
|---|
 | 1423 |     Tcl_DStringInit(&dsPtr); | 
|---|
 | 1424 |     numChars = Tcl_NumUtfChars(bytes, numBytes); | 
|---|
 | 1425 |     unicode = (Tcl_UniChar *)Tcl_UtfToUniCharDString(bytes, numBytes, &dsPtr); | 
|---|
 | 1426 |     AppendUnicodeToUnicodeRep(objPtr, unicode, numChars); | 
|---|
 | 1427 |     Tcl_DStringFree(&dsPtr); | 
|---|
 | 1428 | } | 
|---|
 | 1429 |  | 
|---|
 | 1430 | /* | 
|---|
 | 1431 |  *---------------------------------------------------------------------- | 
|---|
 | 1432 |  * | 
|---|
 | 1433 |  * AppendUtfToUtfRep -- | 
|---|
 | 1434 |  * | 
|---|
 | 1435 |  *      This function appends "numBytes" bytes of "bytes" to the UTF string | 
|---|
 | 1436 |  *      rep of "objPtr". objPtr must already have a valid String rep. | 
|---|
 | 1437 |  * | 
|---|
 | 1438 |  * Results: | 
|---|
 | 1439 |  *      None. | 
|---|
 | 1440 |  * | 
|---|
 | 1441 |  * Side effects: | 
|---|
 | 1442 |  *      objPtr's internal rep is reallocated. | 
|---|
 | 1443 |  * | 
|---|
 | 1444 |  *---------------------------------------------------------------------- | 
|---|
 | 1445 |  */ | 
|---|
 | 1446 |  | 
|---|
 | 1447 | static void | 
|---|
 | 1448 | AppendUtfToUtfRep( | 
|---|
 | 1449 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1450 |     const char *bytes,          /* String to append. */ | 
|---|
 | 1451 |     int numBytes)               /* Number of bytes of "bytes" to append. */ | 
|---|
 | 1452 | { | 
|---|
 | 1453 |     String *stringPtr; | 
|---|
 | 1454 |     int newLength, oldLength; | 
|---|
 | 1455 |  | 
|---|
 | 1456 |     if (numBytes < 0) { | 
|---|
 | 1457 |         numBytes = (bytes ? strlen(bytes) : 0); | 
|---|
 | 1458 |     } | 
|---|
 | 1459 |     if (numBytes == 0) { | 
|---|
 | 1460 |         return; | 
|---|
 | 1461 |     } | 
|---|
 | 1462 |  | 
|---|
 | 1463 |     /* | 
|---|
 | 1464 |      * Copy the new string onto the end of the old string, then add the | 
|---|
 | 1465 |      * trailing null. | 
|---|
 | 1466 |      */ | 
|---|
 | 1467 |  | 
|---|
 | 1468 |     oldLength = objPtr->length; | 
|---|
 | 1469 |     newLength = numBytes + oldLength; | 
|---|
 | 1470 |  | 
|---|
 | 1471 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1472 |     if (newLength > (int) stringPtr->allocated) { | 
|---|
 | 1473 |         /* | 
|---|
 | 1474 |          * There isn't currently enough space in the string representation so | 
|---|
 | 1475 |          * allocate additional space. First, try to double the length | 
|---|
 | 1476 |          * required. If that fails, try a more modest allocation. See the "TCL | 
|---|
 | 1477 |          * STRING GROWTH ALGORITHM" comment at the top of this file for an | 
|---|
 | 1478 |          * explanation of this growth algorithm. | 
|---|
 | 1479 |          */ | 
|---|
 | 1480 |  | 
|---|
 | 1481 |         if (Tcl_AttemptSetObjLength(objPtr, 2 * newLength) == 0) { | 
|---|
 | 1482 |             Tcl_SetObjLength(objPtr, | 
|---|
 | 1483 |                     newLength + numBytes + TCL_GROWTH_MIN_ALLOC); | 
|---|
 | 1484 |         } | 
|---|
 | 1485 |     } | 
|---|
 | 1486 |  | 
|---|
 | 1487 |     /* | 
|---|
 | 1488 |      * Invalidate the unicode data. | 
|---|
 | 1489 |      */ | 
|---|
 | 1490 |  | 
|---|
 | 1491 |     stringPtr->numChars = -1; | 
|---|
 | 1492 |     stringPtr->hasUnicode = 0; | 
|---|
 | 1493 |  | 
|---|
 | 1494 |     memcpy(objPtr->bytes + oldLength, bytes, (size_t) numBytes); | 
|---|
 | 1495 |     objPtr->bytes[newLength] = 0; | 
|---|
 | 1496 |     objPtr->length = newLength; | 
|---|
 | 1497 | } | 
|---|
 | 1498 |  | 
|---|
 | 1499 | /* | 
|---|
 | 1500 |  *---------------------------------------------------------------------- | 
|---|
 | 1501 |  * | 
|---|
 | 1502 |  * Tcl_AppendStringsToObjVA -- | 
|---|
 | 1503 |  * | 
|---|
 | 1504 |  *      This function appends one or more null-terminated strings to an | 
|---|
 | 1505 |  *      object. | 
|---|
 | 1506 |  * | 
|---|
 | 1507 |  * Results: | 
|---|
 | 1508 |  *      None. | 
|---|
 | 1509 |  * | 
|---|
 | 1510 |  * Side effects: | 
|---|
 | 1511 |  *      The contents of all the string arguments are appended to the string | 
|---|
 | 1512 |  *      representation of objPtr. | 
|---|
 | 1513 |  * | 
|---|
 | 1514 |  *---------------------------------------------------------------------- | 
|---|
 | 1515 |  */ | 
|---|
 | 1516 |  | 
|---|
 | 1517 | void | 
|---|
 | 1518 | Tcl_AppendStringsToObjVA( | 
|---|
 | 1519 |     Tcl_Obj *objPtr,            /* Points to the object to append to. */ | 
|---|
 | 1520 |     va_list argList)            /* Variable argument list. */ | 
|---|
 | 1521 | { | 
|---|
 | 1522 | #define STATIC_LIST_SIZE 16 | 
|---|
 | 1523 |     String *stringPtr; | 
|---|
 | 1524 |     int newLength, oldLength, attemptLength; | 
|---|
 | 1525 |     register char *string, *dst; | 
|---|
 | 1526 |     char *static_list[STATIC_LIST_SIZE]; | 
|---|
 | 1527 |     char **args = static_list; | 
|---|
 | 1528 |     int nargs_space = STATIC_LIST_SIZE; | 
|---|
 | 1529 |     int nargs, i; | 
|---|
 | 1530 |  | 
|---|
 | 1531 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 1532 |         Tcl_Panic("%s called with shared object", "Tcl_AppendStringsToObj"); | 
|---|
 | 1533 |     } | 
|---|
 | 1534 |  | 
|---|
 | 1535 |     SetStringFromAny(NULL, objPtr); | 
|---|
 | 1536 |  | 
|---|
 | 1537 |     /* | 
|---|
 | 1538 |      * Figure out how much space is needed for all the strings, and expand the | 
|---|
 | 1539 |      * string representation if it isn't big enough. If no bytes would be | 
|---|
 | 1540 |      * appended, just return. Note that on some platforms (notably OS/390) the | 
|---|
 | 1541 |      * argList is an array so we need to use memcpy. | 
|---|
 | 1542 |      */ | 
|---|
 | 1543 |  | 
|---|
 | 1544 |     nargs = 0; | 
|---|
 | 1545 |     newLength = 0; | 
|---|
 | 1546 |     oldLength = objPtr->length; | 
|---|
 | 1547 |     while (1) { | 
|---|
 | 1548 |         string = va_arg(argList, char *); | 
|---|
 | 1549 |         if (string == NULL) { | 
|---|
 | 1550 |             break; | 
|---|
 | 1551 |         } | 
|---|
 | 1552 |         if (nargs >= nargs_space) { | 
|---|
 | 1553 |             /* | 
|---|
 | 1554 |              * Expand the args buffer. | 
|---|
 | 1555 |              */ | 
|---|
 | 1556 |  | 
|---|
 | 1557 |             nargs_space += STATIC_LIST_SIZE; | 
|---|
 | 1558 |             if (args == static_list) { | 
|---|
 | 1559 |                 args = (void *) ckalloc(nargs_space * sizeof(char *)); | 
|---|
 | 1560 |                 for (i = 0; i < nargs; ++i) { | 
|---|
 | 1561 |                     args[i] = static_list[i]; | 
|---|
 | 1562 |                 } | 
|---|
 | 1563 |             } else { | 
|---|
 | 1564 |                 args = (void *) ckrealloc((void *) args, | 
|---|
 | 1565 |                         nargs_space * sizeof(char *)); | 
|---|
 | 1566 |             } | 
|---|
 | 1567 |         } | 
|---|
 | 1568 |         newLength += strlen(string); | 
|---|
 | 1569 |         args[nargs++] = string; | 
|---|
 | 1570 |     } | 
|---|
 | 1571 |     if (newLength == 0) { | 
|---|
 | 1572 |         goto done; | 
|---|
 | 1573 |     } | 
|---|
 | 1574 |  | 
|---|
 | 1575 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 1576 |     if (oldLength + newLength > (int) stringPtr->allocated) { | 
|---|
 | 1577 |         /* | 
|---|
 | 1578 |          * There isn't currently enough space in the string representation, so | 
|---|
 | 1579 |          * allocate additional space. If the current string representation | 
|---|
 | 1580 |          * isn't empty (i.e. it looks like we're doing a series of appends) | 
|---|
 | 1581 |          * then try to allocate extra space to accomodate future growth: first | 
|---|
 | 1582 |          * try to double the required memory; if that fails, try a more modest | 
|---|
 | 1583 |          * allocation. See the "TCL STRING GROWTH ALGORITHM" comment at the | 
|---|
 | 1584 |          * top of this file for an explanation of this growth algorithm. | 
|---|
 | 1585 |          * Otherwise, if the current string representation is empty, exactly | 
|---|
 | 1586 |          * enough memory is allocated. | 
|---|
 | 1587 |          */ | 
|---|
 | 1588 |  | 
|---|
 | 1589 |         if (oldLength == 0) { | 
|---|
 | 1590 |             Tcl_SetObjLength(objPtr, newLength); | 
|---|
 | 1591 |         } else { | 
|---|
 | 1592 |             attemptLength = 2 * (oldLength + newLength); | 
|---|
 | 1593 |             if (Tcl_AttemptSetObjLength(objPtr, attemptLength) == 0) { | 
|---|
 | 1594 |                 attemptLength = oldLength + (2 * newLength) + | 
|---|
 | 1595 |                         TCL_GROWTH_MIN_ALLOC; | 
|---|
 | 1596 |                 Tcl_SetObjLength(objPtr, attemptLength); | 
|---|
 | 1597 |             } | 
|---|
 | 1598 |         } | 
|---|
 | 1599 |     } | 
|---|
 | 1600 |  | 
|---|
 | 1601 |     /* | 
|---|
 | 1602 |      * Make a second pass through the arguments, appending all the strings to | 
|---|
 | 1603 |      * the object. | 
|---|
 | 1604 |      */ | 
|---|
 | 1605 |  | 
|---|
 | 1606 |     dst = objPtr->bytes + oldLength; | 
|---|
 | 1607 |     for (i = 0; i < nargs; ++i) { | 
|---|
 | 1608 |         string = args[i]; | 
|---|
 | 1609 |         if (string == NULL) { | 
|---|
 | 1610 |             break; | 
|---|
 | 1611 |         } | 
|---|
 | 1612 |         while (*string != 0) { | 
|---|
 | 1613 |             *dst = *string; | 
|---|
 | 1614 |             dst++; | 
|---|
 | 1615 |             string++; | 
|---|
 | 1616 |         } | 
|---|
 | 1617 |     } | 
|---|
 | 1618 |  | 
|---|
 | 1619 |     /* | 
|---|
 | 1620 |      * Add a null byte to terminate the string. However, be careful: it's | 
|---|
 | 1621 |      * possible that the object is totally empty (if it was empty originally | 
|---|
 | 1622 |      * and there was nothing to append). In this case dst is NULL; just leave | 
|---|
 | 1623 |      * everything alone. | 
|---|
 | 1624 |      */ | 
|---|
 | 1625 |  | 
|---|
 | 1626 |     if (dst != NULL) { | 
|---|
 | 1627 |         *dst = 0; | 
|---|
 | 1628 |     } | 
|---|
 | 1629 |     objPtr->length = oldLength + newLength; | 
|---|
 | 1630 |  | 
|---|
 | 1631 |   done: | 
|---|
 | 1632 |     /* | 
|---|
 | 1633 |      * If we had to allocate a buffer from the heap, free it now. | 
|---|
 | 1634 |      */ | 
|---|
 | 1635 |  | 
|---|
 | 1636 |     if (args != static_list) { | 
|---|
 | 1637 |         ckfree((void *) args); | 
|---|
 | 1638 |     } | 
|---|
 | 1639 | #undef STATIC_LIST_SIZE | 
|---|
 | 1640 | } | 
|---|
 | 1641 |  | 
|---|
 | 1642 | /* | 
|---|
 | 1643 |  *---------------------------------------------------------------------- | 
|---|
 | 1644 |  * | 
|---|
 | 1645 |  * Tcl_AppendStringsToObj -- | 
|---|
 | 1646 |  * | 
|---|
 | 1647 |  *      This function appends one or more null-terminated strings to an | 
|---|
 | 1648 |  *      object. | 
|---|
 | 1649 |  * | 
|---|
 | 1650 |  * Results: | 
|---|
 | 1651 |  *      None. | 
|---|
 | 1652 |  * | 
|---|
 | 1653 |  * Side effects: | 
|---|
 | 1654 |  *      The contents of all the string arguments are appended to the string | 
|---|
 | 1655 |  *      representation of objPtr. | 
|---|
 | 1656 |  * | 
|---|
 | 1657 |  *---------------------------------------------------------------------- | 
|---|
 | 1658 |  */ | 
|---|
 | 1659 |  | 
|---|
 | 1660 | void | 
|---|
 | 1661 | Tcl_AppendStringsToObj( | 
|---|
 | 1662 |     Tcl_Obj *objPtr, | 
|---|
 | 1663 |     ...) | 
|---|
 | 1664 | { | 
|---|
 | 1665 |     va_list argList; | 
|---|
 | 1666 |  | 
|---|
 | 1667 |     va_start(argList, objPtr); | 
|---|
 | 1668 |     Tcl_AppendStringsToObjVA(objPtr, argList); | 
|---|
 | 1669 |     va_end(argList); | 
|---|
 | 1670 | } | 
|---|
 | 1671 |  | 
|---|
 | 1672 | /* | 
|---|
 | 1673 |  *---------------------------------------------------------------------- | 
|---|
 | 1674 |  * | 
|---|
 | 1675 |  * Tcl_AppendFormatToObj -- | 
|---|
 | 1676 |  * | 
|---|
 | 1677 |  *      This function appends a list of Tcl_Obj's to a Tcl_Obj according to | 
|---|
 | 1678 |  *      the formatting instructions embedded in the format string. The | 
|---|
 | 1679 |  *      formatting instructions are inspired by sprintf(). Returns TCL_OK when | 
|---|
 | 1680 |  *      successful. If there's an error in the arguments, TCL_ERROR is | 
|---|
 | 1681 |  *      returned, and an error message is written to the interp, if non-NULL. | 
|---|
 | 1682 |  * | 
|---|
 | 1683 |  * Results: | 
|---|
 | 1684 |  *      A standard Tcl result. | 
|---|
 | 1685 |  * | 
|---|
 | 1686 |  * Side effects: | 
|---|
 | 1687 |  *      None. | 
|---|
 | 1688 |  * | 
|---|
 | 1689 |  *---------------------------------------------------------------------- | 
|---|
 | 1690 |  */ | 
|---|
 | 1691 |  | 
|---|
 | 1692 | int | 
|---|
 | 1693 | Tcl_AppendFormatToObj( | 
|---|
 | 1694 |     Tcl_Interp *interp, | 
|---|
 | 1695 |     Tcl_Obj *appendObj, | 
|---|
 | 1696 |     const char *format, | 
|---|
 | 1697 |     int objc, | 
|---|
 | 1698 |     Tcl_Obj *const objv[]) | 
|---|
 | 1699 | { | 
|---|
 | 1700 |     const char *span = format, *msg; | 
|---|
 | 1701 |     int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0; | 
|---|
 | 1702 |     int originalLength; | 
|---|
 | 1703 |     static const char *mixedXPG = | 
|---|
 | 1704 |             "cannot mix \"%\" and \"%n$\" conversion specifiers"; | 
|---|
 | 1705 |     static const char *badIndex[2] = { | 
|---|
 | 1706 |         "not enough arguments for all format specifiers", | 
|---|
 | 1707 |         "\"%n$\" argument index out of range" | 
|---|
 | 1708 |     }; | 
|---|
 | 1709 |  | 
|---|
 | 1710 |     if (Tcl_IsShared(appendObj)) { | 
|---|
 | 1711 |         Tcl_Panic("%s called with shared object", "Tcl_AppendFormatToObj"); | 
|---|
 | 1712 |     } | 
|---|
 | 1713 |     TclGetStringFromObj(appendObj, &originalLength); | 
|---|
 | 1714 |  | 
|---|
 | 1715 |     /* | 
|---|
 | 1716 |      * Format string is NUL-terminated. | 
|---|
 | 1717 |      */ | 
|---|
 | 1718 |  | 
|---|
 | 1719 |     while (*format != '\0') { | 
|---|
 | 1720 |         char *end; | 
|---|
 | 1721 |         int gotMinus, gotHash, gotZero, gotSpace, gotPlus, sawFlag; | 
|---|
 | 1722 |         int width, gotPrecision, precision, useShort, useWide, useBig; | 
|---|
 | 1723 |         int newXpg, numChars, allocSegment = 0; | 
|---|
 | 1724 |         Tcl_Obj *segment; | 
|---|
 | 1725 |         Tcl_UniChar ch; | 
|---|
 | 1726 |         int step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1727 |  | 
|---|
 | 1728 |         format += step; | 
|---|
 | 1729 |         if (ch != '%') { | 
|---|
 | 1730 |             numBytes += step; | 
|---|
 | 1731 |             continue; | 
|---|
 | 1732 |         } | 
|---|
 | 1733 |         if (numBytes) { | 
|---|
 | 1734 |             Tcl_AppendToObj(appendObj, span, numBytes); | 
|---|
 | 1735 |             numBytes = 0; | 
|---|
 | 1736 |         } | 
|---|
 | 1737 |  | 
|---|
 | 1738 |         /* | 
|---|
 | 1739 |          * Saw a % : process the format specifier. | 
|---|
 | 1740 |          * | 
|---|
 | 1741 |          * Step 0. Handle special case of escaped format marker (i.e., %%). | 
|---|
 | 1742 |          */ | 
|---|
 | 1743 |  | 
|---|
 | 1744 |         step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1745 |         if (ch == '%') { | 
|---|
 | 1746 |             span = format; | 
|---|
 | 1747 |             numBytes = step; | 
|---|
 | 1748 |             format += step; | 
|---|
 | 1749 |             continue; | 
|---|
 | 1750 |         } | 
|---|
 | 1751 |  | 
|---|
 | 1752 |         /* | 
|---|
 | 1753 |          * Step 1. XPG3 position specifier | 
|---|
 | 1754 |          */ | 
|---|
 | 1755 |  | 
|---|
 | 1756 |         newXpg = 0; | 
|---|
 | 1757 |         if (isdigit(UCHAR(ch))) { | 
|---|
 | 1758 |             int position = strtoul(format, &end, 10); | 
|---|
 | 1759 |             if (*end == '$') { | 
|---|
 | 1760 |                 newXpg = 1; | 
|---|
 | 1761 |                 objIndex = position - 1; | 
|---|
 | 1762 |                 format = end + 1; | 
|---|
 | 1763 |                 step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1764 |             } | 
|---|
 | 1765 |         } | 
|---|
 | 1766 |         if (newXpg) { | 
|---|
 | 1767 |             if (gotSequential) { | 
|---|
 | 1768 |                 msg = mixedXPG; | 
|---|
 | 1769 |                 goto errorMsg; | 
|---|
 | 1770 |             } | 
|---|
 | 1771 |             gotXpg = 1; | 
|---|
 | 1772 |         } else { | 
|---|
 | 1773 |             if (gotXpg) { | 
|---|
 | 1774 |                 msg = mixedXPG; | 
|---|
 | 1775 |                 goto errorMsg; | 
|---|
 | 1776 |             } | 
|---|
 | 1777 |             gotSequential = 1; | 
|---|
 | 1778 |         } | 
|---|
 | 1779 |         if ((objIndex < 0) || (objIndex >= objc)) { | 
|---|
 | 1780 |             msg = badIndex[gotXpg]; | 
|---|
 | 1781 |             goto errorMsg; | 
|---|
 | 1782 |         } | 
|---|
 | 1783 |  | 
|---|
 | 1784 |         /* | 
|---|
 | 1785 |          * Step 2. Set of flags. | 
|---|
 | 1786 |          */ | 
|---|
 | 1787 |  | 
|---|
 | 1788 |         gotMinus = gotHash = gotZero = gotSpace = gotPlus = 0; | 
|---|
 | 1789 |         sawFlag = 1; | 
|---|
 | 1790 |         do { | 
|---|
 | 1791 |             switch (ch) { | 
|---|
 | 1792 |             case '-': | 
|---|
 | 1793 |                 gotMinus = 1; | 
|---|
 | 1794 |                 break; | 
|---|
 | 1795 |             case '#': | 
|---|
 | 1796 |                 gotHash = 1; | 
|---|
 | 1797 |                 break; | 
|---|
 | 1798 |             case '0': | 
|---|
 | 1799 |                 gotZero = 1; | 
|---|
 | 1800 |                 break; | 
|---|
 | 1801 |             case ' ': | 
|---|
 | 1802 |                 gotSpace = 1; | 
|---|
 | 1803 |                 break; | 
|---|
 | 1804 |             case '+': | 
|---|
 | 1805 |                 gotPlus = 1; | 
|---|
 | 1806 |                 break; | 
|---|
 | 1807 |             default: | 
|---|
 | 1808 |                 sawFlag = 0; | 
|---|
 | 1809 |             } | 
|---|
 | 1810 |             if (sawFlag) { | 
|---|
 | 1811 |                 format += step; | 
|---|
 | 1812 |                 step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1813 |             } | 
|---|
 | 1814 |         } while (sawFlag); | 
|---|
 | 1815 |  | 
|---|
 | 1816 |         /* | 
|---|
 | 1817 |          * Step 3. Minimum field width. | 
|---|
 | 1818 |          */ | 
|---|
 | 1819 |  | 
|---|
 | 1820 |         width = 0; | 
|---|
 | 1821 |         if (isdigit(UCHAR(ch))) { | 
|---|
 | 1822 |             width = strtoul(format, &end, 10); | 
|---|
 | 1823 |             format = end; | 
|---|
 | 1824 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1825 |         } else if (ch == '*') { | 
|---|
 | 1826 |             if (objIndex >= objc - 1) { | 
|---|
 | 1827 |                 msg = badIndex[gotXpg]; | 
|---|
 | 1828 |                 goto errorMsg; | 
|---|
 | 1829 |             } | 
|---|
 | 1830 |             if (TclGetIntFromObj(interp, objv[objIndex], &width) != TCL_OK) { | 
|---|
 | 1831 |                 goto error; | 
|---|
 | 1832 |             } | 
|---|
 | 1833 |             if (width < 0) { | 
|---|
 | 1834 |                 width = -width; | 
|---|
 | 1835 |                 gotMinus = 1; | 
|---|
 | 1836 |             } | 
|---|
 | 1837 |             objIndex++; | 
|---|
 | 1838 |             format += step; | 
|---|
 | 1839 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1840 |         } | 
|---|
 | 1841 |  | 
|---|
 | 1842 |         /* | 
|---|
 | 1843 |          * Step 4. Precision. | 
|---|
 | 1844 |          */ | 
|---|
 | 1845 |  | 
|---|
 | 1846 |         gotPrecision = precision = 0; | 
|---|
 | 1847 |         if (ch == '.') { | 
|---|
 | 1848 |             gotPrecision = 1; | 
|---|
 | 1849 |             format += step; | 
|---|
 | 1850 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1851 |         } | 
|---|
 | 1852 |         if (isdigit(UCHAR(ch))) { | 
|---|
 | 1853 |             precision = strtoul(format, &end, 10); | 
|---|
 | 1854 |             format = end; | 
|---|
 | 1855 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1856 |         } else if (ch == '*') { | 
|---|
 | 1857 |             if (objIndex >= objc - 1) { | 
|---|
 | 1858 |                 msg = badIndex[gotXpg]; | 
|---|
 | 1859 |                 goto errorMsg; | 
|---|
 | 1860 |             } | 
|---|
 | 1861 |             if (TclGetIntFromObj(interp, objv[objIndex], &precision) | 
|---|
 | 1862 |                     != TCL_OK) { | 
|---|
 | 1863 |                 goto error; | 
|---|
 | 1864 |             } | 
|---|
 | 1865 |  | 
|---|
 | 1866 |             /* | 
|---|
 | 1867 |              * TODO: Check this truncation logic. | 
|---|
 | 1868 |              */ | 
|---|
 | 1869 |  | 
|---|
 | 1870 |             if (precision < 0) { | 
|---|
 | 1871 |                 precision = 0; | 
|---|
 | 1872 |             } | 
|---|
 | 1873 |             objIndex++; | 
|---|
 | 1874 |             format += step; | 
|---|
 | 1875 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1876 |         } | 
|---|
 | 1877 |  | 
|---|
 | 1878 |         /* | 
|---|
 | 1879 |          * Step 5. Length modifier. | 
|---|
 | 1880 |          */ | 
|---|
 | 1881 |  | 
|---|
 | 1882 |         useShort = useWide = useBig = 0; | 
|---|
 | 1883 |         if (ch == 'h') { | 
|---|
 | 1884 |             useShort = 1; | 
|---|
 | 1885 |             format += step; | 
|---|
 | 1886 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1887 |         } else if (ch == 'l') { | 
|---|
 | 1888 |             format += step; | 
|---|
 | 1889 |             step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1890 |             if (ch == 'l') { | 
|---|
 | 1891 |                 useBig = 1; | 
|---|
 | 1892 |                 format += step; | 
|---|
 | 1893 |                 step = Tcl_UtfToUniChar(format, &ch); | 
|---|
 | 1894 |             } else { | 
|---|
 | 1895 | #ifndef TCL_WIDE_INT_IS_LONG | 
|---|
 | 1896 |                 useWide = 1; | 
|---|
 | 1897 | #endif | 
|---|
 | 1898 |             } | 
|---|
 | 1899 |         } | 
|---|
 | 1900 |  | 
|---|
 | 1901 |         format += step; | 
|---|
 | 1902 |         span = format; | 
|---|
 | 1903 |  | 
|---|
 | 1904 |         /* | 
|---|
 | 1905 |          * Step 6. The actual conversion character. | 
|---|
 | 1906 |          */ | 
|---|
 | 1907 |  | 
|---|
 | 1908 |         segment = objv[objIndex]; | 
|---|
 | 1909 |         if (ch == 'i') { | 
|---|
 | 1910 |             ch = 'd'; | 
|---|
 | 1911 |         } | 
|---|
 | 1912 |         switch (ch) { | 
|---|
 | 1913 |         case '\0': | 
|---|
 | 1914 |             msg = "format string ended in middle of field specifier"; | 
|---|
 | 1915 |             goto errorMsg; | 
|---|
 | 1916 |         case 's': { | 
|---|
 | 1917 |             numChars = Tcl_GetCharLength(segment); | 
|---|
 | 1918 |             if (gotPrecision && (precision < numChars)) { | 
|---|
 | 1919 |                 segment = Tcl_GetRange(segment, 0, precision - 1); | 
|---|
 | 1920 |                 Tcl_IncrRefCount(segment); | 
|---|
 | 1921 |                 allocSegment = 1; | 
|---|
 | 1922 |             } | 
|---|
 | 1923 |             break; | 
|---|
 | 1924 |         } | 
|---|
 | 1925 |         case 'c': { | 
|---|
 | 1926 |             char buf[TCL_UTF_MAX]; | 
|---|
 | 1927 |             int code, length; | 
|---|
 | 1928 |  | 
|---|
 | 1929 |             if (TclGetIntFromObj(interp, segment, &code) != TCL_OK) { | 
|---|
 | 1930 |                 goto error; | 
|---|
 | 1931 |             } | 
|---|
 | 1932 |             length = Tcl_UniCharToUtf(code, buf); | 
|---|
 | 1933 |             segment = Tcl_NewStringObj(buf, length); | 
|---|
 | 1934 |             Tcl_IncrRefCount(segment); | 
|---|
 | 1935 |             allocSegment = 1; | 
|---|
 | 1936 |             break; | 
|---|
 | 1937 |         } | 
|---|
 | 1938 |  | 
|---|
 | 1939 |         case 'u': | 
|---|
 | 1940 |             if (useBig) { | 
|---|
 | 1941 |                 msg = "unsigned bignum format is invalid"; | 
|---|
 | 1942 |                 goto errorMsg; | 
|---|
 | 1943 |             } | 
|---|
 | 1944 |         case 'd': | 
|---|
 | 1945 |         case 'o': | 
|---|
 | 1946 |         case 'x': | 
|---|
 | 1947 |         case 'X': { | 
|---|
 | 1948 |             short int s = 0;    /* Silence compiler warning; only defined and | 
|---|
 | 1949 |                                  * used when useShort is true. */ | 
|---|
 | 1950 |             long l; | 
|---|
 | 1951 |             Tcl_WideInt w; | 
|---|
 | 1952 |             mp_int big; | 
|---|
 | 1953 |             int isNegative = 0; | 
|---|
 | 1954 |  | 
|---|
 | 1955 |             if (useBig) { | 
|---|
 | 1956 |                 if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) { | 
|---|
 | 1957 |                     goto error; | 
|---|
 | 1958 |                 } | 
|---|
 | 1959 |                 isNegative = (mp_cmp_d(&big, 0) == MP_LT); | 
|---|
 | 1960 |             } else if (useWide) { | 
|---|
 | 1961 |                 if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { | 
|---|
 | 1962 |                     Tcl_Obj *objPtr; | 
|---|
 | 1963 |  | 
|---|
 | 1964 |                     if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) { | 
|---|
 | 1965 |                         goto error; | 
|---|
 | 1966 |                     } | 
|---|
 | 1967 |                     mp_mod_2d(&big, (int) CHAR_BIT*sizeof(Tcl_WideInt), &big); | 
|---|
 | 1968 |                     objPtr = Tcl_NewBignumObj(&big); | 
|---|
 | 1969 |                     Tcl_IncrRefCount(objPtr); | 
|---|
 | 1970 |                     Tcl_GetWideIntFromObj(NULL, objPtr, &w); | 
|---|
 | 1971 |                     Tcl_DecrRefCount(objPtr); | 
|---|
 | 1972 |                 } | 
|---|
 | 1973 |                 isNegative = (w < (Tcl_WideInt)0); | 
|---|
 | 1974 |             } else if (TclGetLongFromObj(NULL, segment, &l) != TCL_OK) { | 
|---|
 | 1975 |                 if (Tcl_GetWideIntFromObj(NULL, segment, &w) != TCL_OK) { | 
|---|
 | 1976 |                     Tcl_Obj *objPtr; | 
|---|
 | 1977 |  | 
|---|
 | 1978 |                     if (Tcl_GetBignumFromObj(interp,segment,&big) != TCL_OK) { | 
|---|
 | 1979 |                         goto error; | 
|---|
 | 1980 |                     } | 
|---|
 | 1981 |                     mp_mod_2d(&big, (int) CHAR_BIT * sizeof(long), &big); | 
|---|
 | 1982 |                     objPtr = Tcl_NewBignumObj(&big); | 
|---|
 | 1983 |                     Tcl_IncrRefCount(objPtr); | 
|---|
 | 1984 |                     TclGetLongFromObj(NULL, objPtr, &l); | 
|---|
 | 1985 |                     Tcl_DecrRefCount(objPtr); | 
|---|
 | 1986 |                 } else { | 
|---|
 | 1987 |                     l = Tcl_WideAsLong(w); | 
|---|
 | 1988 |                 } | 
|---|
 | 1989 |                 if (useShort) { | 
|---|
 | 1990 |                     s = (short int) l; | 
|---|
 | 1991 |                     isNegative = (s < (short int)0); | 
|---|
 | 1992 |                 } else { | 
|---|
 | 1993 |                     isNegative = (l < (long)0); | 
|---|
 | 1994 |                 } | 
|---|
 | 1995 |             } else if (useShort) { | 
|---|
 | 1996 |                 s = (short int) l; | 
|---|
 | 1997 |                 isNegative = (s < (short int)0); | 
|---|
 | 1998 |             } else { | 
|---|
 | 1999 |                 isNegative = (l < (long)0); | 
|---|
 | 2000 |             } | 
|---|
 | 2001 |  | 
|---|
 | 2002 |             segment = Tcl_NewObj(); | 
|---|
 | 2003 |             allocSegment = 1; | 
|---|
 | 2004 |             Tcl_IncrRefCount(segment); | 
|---|
 | 2005 |  | 
|---|
 | 2006 |             if ((isNegative || gotPlus) && (useBig || (ch == 'd'))) { | 
|---|
 | 2007 |                 Tcl_AppendToObj(segment, (isNegative ? "-" : "+"), 1); | 
|---|
 | 2008 |             } | 
|---|
 | 2009 |  | 
|---|
 | 2010 |             if (gotHash) { | 
|---|
 | 2011 |                 switch (ch) { | 
|---|
 | 2012 |                 case 'o': | 
|---|
 | 2013 |                     Tcl_AppendToObj(segment, "0", 1); | 
|---|
 | 2014 |                     precision--; | 
|---|
 | 2015 |                     break; | 
|---|
 | 2016 |                 case 'x': | 
|---|
 | 2017 |                 case 'X': | 
|---|
 | 2018 |                     Tcl_AppendToObj(segment, "0x", 2); | 
|---|
 | 2019 |                     break; | 
|---|
 | 2020 |                 } | 
|---|
 | 2021 |             } | 
|---|
 | 2022 |  | 
|---|
 | 2023 |             switch (ch) { | 
|---|
 | 2024 |             case 'd': { | 
|---|
 | 2025 |                 int length; | 
|---|
 | 2026 |                 Tcl_Obj *pure; | 
|---|
 | 2027 |                 const char *bytes; | 
|---|
 | 2028 |  | 
|---|
 | 2029 |                 if (useShort) { | 
|---|
 | 2030 |                     pure = Tcl_NewIntObj((int)(s)); | 
|---|
 | 2031 |                 } else if (useWide) { | 
|---|
 | 2032 |                     pure = Tcl_NewWideIntObj(w); | 
|---|
 | 2033 |                 } else if (useBig) { | 
|---|
 | 2034 |                     pure = Tcl_NewBignumObj(&big); | 
|---|
 | 2035 |                 } else { | 
|---|
 | 2036 |                     pure = Tcl_NewLongObj(l); | 
|---|
 | 2037 |                 } | 
|---|
 | 2038 |                 Tcl_IncrRefCount(pure); | 
|---|
 | 2039 |                 bytes = TclGetStringFromObj(pure, &length); | 
|---|
 | 2040 |  | 
|---|
 | 2041 |                 /* | 
|---|
 | 2042 |                  * Already did the sign above. | 
|---|
 | 2043 |                  */ | 
|---|
 | 2044 |  | 
|---|
 | 2045 |                 if (*bytes == '-') { | 
|---|
 | 2046 |                     length--; | 
|---|
 | 2047 |                     bytes++; | 
|---|
 | 2048 |                 } | 
|---|
 | 2049 |  | 
|---|
 | 2050 |                 /* | 
|---|
 | 2051 |                  * Canonical decimal string reps for integers are composed | 
|---|
 | 2052 |                  * entirely of one-byte encoded characters, so "length" is the | 
|---|
 | 2053 |                  * number of chars. | 
|---|
 | 2054 |                  */ | 
|---|
 | 2055 |  | 
|---|
 | 2056 |                 if (gotPrecision) { | 
|---|
 | 2057 |                     while (length < precision) { | 
|---|
 | 2058 |                         Tcl_AppendToObj(segment, "0", 1); | 
|---|
 | 2059 |                         length++; | 
|---|
 | 2060 |                     } | 
|---|
 | 2061 |                     gotZero = 0; | 
|---|
 | 2062 |                 } | 
|---|
 | 2063 |                 if (gotZero) { | 
|---|
 | 2064 |                     length += Tcl_GetCharLength(segment); | 
|---|
 | 2065 |                     while (length < width) { | 
|---|
 | 2066 |                         Tcl_AppendToObj(segment, "0", 1); | 
|---|
 | 2067 |                         length++; | 
|---|
 | 2068 |                     } | 
|---|
 | 2069 |                 } | 
|---|
 | 2070 |                 Tcl_AppendToObj(segment, bytes, -1); | 
|---|
 | 2071 |                 Tcl_DecrRefCount(pure); | 
|---|
 | 2072 |                 break; | 
|---|
 | 2073 |             } | 
|---|
 | 2074 |  | 
|---|
 | 2075 |             case 'u': | 
|---|
 | 2076 |             case 'o': | 
|---|
 | 2077 |             case 'x': | 
|---|
 | 2078 |             case 'X': { | 
|---|
 | 2079 |                 Tcl_WideUInt bits = (Tcl_WideUInt)0; | 
|---|
 | 2080 |                 int length, numBits = 4, numDigits = 0, base = 16; | 
|---|
 | 2081 |                 int index = 0, shift = 0; | 
|---|
 | 2082 |                 Tcl_Obj *pure; | 
|---|
 | 2083 |                 char *bytes; | 
|---|
 | 2084 |  | 
|---|
 | 2085 |                 if (ch == 'u') { | 
|---|
 | 2086 |                     base = 10; | 
|---|
 | 2087 |                 } | 
|---|
 | 2088 |                 if (ch == 'o') { | 
|---|
 | 2089 |                     base = 8; | 
|---|
 | 2090 |                     numBits = 3; | 
|---|
 | 2091 |                 } | 
|---|
 | 2092 |                 if (useShort) { | 
|---|
 | 2093 |                     unsigned short int us = (unsigned short int) s; | 
|---|
 | 2094 |  | 
|---|
 | 2095 |                     bits = (Tcl_WideUInt) us; | 
|---|
 | 2096 |                     while (us) { | 
|---|
 | 2097 |                         numDigits++; | 
|---|
 | 2098 |                         us /= base; | 
|---|
 | 2099 |                     } | 
|---|
 | 2100 |                 } else if (useWide) { | 
|---|
 | 2101 |                     Tcl_WideUInt uw = (Tcl_WideUInt) w; | 
|---|
 | 2102 |  | 
|---|
 | 2103 |                     bits = uw; | 
|---|
 | 2104 |                     while (uw) { | 
|---|
 | 2105 |                         numDigits++; | 
|---|
 | 2106 |                         uw /= base; | 
|---|
 | 2107 |                     } | 
|---|
 | 2108 |                 } else if (useBig && big.used) { | 
|---|
 | 2109 |                     int leftover = (big.used * DIGIT_BIT) % numBits; | 
|---|
 | 2110 |                     mp_digit mask = (~(mp_digit)0) << (DIGIT_BIT-leftover); | 
|---|
 | 2111 |  | 
|---|
 | 2112 |                     numDigits = 1 + ((big.used * DIGIT_BIT) / numBits); | 
|---|
 | 2113 |                     while ((mask & big.dp[big.used-1]) == 0) { | 
|---|
 | 2114 |                         numDigits--; | 
|---|
 | 2115 |                         mask >>= numBits; | 
|---|
 | 2116 |                     } | 
|---|
 | 2117 |                 } else if (!useBig) { | 
|---|
 | 2118 |                     unsigned long int ul = (unsigned long int) l; | 
|---|
 | 2119 |  | 
|---|
 | 2120 |                     bits = (Tcl_WideUInt) ul; | 
|---|
 | 2121 |                     while (ul) { | 
|---|
 | 2122 |                         numDigits++; | 
|---|
 | 2123 |                         ul /= base; | 
|---|
 | 2124 |                     } | 
|---|
 | 2125 |                 } | 
|---|
 | 2126 |  | 
|---|
 | 2127 |                 /* | 
|---|
 | 2128 |                  * Need to be sure zero becomes "0", not "". | 
|---|
 | 2129 |                  */ | 
|---|
 | 2130 |  | 
|---|
 | 2131 |                 if ((numDigits == 0) && !((ch == 'o') && gotHash)) { | 
|---|
 | 2132 |                     numDigits = 1; | 
|---|
 | 2133 |                 } | 
|---|
 | 2134 |                 pure = Tcl_NewObj(); | 
|---|
 | 2135 |                 Tcl_SetObjLength(pure, numDigits); | 
|---|
 | 2136 |                 bytes = TclGetString(pure); | 
|---|
 | 2137 |                 length = numDigits; | 
|---|
 | 2138 |                 while (numDigits--) { | 
|---|
 | 2139 |                     int digitOffset; | 
|---|
 | 2140 |  | 
|---|
 | 2141 |                     if (useBig && big.used) { | 
|---|
 | 2142 |                         if ((size_t) shift < | 
|---|
 | 2143 |                                 CHAR_BIT*sizeof(Tcl_WideUInt) - DIGIT_BIT) { | 
|---|
 | 2144 |                             bits |= (((Tcl_WideUInt)big.dp[index++]) <<shift); | 
|---|
 | 2145 |                             shift += DIGIT_BIT; | 
|---|
 | 2146 |                         } | 
|---|
 | 2147 |                         shift -= numBits; | 
|---|
 | 2148 |                     } | 
|---|
 | 2149 |                     digitOffset = (int) (bits % base); | 
|---|
 | 2150 |                     if (digitOffset > 9) { | 
|---|
 | 2151 |                         bytes[numDigits] = 'a' + digitOffset - 10; | 
|---|
 | 2152 |                     } else { | 
|---|
 | 2153 |                         bytes[numDigits] = '0' + digitOffset; | 
|---|
 | 2154 |                     } | 
|---|
 | 2155 |                     bits /= base; | 
|---|
 | 2156 |                 } | 
|---|
 | 2157 |                 if (useBig) { | 
|---|
 | 2158 |                     mp_clear(&big); | 
|---|
 | 2159 |                 } | 
|---|
 | 2160 |                 if (gotPrecision) { | 
|---|
 | 2161 |                     while (length < precision) { | 
|---|
 | 2162 |                         Tcl_AppendToObj(segment, "0", 1); | 
|---|
 | 2163 |                         length++; | 
|---|
 | 2164 |                     } | 
|---|
 | 2165 |                     gotZero = 0; | 
|---|
 | 2166 |                 } | 
|---|
 | 2167 |                 if (gotZero) { | 
|---|
 | 2168 |                     length += Tcl_GetCharLength(segment); | 
|---|
 | 2169 |                     while (length < width) { | 
|---|
 | 2170 |                         Tcl_AppendToObj(segment, "0", 1); | 
|---|
 | 2171 |                         length++; | 
|---|
 | 2172 |                     } | 
|---|
 | 2173 |                 } | 
|---|
 | 2174 |                 Tcl_AppendObjToObj(segment, pure); | 
|---|
 | 2175 |                 Tcl_DecrRefCount(pure); | 
|---|
 | 2176 |                 break; | 
|---|
 | 2177 |             } | 
|---|
 | 2178 |  | 
|---|
 | 2179 |             } | 
|---|
 | 2180 |             break; | 
|---|
 | 2181 |         } | 
|---|
 | 2182 |  | 
|---|
 | 2183 |         case 'e': | 
|---|
 | 2184 |         case 'E': | 
|---|
 | 2185 |         case 'f': | 
|---|
 | 2186 |         case 'g': | 
|---|
 | 2187 |         case 'G': { | 
|---|
 | 2188 | #define MAX_FLOAT_SIZE 320 | 
|---|
 | 2189 |             char spec[2*TCL_INTEGER_SPACE + 9], *p = spec; | 
|---|
 | 2190 |             double d; | 
|---|
 | 2191 |             int length = MAX_FLOAT_SIZE; | 
|---|
 | 2192 |             char *bytes; | 
|---|
 | 2193 |  | 
|---|
 | 2194 |             if (Tcl_GetDoubleFromObj(interp, segment, &d) != TCL_OK) { | 
|---|
 | 2195 |                 /* TODO: Figure out ACCEPT_NAN here */ | 
|---|
 | 2196 |                 goto error; | 
|---|
 | 2197 |             } | 
|---|
 | 2198 |             *p++ = '%'; | 
|---|
 | 2199 |             if (gotMinus) { | 
|---|
 | 2200 |                 *p++ = '-'; | 
|---|
 | 2201 |             } | 
|---|
 | 2202 |             if (gotHash) { | 
|---|
 | 2203 |                 *p++ = '#'; | 
|---|
 | 2204 |             } | 
|---|
 | 2205 |             if (gotZero) { | 
|---|
 | 2206 |                 *p++ = '0'; | 
|---|
 | 2207 |             } | 
|---|
 | 2208 |             if (gotSpace) { | 
|---|
 | 2209 |                 *p++ = ' '; | 
|---|
 | 2210 |             } | 
|---|
 | 2211 |             if (gotPlus) { | 
|---|
 | 2212 |                 *p++ = '+'; | 
|---|
 | 2213 |             } | 
|---|
 | 2214 |             if (width) { | 
|---|
 | 2215 |                 p += sprintf(p, "%d", width); | 
|---|
 | 2216 |             } | 
|---|
 | 2217 |             if (gotPrecision) { | 
|---|
 | 2218 |                 *p++ = '.'; | 
|---|
 | 2219 |                 p += sprintf(p, "%d", precision); | 
|---|
 | 2220 |                 length += precision; | 
|---|
 | 2221 |             } | 
|---|
 | 2222 |  | 
|---|
 | 2223 |             /* | 
|---|
 | 2224 |              * Don't pass length modifiers! | 
|---|
 | 2225 |              */ | 
|---|
 | 2226 |  | 
|---|
 | 2227 |             *p++ = (char) ch; | 
|---|
 | 2228 |             *p = '\0'; | 
|---|
 | 2229 |  | 
|---|
 | 2230 |             segment = Tcl_NewObj(); | 
|---|
 | 2231 |             allocSegment = 1; | 
|---|
 | 2232 |             Tcl_SetObjLength(segment, length); | 
|---|
 | 2233 |             bytes = TclGetString(segment); | 
|---|
 | 2234 |             Tcl_SetObjLength(segment, sprintf(bytes, spec, d)); | 
|---|
 | 2235 |             break; | 
|---|
 | 2236 |         } | 
|---|
 | 2237 |         default: | 
|---|
 | 2238 |             if (interp != NULL) { | 
|---|
 | 2239 |                 char buf[40]; | 
|---|
 | 2240 |  | 
|---|
 | 2241 |                 sprintf(buf, "bad field specifier \"%c\"", ch); | 
|---|
 | 2242 |                 Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1)); | 
|---|
 | 2243 |             } | 
|---|
 | 2244 |             goto error; | 
|---|
 | 2245 |         } | 
|---|
 | 2246 |  | 
|---|
 | 2247 |         switch (ch) { | 
|---|
 | 2248 |         case 'E': | 
|---|
 | 2249 |         case 'G': | 
|---|
 | 2250 |         case 'X': { | 
|---|
 | 2251 |             Tcl_SetObjLength(segment, Tcl_UtfToUpper(TclGetString(segment))); | 
|---|
 | 2252 |         } | 
|---|
 | 2253 |         } | 
|---|
 | 2254 |  | 
|---|
 | 2255 |         numChars = Tcl_GetCharLength(segment); | 
|---|
 | 2256 |         if (!gotMinus) { | 
|---|
 | 2257 |             while (numChars < width) { | 
|---|
 | 2258 |                 Tcl_AppendToObj(appendObj, (gotZero ? "0" : " "), 1); | 
|---|
 | 2259 |                 numChars++; | 
|---|
 | 2260 |             } | 
|---|
 | 2261 |         } | 
|---|
 | 2262 |         Tcl_AppendObjToObj(appendObj, segment); | 
|---|
 | 2263 |         if (allocSegment) { | 
|---|
 | 2264 |             Tcl_DecrRefCount(segment); | 
|---|
 | 2265 |         } | 
|---|
 | 2266 |         while (numChars < width) { | 
|---|
 | 2267 |             Tcl_AppendToObj(appendObj, (gotZero ? "0" : " "), 1); | 
|---|
 | 2268 |             numChars++; | 
|---|
 | 2269 |         } | 
|---|
 | 2270 |  | 
|---|
 | 2271 |         objIndex += gotSequential; | 
|---|
 | 2272 |     } | 
|---|
 | 2273 |     if (numBytes) { | 
|---|
 | 2274 |         Tcl_AppendToObj(appendObj, span, numBytes); | 
|---|
 | 2275 |         numBytes = 0; | 
|---|
 | 2276 |     } | 
|---|
 | 2277 |  | 
|---|
 | 2278 |     return TCL_OK; | 
|---|
 | 2279 |  | 
|---|
 | 2280 |   errorMsg: | 
|---|
 | 2281 |     if (interp != NULL) { | 
|---|
 | 2282 |         Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); | 
|---|
 | 2283 |     } | 
|---|
 | 2284 |   error: | 
|---|
 | 2285 |     Tcl_SetObjLength(appendObj, originalLength); | 
|---|
 | 2286 |     return TCL_ERROR; | 
|---|
 | 2287 | } | 
|---|
 | 2288 |  | 
|---|
 | 2289 | /* | 
|---|
 | 2290 |  *--------------------------------------------------------------------------- | 
|---|
 | 2291 |  * | 
|---|
 | 2292 |  * Tcl_Format-- | 
|---|
 | 2293 |  * | 
|---|
 | 2294 |  * Results: | 
|---|
 | 2295 |  *      A refcount zero Tcl_Obj. | 
|---|
 | 2296 |  * | 
|---|
 | 2297 |  * Side effects: | 
|---|
 | 2298 |  *      None. | 
|---|
 | 2299 |  * | 
|---|
 | 2300 |  *--------------------------------------------------------------------------- | 
|---|
 | 2301 |  */ | 
|---|
 | 2302 |  | 
|---|
 | 2303 | Tcl_Obj * | 
|---|
 | 2304 | Tcl_Format( | 
|---|
 | 2305 |     Tcl_Interp *interp, | 
|---|
 | 2306 |     const char *format, | 
|---|
 | 2307 |     int objc, | 
|---|
 | 2308 |     Tcl_Obj *const objv[]) | 
|---|
 | 2309 | { | 
|---|
 | 2310 |     int result; | 
|---|
 | 2311 |     Tcl_Obj *objPtr = Tcl_NewObj(); | 
|---|
 | 2312 |     result = Tcl_AppendFormatToObj(interp, objPtr, format, objc, objv); | 
|---|
 | 2313 |     if (result != TCL_OK) { | 
|---|
 | 2314 |         Tcl_DecrRefCount(objPtr); | 
|---|
 | 2315 |         return NULL; | 
|---|
 | 2316 |     } | 
|---|
 | 2317 |     return objPtr; | 
|---|
 | 2318 | } | 
|---|
 | 2319 |  | 
|---|
 | 2320 | /* | 
|---|
 | 2321 |  *--------------------------------------------------------------------------- | 
|---|
 | 2322 |  * | 
|---|
 | 2323 |  * AppendPrintfToObjVA -- | 
|---|
 | 2324 |  * | 
|---|
 | 2325 |  * Results: | 
|---|
 | 2326 |  * | 
|---|
 | 2327 |  * Side effects: | 
|---|
 | 2328 |  * | 
|---|
 | 2329 |  *--------------------------------------------------------------------------- | 
|---|
 | 2330 |  */ | 
|---|
 | 2331 |  | 
|---|
 | 2332 | static void | 
|---|
 | 2333 | AppendPrintfToObjVA( | 
|---|
 | 2334 |     Tcl_Obj *objPtr, | 
|---|
 | 2335 |     const char *format, | 
|---|
 | 2336 |     va_list argList) | 
|---|
 | 2337 | { | 
|---|
 | 2338 |     int code, objc; | 
|---|
 | 2339 |     Tcl_Obj **objv, *list = Tcl_NewObj(); | 
|---|
 | 2340 |     const char *p; | 
|---|
 | 2341 |     char *end; | 
|---|
 | 2342 |  | 
|---|
 | 2343 |     p = format; | 
|---|
 | 2344 |     Tcl_IncrRefCount(list); | 
|---|
 | 2345 |     while (*p != '\0') { | 
|---|
 | 2346 |         int size = 0, seekingConversion = 1, gotPrecision = 0; | 
|---|
 | 2347 |         int lastNum = -1; | 
|---|
 | 2348 |  | 
|---|
 | 2349 |         if (*p++ != '%') { | 
|---|
 | 2350 |             continue; | 
|---|
 | 2351 |         } | 
|---|
 | 2352 |         if (*p == '%') { | 
|---|
 | 2353 |             p++; | 
|---|
 | 2354 |             continue; | 
|---|
 | 2355 |         } | 
|---|
 | 2356 |         do { | 
|---|
 | 2357 |             switch (*p) { | 
|---|
 | 2358 |  | 
|---|
 | 2359 |             case '\0': | 
|---|
 | 2360 |                 seekingConversion = 0; | 
|---|
 | 2361 |                 break; | 
|---|
 | 2362 |             case 's': { | 
|---|
 | 2363 |                 const char *q, *end, *bytes = va_arg(argList, char *); | 
|---|
 | 2364 |                 seekingConversion = 0; | 
|---|
 | 2365 |  | 
|---|
 | 2366 |                 /* | 
|---|
 | 2367 |                  * The buffer to copy characters from starts at bytes and ends | 
|---|
 | 2368 |                  * at either the first NUL byte, or after lastNum bytes, when | 
|---|
 | 2369 |                  * caller has indicated a limit. | 
|---|
 | 2370 |                  */ | 
|---|
 | 2371 |  | 
|---|
 | 2372 |                 end = bytes; | 
|---|
 | 2373 |                 while ((!gotPrecision || lastNum--) && (*end != '\0')) { | 
|---|
 | 2374 |                     end++; | 
|---|
 | 2375 |                 } | 
|---|
 | 2376 |  | 
|---|
 | 2377 |                 /* | 
|---|
 | 2378 |                  * Within that buffer, we trim both ends if needed so that we | 
|---|
 | 2379 |                  * copy only whole characters, and avoid copying any partial | 
|---|
 | 2380 |                  * multi-byte characters. | 
|---|
 | 2381 |                  */ | 
|---|
 | 2382 |  | 
|---|
 | 2383 |                 q = Tcl_UtfPrev(end, bytes); | 
|---|
 | 2384 |                 if (!Tcl_UtfCharComplete(q, (int)(end - q))) { | 
|---|
 | 2385 |                     end = q; | 
|---|
 | 2386 |                 } | 
|---|
 | 2387 |  | 
|---|
 | 2388 |                 q = bytes + TCL_UTF_MAX; | 
|---|
 | 2389 |                 while ((bytes < end) && (bytes < q) | 
|---|
 | 2390 |                         && ((*bytes & 0xC0) == 0x80)) { | 
|---|
 | 2391 |                     bytes++; | 
|---|
 | 2392 |                 } | 
|---|
 | 2393 |  | 
|---|
 | 2394 |                 Tcl_ListObjAppendElement(NULL, list, | 
|---|
 | 2395 |                         Tcl_NewStringObj(bytes , (int)(end - bytes))); | 
|---|
 | 2396 |  | 
|---|
 | 2397 |                 break; | 
|---|
 | 2398 |             } | 
|---|
 | 2399 |             case 'c': | 
|---|
 | 2400 |             case 'i': | 
|---|
 | 2401 |             case 'u': | 
|---|
 | 2402 |             case 'd': | 
|---|
 | 2403 |             case 'o': | 
|---|
 | 2404 |             case 'x': | 
|---|
 | 2405 |             case 'X': | 
|---|
 | 2406 |                 seekingConversion = 0; | 
|---|
 | 2407 |                 switch (size) { | 
|---|
 | 2408 |                 case -1: | 
|---|
 | 2409 |                 case 0: | 
|---|
 | 2410 |                     Tcl_ListObjAppendElement(NULL, list, Tcl_NewLongObj( | 
|---|
 | 2411 |                             (long int)va_arg(argList, int))); | 
|---|
 | 2412 |                     break; | 
|---|
 | 2413 |                 case 1: | 
|---|
 | 2414 |                     Tcl_ListObjAppendElement(NULL, list, Tcl_NewLongObj( | 
|---|
 | 2415 |                             va_arg(argList, long int))); | 
|---|
 | 2416 |                     break; | 
|---|
 | 2417 |                 } | 
|---|
 | 2418 |                 break; | 
|---|
 | 2419 |             case 'e': | 
|---|
 | 2420 |             case 'E': | 
|---|
 | 2421 |             case 'f': | 
|---|
 | 2422 |             case 'g': | 
|---|
 | 2423 |             case 'G': | 
|---|
 | 2424 |                 Tcl_ListObjAppendElement(NULL, list, Tcl_NewDoubleObj( | 
|---|
 | 2425 |                         va_arg(argList, double))); | 
|---|
 | 2426 |                 seekingConversion = 0; | 
|---|
 | 2427 |                 break; | 
|---|
 | 2428 |             case '*': | 
|---|
 | 2429 |                 lastNum = (int)va_arg(argList, int); | 
|---|
 | 2430 |                 Tcl_ListObjAppendElement(NULL, list, Tcl_NewIntObj(lastNum)); | 
|---|
 | 2431 |                 p++; | 
|---|
 | 2432 |                 break; | 
|---|
 | 2433 |             case '0': case '1': case '2': case '3': case '4': | 
|---|
 | 2434 |             case '5': case '6': case '7': case '8': case '9': | 
|---|
 | 2435 |                 lastNum = (int) strtoul(p, &end, 10); | 
|---|
 | 2436 |                 p = end; | 
|---|
 | 2437 |                 break; | 
|---|
 | 2438 |             case '.': | 
|---|
 | 2439 |                 gotPrecision = 1; | 
|---|
 | 2440 |                 p++; | 
|---|
 | 2441 |                 break; | 
|---|
 | 2442 |             /* TODO: support for wide (and bignum?) arguments */ | 
|---|
 | 2443 |             case 'l': | 
|---|
 | 2444 |                 size = 1; | 
|---|
 | 2445 |                 p++; | 
|---|
 | 2446 |                 break; | 
|---|
 | 2447 |             case 'h': | 
|---|
 | 2448 |                 size = -1; | 
|---|
 | 2449 |             default: | 
|---|
 | 2450 |                 p++; | 
|---|
 | 2451 |             } | 
|---|
 | 2452 |         } while (seekingConversion); | 
|---|
 | 2453 |     } | 
|---|
 | 2454 |     TclListObjGetElements(NULL, list, &objc, &objv); | 
|---|
 | 2455 |     code = Tcl_AppendFormatToObj(NULL, objPtr, format, objc, objv); | 
|---|
 | 2456 |     if (code != TCL_OK) { | 
|---|
 | 2457 |         Tcl_AppendPrintfToObj(objPtr, | 
|---|
 | 2458 |                 "Unable to format \"%s\" with supplied arguments: %s", | 
|---|
 | 2459 |                 format, Tcl_GetString(list)); | 
|---|
 | 2460 |     } | 
|---|
 | 2461 |     Tcl_DecrRefCount(list); | 
|---|
 | 2462 | } | 
|---|
 | 2463 |  | 
|---|
 | 2464 | /* | 
|---|
 | 2465 |  *--------------------------------------------------------------------------- | 
|---|
 | 2466 |  * | 
|---|
 | 2467 |  * Tcl_AppendPrintfToObj -- | 
|---|
 | 2468 |  * | 
|---|
 | 2469 |  * Results: | 
|---|
 | 2470 |  *      A standard Tcl result. | 
|---|
 | 2471 |  * | 
|---|
 | 2472 |  * Side effects: | 
|---|
 | 2473 |  *      None. | 
|---|
 | 2474 |  * | 
|---|
 | 2475 |  *--------------------------------------------------------------------------- | 
|---|
 | 2476 |  */ | 
|---|
 | 2477 |  | 
|---|
 | 2478 | void | 
|---|
 | 2479 | Tcl_AppendPrintfToObj( | 
|---|
 | 2480 |     Tcl_Obj *objPtr, | 
|---|
 | 2481 |     const char *format, | 
|---|
 | 2482 |     ...) | 
|---|
 | 2483 | { | 
|---|
 | 2484 |     va_list argList; | 
|---|
 | 2485 |  | 
|---|
 | 2486 |     va_start(argList, format); | 
|---|
 | 2487 |     AppendPrintfToObjVA(objPtr, format, argList); | 
|---|
 | 2488 |     va_end(argList); | 
|---|
 | 2489 | } | 
|---|
 | 2490 |  | 
|---|
 | 2491 | /* | 
|---|
 | 2492 |  *--------------------------------------------------------------------------- | 
|---|
 | 2493 |  * | 
|---|
 | 2494 |  * Tcl_ObjPrintf -- | 
|---|
 | 2495 |  * | 
|---|
 | 2496 |  * Results: | 
|---|
 | 2497 |  *      A refcount zero Tcl_Obj. | 
|---|
 | 2498 |  * | 
|---|
 | 2499 |  * Side effects: | 
|---|
 | 2500 |  *      None. | 
|---|
 | 2501 |  * | 
|---|
 | 2502 |  *--------------------------------------------------------------------------- | 
|---|
 | 2503 |  */ | 
|---|
 | 2504 |  | 
|---|
 | 2505 | Tcl_Obj * | 
|---|
 | 2506 | Tcl_ObjPrintf( | 
|---|
 | 2507 |     const char *format, | 
|---|
 | 2508 |     ...) | 
|---|
 | 2509 | { | 
|---|
 | 2510 |     va_list argList; | 
|---|
 | 2511 |     Tcl_Obj *objPtr = Tcl_NewObj(); | 
|---|
 | 2512 |  | 
|---|
 | 2513 |     va_start(argList, format); | 
|---|
 | 2514 |     AppendPrintfToObjVA(objPtr, format, argList); | 
|---|
 | 2515 |     va_end(argList); | 
|---|
 | 2516 |     return objPtr; | 
|---|
 | 2517 | } | 
|---|
 | 2518 |  | 
|---|
 | 2519 | /* | 
|---|
 | 2520 |  *--------------------------------------------------------------------------- | 
|---|
 | 2521 |  * | 
|---|
 | 2522 |  * TclStringObjReverse -- | 
|---|
 | 2523 |  * | 
|---|
 | 2524 |  *      Implements the [string reverse] operation. | 
|---|
 | 2525 |  * | 
|---|
 | 2526 |  * Results: | 
|---|
 | 2527 |  *      An unshared Tcl value which is the [string reverse] of the argument | 
|---|
 | 2528 |  *      supplied.  When sharing rules permit, the returned value might be | 
|---|
 | 2529 |  *      the argument with modifications done in place. | 
|---|
 | 2530 |  * | 
|---|
 | 2531 |  * Side effects: | 
|---|
 | 2532 |  *      May allocate a new Tcl_Obj. | 
|---|
 | 2533 |  * | 
|---|
 | 2534 |  *--------------------------------------------------------------------------- | 
|---|
 | 2535 |  */ | 
|---|
 | 2536 |  | 
|---|
 | 2537 | Tcl_Obj * | 
|---|
 | 2538 | TclStringObjReverse( | 
|---|
 | 2539 |     Tcl_Obj *objPtr) | 
|---|
 | 2540 | { | 
|---|
 | 2541 |     String *stringPtr; | 
|---|
 | 2542 |     int numChars = Tcl_GetCharLength(objPtr); | 
|---|
 | 2543 |     int i = 0, lastCharIdx = numChars - 1; | 
|---|
 | 2544 |     char *bytes; | 
|---|
 | 2545 |  | 
|---|
 | 2546 |     if (numChars <= 1) { | 
|---|
 | 2547 |         return objPtr; | 
|---|
 | 2548 |     } | 
|---|
 | 2549 |  | 
|---|
 | 2550 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 2551 |     if (stringPtr->hasUnicode) { | 
|---|
 | 2552 |         Tcl_UniChar *source = stringPtr->unicode; | 
|---|
 | 2553 |  | 
|---|
 | 2554 |         if (Tcl_IsShared(objPtr)) { | 
|---|
 | 2555 |             Tcl_UniChar *dest, ch = 0; | 
|---|
 | 2556 |  | 
|---|
 | 2557 |             /* | 
|---|
 | 2558 |              * Create a non-empty, pure unicode value, so we can coax | 
|---|
 | 2559 |              * Tcl_SetObjLength into growing the unicode rep buffer. | 
|---|
 | 2560 |              */ | 
|---|
 | 2561 |  | 
|---|
 | 2562 |             Tcl_Obj *resultPtr = Tcl_NewUnicodeObj(&ch, 1); | 
|---|
 | 2563 |             Tcl_SetObjLength(resultPtr, numChars); | 
|---|
 | 2564 |             dest = Tcl_GetUnicode(resultPtr); | 
|---|
 | 2565 |  | 
|---|
 | 2566 |             while (i < numChars) { | 
|---|
 | 2567 |                 dest[i++] = source[lastCharIdx--]; | 
|---|
 | 2568 |             } | 
|---|
 | 2569 |             return resultPtr; | 
|---|
 | 2570 |         } | 
|---|
 | 2571 |  | 
|---|
 | 2572 |         while (i < lastCharIdx) { | 
|---|
 | 2573 |             Tcl_UniChar tmp = source[lastCharIdx]; | 
|---|
 | 2574 |             source[lastCharIdx--] = source[i]; | 
|---|
 | 2575 |             source[i++] = tmp; | 
|---|
 | 2576 |         } | 
|---|
 | 2577 |         Tcl_InvalidateStringRep(objPtr); | 
|---|
 | 2578 |         return objPtr; | 
|---|
 | 2579 |     } | 
|---|
 | 2580 |  | 
|---|
 | 2581 |     bytes = TclGetString(objPtr); | 
|---|
 | 2582 |     if (Tcl_IsShared(objPtr)) { | 
|---|
 | 2583 |         char *dest; | 
|---|
 | 2584 |         Tcl_Obj *resultPtr = Tcl_NewObj(); | 
|---|
 | 2585 |         Tcl_SetObjLength(resultPtr, numChars); | 
|---|
 | 2586 |         dest = TclGetString(resultPtr); | 
|---|
 | 2587 |         while (i < numChars) { | 
|---|
 | 2588 |             dest[i++] = bytes[lastCharIdx--]; | 
|---|
 | 2589 |         } | 
|---|
 | 2590 |         return resultPtr; | 
|---|
 | 2591 |     } | 
|---|
 | 2592 |  | 
|---|
 | 2593 |     while (i < lastCharIdx) { | 
|---|
 | 2594 |         char tmp = bytes[lastCharIdx]; | 
|---|
 | 2595 |         bytes[lastCharIdx--] = bytes[i]; | 
|---|
 | 2596 |         bytes[i++] = tmp; | 
|---|
 | 2597 |     } | 
|---|
 | 2598 |     return objPtr; | 
|---|
 | 2599 | } | 
|---|
 | 2600 |  | 
|---|
 | 2601 | /* | 
|---|
 | 2602 |  *--------------------------------------------------------------------------- | 
|---|
 | 2603 |  * | 
|---|
 | 2604 |  * FillUnicodeRep -- | 
|---|
 | 2605 |  * | 
|---|
 | 2606 |  *      Populate the Unicode internal rep with the Unicode form of its string | 
|---|
 | 2607 |  *      rep. The object must alread have a "String" internal rep. | 
|---|
 | 2608 |  * | 
|---|
 | 2609 |  * Results: | 
|---|
 | 2610 |  *      None. | 
|---|
 | 2611 |  * | 
|---|
 | 2612 |  * Side effects: | 
|---|
 | 2613 |  *      Reallocates the String internal rep. | 
|---|
 | 2614 |  * | 
|---|
 | 2615 |  *--------------------------------------------------------------------------- | 
|---|
 | 2616 |  */ | 
|---|
 | 2617 |  | 
|---|
 | 2618 | static void | 
|---|
 | 2619 | FillUnicodeRep( | 
|---|
 | 2620 |     Tcl_Obj *objPtr)            /* The object in which to fill the unicode | 
|---|
 | 2621 |                                  * rep. */ | 
|---|
 | 2622 | { | 
|---|
 | 2623 |     String *stringPtr; | 
|---|
 | 2624 |     size_t uallocated; | 
|---|
 | 2625 |     char *srcEnd, *src = objPtr->bytes; | 
|---|
 | 2626 |     Tcl_UniChar *dst; | 
|---|
 | 2627 |  | 
|---|
 | 2628 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 2629 |     if (stringPtr->numChars == -1) { | 
|---|
 | 2630 |         stringPtr->numChars = Tcl_NumUtfChars(src, objPtr->length); | 
|---|
 | 2631 |     } | 
|---|
 | 2632 |     stringPtr->hasUnicode = (stringPtr->numChars > 0); | 
|---|
 | 2633 |  | 
|---|
 | 2634 |     uallocated = STRING_UALLOC(stringPtr->numChars); | 
|---|
 | 2635 |     if (uallocated > stringPtr->uallocated) { | 
|---|
 | 2636 |         /* | 
|---|
 | 2637 |          * If not enough space has been allocated for the unicode rep, | 
|---|
 | 2638 |          * reallocate the internal rep object. | 
|---|
 | 2639 |          * | 
|---|
 | 2640 |          * There isn't currently enough space in the Unicode representation so | 
|---|
 | 2641 |          * allocate additional space. If the current Unicode representation | 
|---|
 | 2642 |          * isn't empty (i.e. it looks like we've done some appends) then | 
|---|
 | 2643 |          * overallocate the space so that we won't have to do as much | 
|---|
 | 2644 |          * reallocation in the future. | 
|---|
 | 2645 |          */ | 
|---|
 | 2646 |  | 
|---|
 | 2647 |         if (stringPtr->uallocated > 0) { | 
|---|
 | 2648 |             uallocated *= 2; | 
|---|
 | 2649 |         } | 
|---|
 | 2650 |         stringPtr = (String *) ckrealloc((char*) stringPtr, | 
|---|
 | 2651 |                 STRING_SIZE(uallocated)); | 
|---|
 | 2652 |         stringPtr->uallocated = uallocated; | 
|---|
 | 2653 |     } | 
|---|
 | 2654 |  | 
|---|
 | 2655 |     /* | 
|---|
 | 2656 |      * Convert src to Unicode and store the coverted data in "unicode". | 
|---|
 | 2657 |      */ | 
|---|
 | 2658 |  | 
|---|
 | 2659 |     srcEnd = src + objPtr->length; | 
|---|
 | 2660 |     for (dst = stringPtr->unicode; src < srcEnd; dst++) { | 
|---|
 | 2661 |         src += TclUtfToUniChar(src, dst); | 
|---|
 | 2662 |     } | 
|---|
 | 2663 |     *dst = 0; | 
|---|
 | 2664 |  | 
|---|
 | 2665 |     SET_STRING(objPtr, stringPtr); | 
|---|
 | 2666 | } | 
|---|
 | 2667 |  | 
|---|
 | 2668 | /* | 
|---|
 | 2669 |  *---------------------------------------------------------------------- | 
|---|
 | 2670 |  * | 
|---|
 | 2671 |  * DupStringInternalRep -- | 
|---|
 | 2672 |  * | 
|---|
 | 2673 |  *      Initialize the internal representation of a new Tcl_Obj to a copy of | 
|---|
 | 2674 |  *      the internal representation of an existing string object. | 
|---|
 | 2675 |  * | 
|---|
 | 2676 |  * Results: | 
|---|
 | 2677 |  *      None. | 
|---|
 | 2678 |  * | 
|---|
 | 2679 |  * Side effects: | 
|---|
 | 2680 |  *      copyPtr's internal rep is set to a copy of srcPtr's internal | 
|---|
 | 2681 |  *      representation. | 
|---|
 | 2682 |  * | 
|---|
 | 2683 |  *---------------------------------------------------------------------- | 
|---|
 | 2684 |  */ | 
|---|
 | 2685 |  | 
|---|
 | 2686 | static void | 
|---|
 | 2687 | DupStringInternalRep( | 
|---|
 | 2688 |     register Tcl_Obj *srcPtr,   /* Object with internal rep to copy. Must have | 
|---|
 | 2689 |                                  * an internal rep of type "String". */ | 
|---|
 | 2690 |     register Tcl_Obj *copyPtr)  /* Object with internal rep to set. Must not | 
|---|
 | 2691 |                                  * currently have an internal rep.*/ | 
|---|
 | 2692 | { | 
|---|
 | 2693 |     String *srcStringPtr = GET_STRING(srcPtr); | 
|---|
 | 2694 |     String *copyStringPtr = NULL; | 
|---|
 | 2695 |  | 
|---|
 | 2696 |     /* | 
|---|
 | 2697 |      * If the src obj is a string of 1-byte Utf chars, then copy the string | 
|---|
 | 2698 |      * rep of the source object and create an "empty" Unicode internal rep for | 
|---|
 | 2699 |      * the new object. Otherwise, copy Unicode internal rep, and invalidate | 
|---|
 | 2700 |      * the string rep of the new object. | 
|---|
 | 2701 |      */ | 
|---|
 | 2702 |  | 
|---|
 | 2703 |     if (srcStringPtr->hasUnicode == 0) { | 
|---|
 | 2704 |         copyStringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0))); | 
|---|
 | 2705 |         copyStringPtr->uallocated = STRING_UALLOC(0); | 
|---|
 | 2706 |     } else { | 
|---|
 | 2707 |         copyStringPtr = (String *) ckalloc( | 
|---|
 | 2708 |                 STRING_SIZE(srcStringPtr->uallocated)); | 
|---|
 | 2709 |         copyStringPtr->uallocated = srcStringPtr->uallocated; | 
|---|
 | 2710 |  | 
|---|
 | 2711 |         memcpy(copyStringPtr->unicode, srcStringPtr->unicode, | 
|---|
 | 2712 |                 (size_t) srcStringPtr->numChars * sizeof(Tcl_UniChar)); | 
|---|
 | 2713 |         copyStringPtr->unicode[srcStringPtr->numChars] = 0; | 
|---|
 | 2714 |     } | 
|---|
 | 2715 |     copyStringPtr->numChars = srcStringPtr->numChars; | 
|---|
 | 2716 |     copyStringPtr->hasUnicode = srcStringPtr->hasUnicode; | 
|---|
 | 2717 |     copyStringPtr->allocated = srcStringPtr->allocated; | 
|---|
 | 2718 |  | 
|---|
 | 2719 |     /* | 
|---|
 | 2720 |      * Tricky point: the string value was copied by generic object management | 
|---|
 | 2721 |      * code, so it doesn't contain any extra bytes that might exist in the | 
|---|
 | 2722 |      * source object. | 
|---|
 | 2723 |      */ | 
|---|
 | 2724 |  | 
|---|
 | 2725 |     copyStringPtr->allocated = copyPtr->length; | 
|---|
 | 2726 |  | 
|---|
 | 2727 |     SET_STRING(copyPtr, copyStringPtr); | 
|---|
 | 2728 |     copyPtr->typePtr = &tclStringType; | 
|---|
 | 2729 | } | 
|---|
 | 2730 |  | 
|---|
 | 2731 | /* | 
|---|
 | 2732 |  *---------------------------------------------------------------------- | 
|---|
 | 2733 |  * | 
|---|
 | 2734 |  * SetStringFromAny -- | 
|---|
 | 2735 |  * | 
|---|
 | 2736 |  *      Create an internal representation of type "String" for an object. | 
|---|
 | 2737 |  * | 
|---|
 | 2738 |  * Results: | 
|---|
 | 2739 |  *      This operation always succeeds and returns TCL_OK. | 
|---|
 | 2740 |  * | 
|---|
 | 2741 |  * Side effects: | 
|---|
 | 2742 |  *      Any old internal reputation for objPtr is freed and the internal | 
|---|
 | 2743 |  *      representation is set to "String". | 
|---|
 | 2744 |  * | 
|---|
 | 2745 |  *---------------------------------------------------------------------- | 
|---|
 | 2746 |  */ | 
|---|
 | 2747 |  | 
|---|
 | 2748 | static int | 
|---|
 | 2749 | SetStringFromAny( | 
|---|
 | 2750 |     Tcl_Interp *interp,         /* Used for error reporting if not NULL. */ | 
|---|
 | 2751 |     register Tcl_Obj *objPtr)   /* The object to convert. */ | 
|---|
 | 2752 | { | 
|---|
 | 2753 |     /* | 
|---|
 | 2754 |      * The Unicode object is optimized for the case where each UTF char in a | 
|---|
 | 2755 |      * string is only one byte. In this case, we store the value of numChars, | 
|---|
 | 2756 |      * but we don't copy the bytes to the unicodeObj->unicode. | 
|---|
 | 2757 |      */ | 
|---|
 | 2758 |  | 
|---|
 | 2759 |     if (objPtr->typePtr != &tclStringType) { | 
|---|
 | 2760 |         String *stringPtr; | 
|---|
 | 2761 |  | 
|---|
 | 2762 |         if (objPtr->typePtr != NULL) { | 
|---|
 | 2763 |             if (objPtr->bytes == NULL) { | 
|---|
 | 2764 |                 objPtr->typePtr->updateStringProc(objPtr); | 
|---|
 | 2765 |             } | 
|---|
 | 2766 |             TclFreeIntRep(objPtr); | 
|---|
 | 2767 |         } | 
|---|
 | 2768 |         objPtr->typePtr = &tclStringType; | 
|---|
 | 2769 |  | 
|---|
 | 2770 |         /* | 
|---|
 | 2771 |          * Allocate enough space for the basic String structure. | 
|---|
 | 2772 |          */ | 
|---|
 | 2773 |  | 
|---|
 | 2774 |         stringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0))); | 
|---|
 | 2775 |         stringPtr->numChars = -1; | 
|---|
 | 2776 |         stringPtr->uallocated = STRING_UALLOC(0); | 
|---|
 | 2777 |         stringPtr->hasUnicode = 0; | 
|---|
 | 2778 |  | 
|---|
 | 2779 |         if (objPtr->bytes != NULL) { | 
|---|
 | 2780 |             stringPtr->allocated = objPtr->length; | 
|---|
 | 2781 |             objPtr->bytes[objPtr->length] = 0; | 
|---|
 | 2782 |         } else { | 
|---|
 | 2783 |             objPtr->length = 0; | 
|---|
 | 2784 |         } | 
|---|
 | 2785 |         SET_STRING(objPtr, stringPtr); | 
|---|
 | 2786 |     } | 
|---|
 | 2787 |     return TCL_OK; | 
|---|
 | 2788 | } | 
|---|
 | 2789 |  | 
|---|
 | 2790 | /* | 
|---|
 | 2791 |  *---------------------------------------------------------------------- | 
|---|
 | 2792 |  * | 
|---|
 | 2793 |  * UpdateStringOfString -- | 
|---|
 | 2794 |  * | 
|---|
 | 2795 |  *      Update the string representation for an object whose internal | 
|---|
 | 2796 |  *      representation is "String". | 
|---|
 | 2797 |  * | 
|---|
 | 2798 |  * Results: | 
|---|
 | 2799 |  *      None. | 
|---|
 | 2800 |  * | 
|---|
 | 2801 |  * Side effects: | 
|---|
 | 2802 |  *      The object's string may be set by converting its Unicode represention | 
|---|
 | 2803 |  *      to UTF format. | 
|---|
 | 2804 |  * | 
|---|
 | 2805 |  *---------------------------------------------------------------------- | 
|---|
 | 2806 |  */ | 
|---|
 | 2807 |  | 
|---|
 | 2808 | static void | 
|---|
 | 2809 | UpdateStringOfString( | 
|---|
 | 2810 |     Tcl_Obj *objPtr)            /* Object with string rep to update. */ | 
|---|
 | 2811 | { | 
|---|
 | 2812 |     int i, size; | 
|---|
 | 2813 |     Tcl_UniChar *unicode; | 
|---|
 | 2814 |     char dummy[TCL_UTF_MAX]; | 
|---|
 | 2815 |     char *dst; | 
|---|
 | 2816 |     String *stringPtr; | 
|---|
 | 2817 |  | 
|---|
 | 2818 |     stringPtr = GET_STRING(objPtr); | 
|---|
 | 2819 |     if ((objPtr->bytes == NULL) || (stringPtr->allocated == 0)) { | 
|---|
 | 2820 |         if (stringPtr->numChars <= 0) { | 
|---|
 | 2821 |             /* | 
|---|
 | 2822 |              * If there is no Unicode rep, or the string has 0 chars, then set | 
|---|
 | 2823 |              * the string rep to an empty string. | 
|---|
 | 2824 |              */ | 
|---|
 | 2825 |  | 
|---|
 | 2826 |             objPtr->bytes = tclEmptyStringRep; | 
|---|
 | 2827 |             objPtr->length = 0; | 
|---|
 | 2828 |             return; | 
|---|
 | 2829 |         } | 
|---|
 | 2830 |  | 
|---|
 | 2831 |         unicode = stringPtr->unicode; | 
|---|
 | 2832 |  | 
|---|
 | 2833 |         /* | 
|---|
 | 2834 |          * Translate the Unicode string to UTF. "size" will hold the amount of | 
|---|
 | 2835 |          * space the UTF string needs. | 
|---|
 | 2836 |          */ | 
|---|
 | 2837 |  | 
|---|
 | 2838 |         size = 0; | 
|---|
 | 2839 |         for (i = 0; i < stringPtr->numChars; i++) { | 
|---|
 | 2840 |             size += Tcl_UniCharToUtf((int) unicode[i], dummy); | 
|---|
 | 2841 |         } | 
|---|
 | 2842 |  | 
|---|
 | 2843 |         dst = (char *) ckalloc((unsigned) (size + 1)); | 
|---|
 | 2844 |         objPtr->bytes = dst; | 
|---|
 | 2845 |         objPtr->length = size; | 
|---|
 | 2846 |         stringPtr->allocated = size; | 
|---|
 | 2847 |  | 
|---|
 | 2848 |         for (i = 0; i < stringPtr->numChars; i++) { | 
|---|
 | 2849 |             dst += Tcl_UniCharToUtf(unicode[i], dst); | 
|---|
 | 2850 |         } | 
|---|
 | 2851 |         *dst = '\0'; | 
|---|
 | 2852 |     } | 
|---|
 | 2853 |     return; | 
|---|
 | 2854 | } | 
|---|
 | 2855 |  | 
|---|
 | 2856 | /* | 
|---|
 | 2857 |  *---------------------------------------------------------------------- | 
|---|
 | 2858 |  * | 
|---|
 | 2859 |  * FreeStringInternalRep -- | 
|---|
 | 2860 |  * | 
|---|
 | 2861 |  *      Deallocate the storage associated with a String data object's internal | 
|---|
 | 2862 |  *      representation. | 
|---|
 | 2863 |  * | 
|---|
 | 2864 |  * Results: | 
|---|
 | 2865 |  *      None. | 
|---|
 | 2866 |  * | 
|---|
 | 2867 |  * Side effects: | 
|---|
 | 2868 |  *      Frees memory. | 
|---|
 | 2869 |  * | 
|---|
 | 2870 |  *---------------------------------------------------------------------- | 
|---|
 | 2871 |  */ | 
|---|
 | 2872 |  | 
|---|
 | 2873 | static void | 
|---|
 | 2874 | FreeStringInternalRep( | 
|---|
 | 2875 |     Tcl_Obj *objPtr)            /* Object with internal rep to free. */ | 
|---|
 | 2876 | { | 
|---|
 | 2877 |     ckfree((char *) GET_STRING(objPtr)); | 
|---|
 | 2878 | } | 
|---|
 | 2879 |  | 
|---|
 | 2880 | /* | 
|---|
 | 2881 |  * Local Variables: | 
|---|
 | 2882 |  * mode: c | 
|---|
 | 2883 |  * c-basic-offset: 4 | 
|---|
 | 2884 |  * fill-column: 78 | 
|---|
 | 2885 |  * End: | 
|---|
 | 2886 |  */ | 
|---|