os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclStringObj.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclStringObj.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains procedures that implement string operations on Tcl
sl@0
     5
 *	objects.  Some string operations work with UTF strings and others
sl@0
     6
 *	require Unicode format.  Functions that require knowledge of the width
sl@0
     7
 *	of each character, such as indexing, operate on Unicode data.
sl@0
     8
 *
sl@0
     9
 *	A Unicode string is an internationalized string.  Conceptually, a
sl@0
    10
 *	Unicode string is an array of 16-bit quantities organized as a sequence
sl@0
    11
 *	of properly formed UTF-8 characters.  There is a one-to-one map between
sl@0
    12
 *	Unicode and UTF characters.  Because Unicode characters have a fixed
sl@0
    13
 *	width, operations such as indexing operate on Unicode data.  The String
sl@0
    14
 *	object is optimized for the case where each UTF char in a string is
sl@0
    15
 *	only one byte.  In this case, we store the value of numChars, but we
sl@0
    16
 *	don't store the Unicode data (unless Tcl_GetUnicode is explicitly
sl@0
    17
 *	called).
sl@0
    18
 *
sl@0
    19
 *	The String object type stores one or both formats.  The default
sl@0
    20
 *	behavior is to store UTF.  Once Unicode is calculated by a function, it
sl@0
    21
 *	is stored in the internal rep for future access (without an additional
sl@0
    22
 *	O(n) cost).
sl@0
    23
 *
sl@0
    24
 *	To allow many appends to be done to an object without constantly
sl@0
    25
 *	reallocating the space for the string or Unicode representation, we
sl@0
    26
 *	allocate double the space for the string or Unicode and use the
sl@0
    27
 *	internal representation to keep track of how much space is used
sl@0
    28
 *	vs. allocated.
sl@0
    29
 *
sl@0
    30
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
sl@0
    31
 * Copyright (c) 1999 by Scriptics Corporation.
sl@0
    32
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    33
 *
sl@0
    34
 * See the file "license.terms" for information on usage and redistribution
sl@0
    35
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    36
 *
sl@0
    37
 * RCS: @(#) $Id: tclStringObj.c,v 1.32.2.2 2006/09/24 21:15:11 msofer Exp $ */
sl@0
    38
sl@0
    39
#include "tclInt.h"
sl@0
    40
sl@0
    41
/*
sl@0
    42
 * Prototypes for procedures defined later in this file:
sl@0
    43
 */
sl@0
    44
sl@0
    45
static void		AppendUnicodeToUnicodeRep _ANSI_ARGS_((
sl@0
    46
    			    Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode,
sl@0
    47
			    int appendNumChars));
sl@0
    48
static void		AppendUnicodeToUtfRep _ANSI_ARGS_((
sl@0
    49
    			    Tcl_Obj *objPtr, CONST Tcl_UniChar *unicode,
sl@0
    50
			    int numChars));
sl@0
    51
static void		AppendUtfToUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr,
sl@0
    52
    			    CONST char *bytes, int numBytes));
sl@0
    53
static void		AppendUtfToUtfRep _ANSI_ARGS_((Tcl_Obj *objPtr,
sl@0
    54
    			    CONST char *bytes, int numBytes));
sl@0
    55
sl@0
    56
static void		FillUnicodeRep _ANSI_ARGS_((Tcl_Obj *objPtr));
sl@0
    57
sl@0
    58
static void		FreeStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr));
sl@0
    59
static void		DupStringInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
sl@0
    60
			    Tcl_Obj *copyPtr));
sl@0
    61
static int		SetStringFromAny _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
    62
			    Tcl_Obj *objPtr));
sl@0
    63
static void		UpdateStringOfString _ANSI_ARGS_((Tcl_Obj *objPtr));
sl@0
    64
sl@0
    65
/*
sl@0
    66
 * The structure below defines the string Tcl object type by means of
sl@0
    67
 * procedures that can be invoked by generic object code.
sl@0
    68
 */
sl@0
    69
sl@0
    70
Tcl_ObjType tclStringType = {
sl@0
    71
    "string",				/* name */
sl@0
    72
    FreeStringInternalRep,		/* freeIntRepPro */
sl@0
    73
    DupStringInternalRep,		/* dupIntRepProc */
sl@0
    74
    UpdateStringOfString,		/* updateStringProc */
sl@0
    75
    SetStringFromAny			/* setFromAnyProc */
sl@0
    76
};
sl@0
    77
sl@0
    78
/*
sl@0
    79
 * The following structure is the internal rep for a String object.
sl@0
    80
 * It keeps track of how much memory has been used and how much has been
sl@0
    81
 * allocated for the Unicode and UTF string to enable growing and
sl@0
    82
 * shrinking of the UTF and Unicode reps of the String object with fewer
sl@0
    83
 * mallocs.  To optimize string length and indexing operations, this
sl@0
    84
 * structure also stores the number of characters (same of UTF and Unicode!)
sl@0
    85
 * once that value has been computed.
sl@0
    86
 */
sl@0
    87
sl@0
    88
typedef struct String {
sl@0
    89
    int numChars;		/* The number of chars in the string.
sl@0
    90
				 * -1 means this value has not been
sl@0
    91
				 * calculated. >= 0 means that there is a
sl@0
    92
				 * valid Unicode rep, or that the number
sl@0
    93
				 * of UTF bytes == the number of chars. */
sl@0
    94
    size_t allocated;		/* The amount of space actually allocated
sl@0
    95
				 * for the UTF string (minus 1 byte for
sl@0
    96
				 * the termination char). */
sl@0
    97
    size_t uallocated;		/* The amount of space actually allocated
sl@0
    98
				 * for the Unicode string (minus 2 bytes for
sl@0
    99
				 * the termination char). */
sl@0
   100
    int hasUnicode;		/* Boolean determining whether the string
sl@0
   101
				 * has a Unicode representation. */
sl@0
   102
    Tcl_UniChar unicode[2];	/* The array of Unicode chars.  The actual
sl@0
   103
				 * size of this field depends on the
sl@0
   104
				 * 'uallocated' field above. */
sl@0
   105
} String;
sl@0
   106
sl@0
   107
#define STRING_UALLOC(numChars)	\
sl@0
   108
		(numChars * sizeof(Tcl_UniChar))
sl@0
   109
#define STRING_SIZE(ualloc) \
sl@0
   110
	((unsigned) ((ualloc) \
sl@0
   111
                 ? sizeof(String) - sizeof(Tcl_UniChar) + (ualloc) \
sl@0
   112
                 : sizeof(String)))
sl@0
   113
#define GET_STRING(objPtr) \
sl@0
   114
		((String *) (objPtr)->internalRep.otherValuePtr)
sl@0
   115
#define SET_STRING(objPtr, stringPtr) \
sl@0
   116
		(objPtr)->internalRep.otherValuePtr = (VOID *) (stringPtr)
sl@0
   117
sl@0
   118
/*
sl@0
   119
 * TCL STRING GROWTH ALGORITHM
sl@0
   120
 *
sl@0
   121
 * When growing strings (during an append, for example), the following growth
sl@0
   122
 * algorithm is used:
sl@0
   123
 *
sl@0
   124
 *   Attempt to allocate 2 * (originalLength + appendLength)
sl@0
   125
 *   On failure:
sl@0
   126
 *	attempt to allocate originalLength + 2*appendLength +
sl@0
   127
 *			TCL_GROWTH_MIN_ALLOC 
sl@0
   128
 *
sl@0
   129
 * This algorithm allows very good performance, as it rapidly increases the
sl@0
   130
 * memory allocated for a given string, which minimizes the number of
sl@0
   131
 * reallocations that must be performed.  However, using only the doubling
sl@0
   132
 * algorithm can lead to a significant waste of memory.  In particular, it
sl@0
   133
 * may fail even when there is sufficient memory available to complete the
sl@0
   134
 * append request (but there is not 2 * totalLength memory available).  So when
sl@0
   135
 * the doubling fails (because there is not enough memory available), the
sl@0
   136
 * algorithm requests a smaller amount of memory, which is still enough to
sl@0
   137
 * cover the request, but which hopefully will be less than the total available
sl@0
   138
 * memory.
sl@0
   139
 * 
sl@0
   140
 * The addition of TCL_GROWTH_MIN_ALLOC allows for efficient handling
sl@0
   141
 * of very small appends.  Without this extra slush factor, a sequence
sl@0
   142
 * of several small appends would cause several memory allocations.
sl@0
   143
 * As long as TCL_GROWTH_MIN_ALLOC is a reasonable size, we can
sl@0
   144
 * avoid that behavior.
sl@0
   145
 *
sl@0
   146
 * The growth algorithm can be tuned by adjusting the following parameters:
sl@0
   147
 *
sl@0
   148
 * TCL_GROWTH_MIN_ALLOC		Additional space, in bytes, to allocate when
sl@0
   149
 *				the double allocation has failed.
sl@0
   150
 *				Default is 1024 (1 kilobyte).
sl@0
   151
 */
sl@0
   152
#ifndef TCL_GROWTH_MIN_ALLOC
sl@0
   153
#define TCL_GROWTH_MIN_ALLOC	1024
sl@0
   154
#endif
sl@0
   155
sl@0
   156

sl@0
   157
/*
sl@0
   158
 *----------------------------------------------------------------------
sl@0
   159
 *
sl@0
   160
 * Tcl_NewStringObj --
sl@0
   161
 *
sl@0
   162
 *	This procedure is normally called when not debugging: i.e., when
sl@0
   163
 *	TCL_MEM_DEBUG is not defined. It creates a new string object and
sl@0
   164
 *	initializes it from the byte pointer and length arguments.
sl@0
   165
 *
sl@0
   166
 *	When TCL_MEM_DEBUG is defined, this procedure just returns the
sl@0
   167
 *	result of calling the debugging version Tcl_DbNewStringObj.
sl@0
   168
 *
sl@0
   169
 * Results:
sl@0
   170
 *	A newly created string object is returned that has ref count zero.
sl@0
   171
 *
sl@0
   172
 * Side effects:
sl@0
   173
 *	The new object's internal string representation will be set to a
sl@0
   174
 *	copy of the length bytes starting at "bytes". If "length" is
sl@0
   175
 *	negative, use bytes up to the first NULL byte; i.e., assume "bytes"
sl@0
   176
 *	points to a C-style NULL-terminated string. The object's type is set
sl@0
   177
 *	to NULL. An extra NULL is added to the end of the new object's byte
sl@0
   178
 *	array.
sl@0
   179
 *
sl@0
   180
 *----------------------------------------------------------------------
sl@0
   181
 */
sl@0
   182
sl@0
   183
#ifdef TCL_MEM_DEBUG
sl@0
   184
#undef Tcl_NewStringObj
sl@0
   185
sl@0
   186
EXPORT_C Tcl_Obj *
sl@0
   187
Tcl_NewStringObj(bytes, length)
sl@0
   188
    CONST char *bytes;		/* Points to the first of the length bytes
sl@0
   189
				 * used to initialize the new object. */
sl@0
   190
    int length;			/* The number of bytes to copy from "bytes"
sl@0
   191
				 * when initializing the new object. If 
sl@0
   192
				 * negative, use bytes up to the first
sl@0
   193
				 * NULL byte. */
sl@0
   194
{
sl@0
   195
    return Tcl_DbNewStringObj(bytes, length, "unknown", 0);
sl@0
   196
}
sl@0
   197
sl@0
   198
#else /* if not TCL_MEM_DEBUG */
sl@0
   199
sl@0
   200
EXPORT_C Tcl_Obj *
sl@0
   201
Tcl_NewStringObj(bytes, length)
sl@0
   202
    CONST char *bytes;		/* Points to the first of the length bytes
sl@0
   203
				 * used to initialize the new object. */
sl@0
   204
    int length;			/* The number of bytes to copy from "bytes"
sl@0
   205
				 * when initializing the new object. If 
sl@0
   206
				 * negative, use bytes up to the first
sl@0
   207
				 * NULL byte. */
sl@0
   208
{
sl@0
   209
    register Tcl_Obj *objPtr;
sl@0
   210
sl@0
   211
    if (length < 0) {
sl@0
   212
	length = (bytes? strlen(bytes) : 0);
sl@0
   213
    }
sl@0
   214
    TclNewObj(objPtr);
sl@0
   215
    TclInitStringRep(objPtr, bytes, length);
sl@0
   216
    return objPtr;
sl@0
   217
}
sl@0
   218
#endif /* TCL_MEM_DEBUG */
sl@0
   219

sl@0
   220
/*
sl@0
   221
 *----------------------------------------------------------------------
sl@0
   222
 *
sl@0
   223
 * Tcl_DbNewStringObj --
sl@0
   224
 *
sl@0
   225
 *	This procedure is normally called when debugging: i.e., when
sl@0
   226
 *	TCL_MEM_DEBUG is defined. It creates new string objects. It is the
sl@0
   227
 *	same as the Tcl_NewStringObj procedure above except that it calls
sl@0
   228
 *	Tcl_DbCkalloc directly with the file name and line number from its
sl@0
   229
 *	caller. This simplifies debugging since then the [memory active]
sl@0
   230
 *	command	will report the correct file name and line number when
sl@0
   231
 *	reporting objects that haven't been freed.
sl@0
   232
 *
sl@0
   233
 *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
sl@0
   234
 *	result of calling Tcl_NewStringObj.
sl@0
   235
 *
sl@0
   236
 * Results:
sl@0
   237
 *	A newly created string object is returned that has ref count zero.
sl@0
   238
 *
sl@0
   239
 * Side effects:
sl@0
   240
 *	The new object's internal string representation will be set to a
sl@0
   241
 *	copy of the length bytes starting at "bytes". If "length" is
sl@0
   242
 *	negative, use bytes up to the first NULL byte; i.e., assume "bytes"
sl@0
   243
 *	points to a C-style NULL-terminated string. The object's type is set
sl@0
   244
 *	to NULL. An extra NULL is added to the end of the new object's byte
sl@0
   245
 *	array.
sl@0
   246
 *
sl@0
   247
 *----------------------------------------------------------------------
sl@0
   248
 */
sl@0
   249
sl@0
   250
#ifdef TCL_MEM_DEBUG
sl@0
   251
sl@0
   252
EXPORT_C Tcl_Obj *
sl@0
   253
Tcl_DbNewStringObj(bytes, length, file, line)
sl@0
   254
    CONST char *bytes;		/* Points to the first of the length bytes
sl@0
   255
				 * used to initialize the new object. */
sl@0
   256
    int length;			/* The number of bytes to copy from "bytes"
sl@0
   257
				 * when initializing the new object. If 
sl@0
   258
				 * negative, use bytes up to the first
sl@0
   259
				 * NULL byte. */
sl@0
   260
    CONST char *file;		/* The name of the source file calling this
sl@0
   261
				 * procedure; used for debugging. */
sl@0
   262
    int line;			/* Line number in the source file; used
sl@0
   263
				 * for debugging. */
sl@0
   264
{
sl@0
   265
    register Tcl_Obj *objPtr;
sl@0
   266
sl@0
   267
    if (length < 0) {
sl@0
   268
	length = (bytes? strlen(bytes) : 0);
sl@0
   269
    }
sl@0
   270
    TclDbNewObj(objPtr, file, line);
sl@0
   271
    TclInitStringRep(objPtr, bytes, length);
sl@0
   272
    return objPtr;
sl@0
   273
}
sl@0
   274
sl@0
   275
#else /* if not TCL_MEM_DEBUG */
sl@0
   276
sl@0
   277
EXPORT_C Tcl_Obj *
sl@0
   278
Tcl_DbNewStringObj(bytes, length, file, line)
sl@0
   279
    CONST char *bytes;		/* Points to the first of the length bytes
sl@0
   280
				 * used to initialize the new object. */
sl@0
   281
    register int length;	/* The number of bytes to copy from "bytes"
sl@0
   282
				 * when initializing the new object. If 
sl@0
   283
				 * negative, use bytes up to the first
sl@0
   284
				 * NULL byte. */
sl@0
   285
    CONST char *file;		/* The name of the source file calling this
sl@0
   286
				 * procedure; used for debugging. */
sl@0
   287
    int line;			/* Line number in the source file; used
sl@0
   288
				 * for debugging. */
sl@0
   289
{
sl@0
   290
    return Tcl_NewStringObj(bytes, length);
sl@0
   291
}
sl@0
   292
#endif /* TCL_MEM_DEBUG */
sl@0
   293

sl@0
   294
/*
sl@0
   295
 *---------------------------------------------------------------------------
sl@0
   296
 *
sl@0
   297
 * Tcl_NewUnicodeObj --
sl@0
   298
 *
sl@0
   299
 *	This procedure is creates a new String object and initializes
sl@0
   300
 *	it from the given Unicode String.  If the Utf String is the same size
sl@0
   301
 *	as the Unicode string, don't duplicate the data.
sl@0
   302
 *
sl@0
   303
 * Results:
sl@0
   304
 *	The newly created object is returned.  This object will have no
sl@0
   305
 *	initial string representation.  The returned object has a ref count
sl@0
   306
 *	of 0.
sl@0
   307
 *
sl@0
   308
 * Side effects:
sl@0
   309
 *	Memory allocated for new object and copy of Unicode argument.
sl@0
   310
 *
sl@0
   311
 *---------------------------------------------------------------------------
sl@0
   312
 */
sl@0
   313
sl@0
   314
EXPORT_C Tcl_Obj *
sl@0
   315
Tcl_NewUnicodeObj(unicode, numChars)
sl@0
   316
    CONST Tcl_UniChar *unicode;	/* The unicode string used to initialize
sl@0
   317
				 * the new object. */
sl@0
   318
    int numChars;		/* Number of characters in the unicode
sl@0
   319
				 * string. */
sl@0
   320
{
sl@0
   321
    Tcl_Obj *objPtr;
sl@0
   322
    String *stringPtr;
sl@0
   323
    size_t uallocated;
sl@0
   324
sl@0
   325
    if (numChars < 0) {
sl@0
   326
	numChars = 0;
sl@0
   327
	if (unicode) {
sl@0
   328
	    while (unicode[numChars] != 0) { numChars++; }
sl@0
   329
	}
sl@0
   330
    }
sl@0
   331
    uallocated = STRING_UALLOC(numChars);
sl@0
   332
sl@0
   333
    /*
sl@0
   334
     * Create a new obj with an invalid string rep.
sl@0
   335
     */
sl@0
   336
sl@0
   337
    TclNewObj(objPtr);
sl@0
   338
    Tcl_InvalidateStringRep(objPtr);
sl@0
   339
    objPtr->typePtr = &tclStringType;
sl@0
   340
sl@0
   341
    stringPtr = (String *) ckalloc(STRING_SIZE(uallocated));
sl@0
   342
    stringPtr->numChars = numChars;
sl@0
   343
    stringPtr->uallocated = uallocated;
sl@0
   344
    stringPtr->hasUnicode = (numChars > 0);
sl@0
   345
    stringPtr->allocated = 0;
sl@0
   346
    memcpy((VOID *) stringPtr->unicode, (VOID *) unicode, uallocated);
sl@0
   347
    stringPtr->unicode[numChars] = 0;
sl@0
   348
    SET_STRING(objPtr, stringPtr);
sl@0
   349
    return objPtr;
sl@0
   350
}
sl@0
   351

sl@0
   352
/*
sl@0
   353
 *----------------------------------------------------------------------
sl@0
   354
 *
sl@0
   355
 * Tcl_GetCharLength --
sl@0
   356
 *
sl@0
   357
 *	Get the length of the Unicode string from the Tcl object.
sl@0
   358
 *
sl@0
   359
 * Results:
sl@0
   360
 *	Pointer to unicode string representing the unicode object.
sl@0
   361
 *
sl@0
   362
 * Side effects:
sl@0
   363
 *	Frees old internal rep.  Allocates memory for new "String"
sl@0
   364
 *	internal rep.
sl@0
   365
 *
sl@0
   366
 *----------------------------------------------------------------------
sl@0
   367
 */
sl@0
   368
sl@0
   369
EXPORT_C int
sl@0
   370
Tcl_GetCharLength(objPtr)
sl@0
   371
    Tcl_Obj *objPtr;	/* The String object to get the num chars of. */
sl@0
   372
{
sl@0
   373
    String *stringPtr;
sl@0
   374
    
sl@0
   375
    SetStringFromAny(NULL, objPtr);
sl@0
   376
    stringPtr = GET_STRING(objPtr);
sl@0
   377
sl@0
   378
    /*
sl@0
   379
     * If numChars is unknown, then calculate the number of characaters
sl@0
   380
     * while populating the Unicode string.
sl@0
   381
     */
sl@0
   382
    
sl@0
   383
    if (stringPtr->numChars == -1) {
sl@0
   384
	register int i = objPtr->length;
sl@0
   385
	register unsigned char *str = (unsigned char *) objPtr->bytes;
sl@0
   386
sl@0
   387
	/*
sl@0
   388
	 * This is a speed sensitive function, so run specially over the
sl@0
   389
	 * string to count continuous ascii characters before resorting
sl@0
   390
	 * to the Tcl_NumUtfChars call.  This is a long form of:
sl@0
   391
	 stringPtr->numChars = Tcl_NumUtfChars(objPtr->bytes, objPtr->length);
sl@0
   392
	*/
sl@0
   393
sl@0
   394
	while (i && (*str < 0xC0)) { i--; str++; }
sl@0
   395
	stringPtr->numChars = objPtr->length - i;
sl@0
   396
	if (i) {
sl@0
   397
	    stringPtr->numChars += Tcl_NumUtfChars(objPtr->bytes
sl@0
   398
		    + (objPtr->length - i), i);
sl@0
   399
	}
sl@0
   400
sl@0
   401
 	if (stringPtr->numChars == objPtr->length) {
sl@0
   402
sl@0
   403
	    /*
sl@0
   404
	     * Since we've just calculated the number of chars, and all
sl@0
   405
	     * UTF chars are 1-byte long, we don't need to store the
sl@0
   406
	     * unicode string.
sl@0
   407
	     */
sl@0
   408
sl@0
   409
	    stringPtr->hasUnicode = 0;
sl@0
   410
sl@0
   411
	} else {
sl@0
   412
    
sl@0
   413
	    /*
sl@0
   414
	     * Since we've just calucalated the number of chars, and not
sl@0
   415
	     * all UTF chars are 1-byte long, go ahead and populate the
sl@0
   416
	     * unicode string.
sl@0
   417
	     */
sl@0
   418
sl@0
   419
	    FillUnicodeRep(objPtr);
sl@0
   420
sl@0
   421
	    /*
sl@0
   422
	     * We need to fetch the pointer again because we have just
sl@0
   423
	     * reallocated the structure to make room for the Unicode data.
sl@0
   424
	     */
sl@0
   425
	    
sl@0
   426
	    stringPtr = GET_STRING(objPtr);
sl@0
   427
	}
sl@0
   428
    }
sl@0
   429
    return stringPtr->numChars;
sl@0
   430
}
sl@0
   431

sl@0
   432
/*
sl@0
   433
 *----------------------------------------------------------------------
sl@0
   434
 *
sl@0
   435
 * Tcl_GetUniChar --
sl@0
   436
 *
sl@0
   437
 *	Get the index'th Unicode character from the String object.  The
sl@0
   438
 *	index is assumed to be in the appropriate range.
sl@0
   439
 *
sl@0
   440
 * Results:
sl@0
   441
 *	Returns the index'th Unicode character in the Object.
sl@0
   442
 *
sl@0
   443
 * Side effects:
sl@0
   444
 *	Fills unichar with the index'th Unicode character.
sl@0
   445
 *
sl@0
   446
 *----------------------------------------------------------------------
sl@0
   447
 */
sl@0
   448
sl@0
   449
EXPORT_C Tcl_UniChar
sl@0
   450
Tcl_GetUniChar(objPtr, index)
sl@0
   451
    Tcl_Obj *objPtr;	/* The object to get the Unicode charater from. */
sl@0
   452
    int index;		/* Get the index'th Unicode character. */
sl@0
   453
{
sl@0
   454
    Tcl_UniChar unichar;
sl@0
   455
    String *stringPtr;
sl@0
   456
    
sl@0
   457
    SetStringFromAny(NULL, objPtr);
sl@0
   458
    stringPtr = GET_STRING(objPtr);
sl@0
   459
sl@0
   460
    if (stringPtr->numChars == -1) {
sl@0
   461
sl@0
   462
	/*
sl@0
   463
	 * We haven't yet calculated the length, so we don't have the
sl@0
   464
	 * Unicode str.  We need to know the number of chars before we
sl@0
   465
	 * can do indexing.
sl@0
   466
	 */
sl@0
   467
sl@0
   468
	Tcl_GetCharLength(objPtr);
sl@0
   469
sl@0
   470
	/*
sl@0
   471
	 * We need to fetch the pointer again because we may have just
sl@0
   472
	 * reallocated the structure.
sl@0
   473
	 */
sl@0
   474
	
sl@0
   475
	stringPtr = GET_STRING(objPtr);
sl@0
   476
    }
sl@0
   477
    if (stringPtr->hasUnicode == 0) {
sl@0
   478
sl@0
   479
	/*
sl@0
   480
	 * All of the characters in the Utf string are 1 byte chars,
sl@0
   481
	 * so we don't store the unicode char.  We get the Utf string
sl@0
   482
	 * and convert the index'th byte to a Unicode character.
sl@0
   483
	 */
sl@0
   484
sl@0
   485
	unichar = (Tcl_UniChar) objPtr->bytes[index];
sl@0
   486
    } else {
sl@0
   487
	unichar = stringPtr->unicode[index];
sl@0
   488
    }
sl@0
   489
    return unichar;
sl@0
   490
}
sl@0
   491

sl@0
   492
/*
sl@0
   493
 *----------------------------------------------------------------------
sl@0
   494
 *
sl@0
   495
 * Tcl_GetUnicode --
sl@0
   496
 *
sl@0
   497
 *	Get the Unicode form of the String object.  If
sl@0
   498
 *	the object is not already a String object, it will be converted
sl@0
   499
 *	to one.  If the String object does not have a Unicode rep, then
sl@0
   500
 *	one is create from the UTF string format.
sl@0
   501
 *
sl@0
   502
 * Results:
sl@0
   503
 *	Returns a pointer to the object's internal Unicode string.
sl@0
   504
 *
sl@0
   505
 * Side effects:
sl@0
   506
 *	Converts the object to have the String internal rep.
sl@0
   507
 *
sl@0
   508
 *----------------------------------------------------------------------
sl@0
   509
 */
sl@0
   510
sl@0
   511
EXPORT_C Tcl_UniChar *
sl@0
   512
Tcl_GetUnicode(objPtr)
sl@0
   513
    Tcl_Obj *objPtr;	/* The object to find the unicode string for. */
sl@0
   514
{
sl@0
   515
    String *stringPtr;
sl@0
   516
    
sl@0
   517
    SetStringFromAny(NULL, objPtr);
sl@0
   518
    stringPtr = GET_STRING(objPtr);
sl@0
   519
    
sl@0
   520
    if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) {
sl@0
   521
sl@0
   522
	/*
sl@0
   523
	 * We haven't yet calculated the length, or all of the characters
sl@0
   524
	 * in the Utf string are 1 byte chars (so we didn't store the
sl@0
   525
	 * unicode str).  Since this function must return a unicode string,
sl@0
   526
	 * and one has not yet been stored, force the Unicode to be
sl@0
   527
	 * calculated and stored now.
sl@0
   528
	 */
sl@0
   529
sl@0
   530
	FillUnicodeRep(objPtr);
sl@0
   531
sl@0
   532
	/*
sl@0
   533
	 * We need to fetch the pointer again because we have just
sl@0
   534
	 * reallocated the structure to make room for the Unicode data.
sl@0
   535
	 */
sl@0
   536
	
sl@0
   537
	stringPtr = GET_STRING(objPtr);
sl@0
   538
    }
sl@0
   539
    return stringPtr->unicode;
sl@0
   540
}
sl@0
   541

sl@0
   542
/*
sl@0
   543
 *----------------------------------------------------------------------
sl@0
   544
 *
sl@0
   545
 * Tcl_GetUnicodeFromObj --
sl@0
   546
 *
sl@0
   547
 *	Get the Unicode form of the String object with length.  If
sl@0
   548
 *	the object is not already a String object, it will be converted
sl@0
   549
 *	to one.  If the String object does not have a Unicode rep, then
sl@0
   550
 *	one is create from the UTF string format.
sl@0
   551
 *
sl@0
   552
 * Results:
sl@0
   553
 *	Returns a pointer to the object's internal Unicode string.
sl@0
   554
 *
sl@0
   555
 * Side effects:
sl@0
   556
 *	Converts the object to have the String internal rep.
sl@0
   557
 *
sl@0
   558
 *----------------------------------------------------------------------
sl@0
   559
 */
sl@0
   560
sl@0
   561
EXPORT_C Tcl_UniChar *
sl@0
   562
Tcl_GetUnicodeFromObj(objPtr, lengthPtr)
sl@0
   563
    Tcl_Obj *objPtr;	/* The object to find the unicode string for. */
sl@0
   564
    int *lengthPtr;	/* If non-NULL, the location where the
sl@0
   565
			 * string rep's unichar length should be
sl@0
   566
			 * stored. If NULL, no length is stored. */
sl@0
   567
{
sl@0
   568
    String *stringPtr;
sl@0
   569
    
sl@0
   570
    SetStringFromAny(NULL, objPtr);
sl@0
   571
    stringPtr = GET_STRING(objPtr);
sl@0
   572
    
sl@0
   573
    if ((stringPtr->numChars == -1) || (stringPtr->hasUnicode == 0)) {
sl@0
   574
sl@0
   575
	/*
sl@0
   576
	 * We haven't yet calculated the length, or all of the characters
sl@0
   577
	 * in the Utf string are 1 byte chars (so we didn't store the
sl@0
   578
	 * unicode str).  Since this function must return a unicode string,
sl@0
   579
	 * and one has not yet been stored, force the Unicode to be
sl@0
   580
	 * calculated and stored now.
sl@0
   581
	 */
sl@0
   582
sl@0
   583
	FillUnicodeRep(objPtr);
sl@0
   584
sl@0
   585
	/*
sl@0
   586
	 * We need to fetch the pointer again because we have just
sl@0
   587
	 * reallocated the structure to make room for the Unicode data.
sl@0
   588
	 */
sl@0
   589
	
sl@0
   590
	stringPtr = GET_STRING(objPtr);
sl@0
   591
    }
sl@0
   592
sl@0
   593
    if (lengthPtr != NULL) {
sl@0
   594
	*lengthPtr = stringPtr->numChars;
sl@0
   595
    }
sl@0
   596
    return stringPtr->unicode;
sl@0
   597
}
sl@0
   598

sl@0
   599
/*
sl@0
   600
 *----------------------------------------------------------------------
sl@0
   601
 *
sl@0
   602
 * Tcl_GetRange --
sl@0
   603
 *
sl@0
   604
 *	Create a Tcl Object that contains the chars between first and last
sl@0
   605
 *	of the object indicated by "objPtr".  If the object is not already
sl@0
   606
 *	a String object, convert it to one.  The first and last indices
sl@0
   607
 *	are assumed to be in the appropriate range.
sl@0
   608
 *
sl@0
   609
 * Results:
sl@0
   610
 *	Returns a new Tcl Object of the String type.
sl@0
   611
 *
sl@0
   612
 * Side effects:
sl@0
   613
 *	Changes the internal rep of "objPtr" to the String type.
sl@0
   614
 *
sl@0
   615
 *----------------------------------------------------------------------
sl@0
   616
 */
sl@0
   617
sl@0
   618
EXPORT_C Tcl_Obj *
sl@0
   619
Tcl_GetRange(objPtr, first, last)
sl@0
   620
    Tcl_Obj *objPtr;		/* The Tcl object to find the range of. */
sl@0
   621
    int first;			/* First index of the range. */
sl@0
   622
    int last;			/* Last index of the range. */
sl@0
   623
{
sl@0
   624
    Tcl_Obj *newObjPtr;		/* The Tcl object to find the range of. */
sl@0
   625
    String *stringPtr;
sl@0
   626
    
sl@0
   627
    SetStringFromAny(NULL, objPtr);
sl@0
   628
    stringPtr = GET_STRING(objPtr);
sl@0
   629
sl@0
   630
    if (stringPtr->numChars == -1) {
sl@0
   631
    
sl@0
   632
	/*
sl@0
   633
	 * We haven't yet calculated the length, so we don't have the
sl@0
   634
	 * Unicode str.  We need to know the number of chars before we
sl@0
   635
	 * can do indexing.
sl@0
   636
	 */
sl@0
   637
sl@0
   638
	Tcl_GetCharLength(objPtr);
sl@0
   639
sl@0
   640
	/*
sl@0
   641
	 * We need to fetch the pointer again because we may have just
sl@0
   642
	 * reallocated the structure.
sl@0
   643
	 */
sl@0
   644
	
sl@0
   645
	stringPtr = GET_STRING(objPtr);
sl@0
   646
    }
sl@0
   647
sl@0
   648
    if (objPtr->bytes && stringPtr->numChars == objPtr->length) {
sl@0
   649
	char *str = Tcl_GetString(objPtr);
sl@0
   650
sl@0
   651
	/*
sl@0
   652
	 * All of the characters in the Utf string are 1 byte chars,
sl@0
   653
	 * so we don't store the unicode char.  Create a new string
sl@0
   654
	 * object containing the specified range of chars.
sl@0
   655
	 */
sl@0
   656
	
sl@0
   657
	newObjPtr = Tcl_NewStringObj(&str[first], last-first+1);
sl@0
   658
sl@0
   659
	/*
sl@0
   660
	 * Since we know the new string only has 1-byte chars, we
sl@0
   661
	 * can set it's numChars field.
sl@0
   662
	 */
sl@0
   663
	
sl@0
   664
	SetStringFromAny(NULL, newObjPtr);
sl@0
   665
	stringPtr = GET_STRING(newObjPtr);
sl@0
   666
	stringPtr->numChars = last-first+1;
sl@0
   667
    } else {
sl@0
   668
	newObjPtr = Tcl_NewUnicodeObj(stringPtr->unicode + first,
sl@0
   669
		last-first+1);
sl@0
   670
    }
sl@0
   671
    return newObjPtr;
sl@0
   672
}
sl@0
   673

sl@0
   674
/*
sl@0
   675
 *----------------------------------------------------------------------
sl@0
   676
 *
sl@0
   677
 * Tcl_SetStringObj --
sl@0
   678
 *
sl@0
   679
 *	Modify an object to hold a string that is a copy of the bytes
sl@0
   680
 *	indicated by the byte pointer and length arguments. 
sl@0
   681
 *
sl@0
   682
 * Results:
sl@0
   683
 *	None.
sl@0
   684
 *
sl@0
   685
 * Side effects:
sl@0
   686
 *	The object's string representation will be set to a copy of
sl@0
   687
 *	the "length" bytes starting at "bytes". If "length" is negative, use
sl@0
   688
 *	bytes up to the first NULL byte; i.e., assume "bytes" points to a
sl@0
   689
 *	C-style NULL-terminated string. The object's old string and internal
sl@0
   690
 *	representations are freed and the object's type is set NULL.
sl@0
   691
 *
sl@0
   692
 *----------------------------------------------------------------------
sl@0
   693
 */
sl@0
   694
sl@0
   695
EXPORT_C void
sl@0
   696
Tcl_SetStringObj(objPtr, bytes, length)
sl@0
   697
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
sl@0
   698
    CONST char *bytes;		/* Points to the first of the length bytes
sl@0
   699
				 * used to initialize the object. */
sl@0
   700
    register int length;	/* The number of bytes to copy from "bytes"
sl@0
   701
				 * when initializing the object. If 
sl@0
   702
				 * negative, use bytes up to the first
sl@0
   703
				 * NULL byte.*/
sl@0
   704
{
sl@0
   705
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;
sl@0
   706
sl@0
   707
    /*
sl@0
   708
     * Free any old string rep, then set the string rep to a copy of
sl@0
   709
     * the length bytes starting at "bytes".
sl@0
   710
     */
sl@0
   711
sl@0
   712
    if (Tcl_IsShared(objPtr)) {
sl@0
   713
	panic("Tcl_SetStringObj called with shared object");
sl@0
   714
    }
sl@0
   715
sl@0
   716
    /*
sl@0
   717
     * Set the type to NULL and free any internal rep for the old type.
sl@0
   718
     */
sl@0
   719
sl@0
   720
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
sl@0
   721
	oldTypePtr->freeIntRepProc(objPtr);
sl@0
   722
    }
sl@0
   723
    objPtr->typePtr = NULL;
sl@0
   724
sl@0
   725
    Tcl_InvalidateStringRep(objPtr);
sl@0
   726
    if (length < 0) {
sl@0
   727
	length = (bytes? strlen(bytes) : 0);
sl@0
   728
    }
sl@0
   729
    TclInitStringRep(objPtr, bytes, length);
sl@0
   730
}
sl@0
   731

sl@0
   732
/*
sl@0
   733
 *----------------------------------------------------------------------
sl@0
   734
 *
sl@0
   735
 * Tcl_SetObjLength --
sl@0
   736
 *
sl@0
   737
 *	This procedure changes the length of the string representation
sl@0
   738
 *	of an object.
sl@0
   739
 *
sl@0
   740
 * Results:
sl@0
   741
 *	None.
sl@0
   742
 *
sl@0
   743
 * Side effects:
sl@0
   744
 *	If the size of objPtr's string representation is greater than
sl@0
   745
 *	length, then it is reduced to length and a new terminating null
sl@0
   746
 *	byte is stored in the strength.  If the length of the string
sl@0
   747
 *	representation is greater than length, the storage space is
sl@0
   748
 *	reallocated to the given length; a null byte is stored at the
sl@0
   749
 *	end, but other bytes past the end of the original string
sl@0
   750
 *	representation are undefined.  The object's internal
sl@0
   751
 *	representation is changed to "expendable string".
sl@0
   752
 *
sl@0
   753
 *----------------------------------------------------------------------
sl@0
   754
 */
sl@0
   755
sl@0
   756
EXPORT_C void
sl@0
   757
Tcl_SetObjLength(objPtr, length)
sl@0
   758
    register Tcl_Obj *objPtr;	/* Pointer to object.  This object must
sl@0
   759
				 * not currently be shared. */
sl@0
   760
    register int length;	/* Number of bytes desired for string
sl@0
   761
				 * representation of object, not including
sl@0
   762
				 * terminating null byte. */
sl@0
   763
{
sl@0
   764
    String *stringPtr;
sl@0
   765
sl@0
   766
    if (Tcl_IsShared(objPtr)) {
sl@0
   767
	panic("Tcl_SetObjLength called with shared object");
sl@0
   768
    }
sl@0
   769
    SetStringFromAny(NULL, objPtr);
sl@0
   770
    
sl@0
   771
    stringPtr = GET_STRING(objPtr);
sl@0
   772
    
sl@0
   773
    /* Check that we're not extending a pure unicode string */
sl@0
   774
    
sl@0
   775
    if (length > (int) stringPtr->allocated && 
sl@0
   776
	    (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) {
sl@0
   777
	char *new;
sl@0
   778
sl@0
   779
	/*
sl@0
   780
	 * Not enough space in current string. Reallocate the string
sl@0
   781
	 * space and free the old string.
sl@0
   782
	 */
sl@0
   783
	if (objPtr->bytes != tclEmptyStringRep && objPtr->bytes != NULL) {
sl@0
   784
	    new = (char *) ckrealloc((char *)objPtr->bytes,
sl@0
   785
		    (unsigned)(length+1));
sl@0
   786
	} else {
sl@0
   787
	    new = (char *) ckalloc((unsigned) (length+1));
sl@0
   788
	    if (objPtr->bytes != NULL && objPtr->length != 0) {
sl@0
   789
		memcpy((VOID *) new, (VOID *) objPtr->bytes,
sl@0
   790
			(size_t) objPtr->length);
sl@0
   791
		Tcl_InvalidateStringRep(objPtr);
sl@0
   792
	    }
sl@0
   793
	}
sl@0
   794
	objPtr->bytes = new;
sl@0
   795
	stringPtr->allocated = length;
sl@0
   796
	/* Invalidate the unicode data. */
sl@0
   797
	stringPtr->hasUnicode = 0;
sl@0
   798
    }
sl@0
   799
    
sl@0
   800
    if (objPtr->bytes != NULL) {
sl@0
   801
        objPtr->length = length;
sl@0
   802
        if (objPtr->bytes != tclEmptyStringRep) {
sl@0
   803
            /* Ensure the string is NULL-terminated */
sl@0
   804
            objPtr->bytes[length] = 0;
sl@0
   805
        }
sl@0
   806
        /* Invalidate the unicode data. */
sl@0
   807
        stringPtr->numChars = -1;
sl@0
   808
        stringPtr->hasUnicode = 0;
sl@0
   809
    } else {
sl@0
   810
        /* Changing length of pure unicode string */
sl@0
   811
        size_t uallocated = STRING_UALLOC(length);
sl@0
   812
        if (uallocated > stringPtr->uallocated) {
sl@0
   813
            stringPtr = (String *) ckrealloc((char*) stringPtr,
sl@0
   814
                    STRING_SIZE(uallocated));
sl@0
   815
            SET_STRING(objPtr, stringPtr);
sl@0
   816
            stringPtr->uallocated = uallocated;
sl@0
   817
        }
sl@0
   818
        stringPtr->numChars = length;
sl@0
   819
        stringPtr->hasUnicode = (length > 0);
sl@0
   820
        /* Ensure the string is NULL-terminated */
sl@0
   821
        stringPtr->unicode[length] = 0;
sl@0
   822
        stringPtr->allocated = 0;
sl@0
   823
        objPtr->length = 0;
sl@0
   824
    }
sl@0
   825
}
sl@0
   826

sl@0
   827
/*
sl@0
   828
 *----------------------------------------------------------------------
sl@0
   829
 *
sl@0
   830
 * Tcl_AttemptSetObjLength --
sl@0
   831
 *
sl@0
   832
 *	This procedure changes the length of the string representation
sl@0
   833
 *	of an object.  It uses the attempt* (non-panic'ing) memory allocators.
sl@0
   834
 *
sl@0
   835
 * Results:
sl@0
   836
 *	1 if the requested memory was allocated, 0 otherwise.
sl@0
   837
 *
sl@0
   838
 * Side effects:
sl@0
   839
 *	If the size of objPtr's string representation is greater than
sl@0
   840
 *	length, then it is reduced to length and a new terminating null
sl@0
   841
 *	byte is stored in the strength.  If the length of the string
sl@0
   842
 *	representation is greater than length, the storage space is
sl@0
   843
 *	reallocated to the given length; a null byte is stored at the
sl@0
   844
 *	end, but other bytes past the end of the original string
sl@0
   845
 *	representation are undefined.  The object's internal
sl@0
   846
 *	representation is changed to "expendable string".
sl@0
   847
 *
sl@0
   848
 *----------------------------------------------------------------------
sl@0
   849
 */
sl@0
   850
sl@0
   851
EXPORT_C int
sl@0
   852
Tcl_AttemptSetObjLength(objPtr, length)
sl@0
   853
    register Tcl_Obj *objPtr;	/* Pointer to object.  This object must
sl@0
   854
				 * not currently be shared. */
sl@0
   855
    register int length;	/* Number of bytes desired for string
sl@0
   856
				 * representation of object, not including
sl@0
   857
				 * terminating null byte. */
sl@0
   858
{
sl@0
   859
    String *stringPtr;
sl@0
   860
sl@0
   861
    if (Tcl_IsShared(objPtr)) {
sl@0
   862
	panic("Tcl_AttemptSetObjLength called with shared object");
sl@0
   863
    }
sl@0
   864
    SetStringFromAny(NULL, objPtr);
sl@0
   865
        
sl@0
   866
    stringPtr = GET_STRING(objPtr);
sl@0
   867
sl@0
   868
    /* Check that we're not extending a pure unicode string */
sl@0
   869
sl@0
   870
    if (length > (int) stringPtr->allocated && 
sl@0
   871
	    (objPtr->bytes != NULL || stringPtr->hasUnicode == 0)) {
sl@0
   872
	char *new;
sl@0
   873
sl@0
   874
	/*
sl@0
   875
	 * Not enough space in current string. Reallocate the string
sl@0
   876
	 * space and free the old string.
sl@0
   877
	 */
sl@0
   878
	if (objPtr->bytes != tclEmptyStringRep && objPtr->bytes != NULL) {
sl@0
   879
	    new = (char *) attemptckrealloc((char *)objPtr->bytes,
sl@0
   880
		    (unsigned)(length+1));
sl@0
   881
	    if (new == NULL) {
sl@0
   882
		return 0;
sl@0
   883
	    }
sl@0
   884
	} else {
sl@0
   885
	    new = (char *) attemptckalloc((unsigned) (length+1));
sl@0
   886
	    if (new == NULL) {
sl@0
   887
		return 0;
sl@0
   888
	    }
sl@0
   889
	    if (objPtr->bytes != NULL && objPtr->length != 0) {
sl@0
   890
 	    	memcpy((VOID *) new, (VOID *) objPtr->bytes,
sl@0
   891
 		    	(size_t) objPtr->length);
sl@0
   892
 	    	Tcl_InvalidateStringRep(objPtr);
sl@0
   893
	    }
sl@0
   894
	}
sl@0
   895
	objPtr->bytes = new;
sl@0
   896
	stringPtr->allocated = length;
sl@0
   897
	/* Invalidate the unicode data. */
sl@0
   898
	stringPtr->hasUnicode = 0;
sl@0
   899
    }
sl@0
   900
    
sl@0
   901
    if (objPtr->bytes != NULL) {
sl@0
   902
	objPtr->length = length;
sl@0
   903
	if (objPtr->bytes != tclEmptyStringRep) {
sl@0
   904
	    /* Ensure the string is NULL-terminated */
sl@0
   905
	    objPtr->bytes[length] = 0;
sl@0
   906
	}
sl@0
   907
	/* Invalidate the unicode data. */
sl@0
   908
	stringPtr->numChars = -1;
sl@0
   909
	stringPtr->hasUnicode = 0;
sl@0
   910
    } else {
sl@0
   911
	/* Changing length of pure unicode string */
sl@0
   912
	size_t uallocated = STRING_UALLOC(length);
sl@0
   913
	if (uallocated > stringPtr->uallocated) {
sl@0
   914
	    stringPtr = (String *) attemptckrealloc((char*) stringPtr,
sl@0
   915
		    STRING_SIZE(uallocated));
sl@0
   916
	    if (stringPtr == NULL) {
sl@0
   917
	        return 0;
sl@0
   918
	    }
sl@0
   919
	    SET_STRING(objPtr, stringPtr);
sl@0
   920
	    stringPtr->uallocated = uallocated;
sl@0
   921
	}
sl@0
   922
	stringPtr->numChars = length;
sl@0
   923
	stringPtr->hasUnicode = (length > 0);
sl@0
   924
	/* Ensure the string is NULL-terminated */
sl@0
   925
	stringPtr->unicode[length] = 0;
sl@0
   926
	stringPtr->allocated = 0;
sl@0
   927
	objPtr->length = 0;
sl@0
   928
    }
sl@0
   929
    return 1;
sl@0
   930
}
sl@0
   931

sl@0
   932
/*
sl@0
   933
 *---------------------------------------------------------------------------
sl@0
   934
 *
sl@0
   935
 * TclSetUnicodeObj --
sl@0
   936
 *
sl@0
   937
 *	Modify an object to hold the Unicode string indicated by "unicode".
sl@0
   938
 *
sl@0
   939
 * Results:
sl@0
   940
 *	None.
sl@0
   941
 *
sl@0
   942
 * Side effects:
sl@0
   943
 *	Memory allocated for new "String" internal rep.
sl@0
   944
 *
sl@0
   945
 *---------------------------------------------------------------------------
sl@0
   946
 */
sl@0
   947
sl@0
   948
EXPORT_C void
sl@0
   949
Tcl_SetUnicodeObj(objPtr, unicode, numChars)
sl@0
   950
    Tcl_Obj *objPtr;		/* The object to set the string of. */
sl@0
   951
    CONST Tcl_UniChar *unicode;	/* The unicode string used to initialize
sl@0
   952
				 * the object. */
sl@0
   953
    int numChars;		/* Number of characters in the unicode
sl@0
   954
				 * string. */
sl@0
   955
{
sl@0
   956
    Tcl_ObjType *typePtr;
sl@0
   957
    String *stringPtr;
sl@0
   958
    size_t uallocated;
sl@0
   959
sl@0
   960
    if (numChars < 0) {
sl@0
   961
	numChars = 0;
sl@0
   962
	if (unicode) {
sl@0
   963
	    while (unicode[numChars] != 0) { numChars++; }
sl@0
   964
	}
sl@0
   965
    }
sl@0
   966
    uallocated = STRING_UALLOC(numChars);
sl@0
   967
sl@0
   968
    /*
sl@0
   969
     * Free the internal rep if one exists, and invalidate the string rep.
sl@0
   970
     */
sl@0
   971
sl@0
   972
    typePtr = objPtr->typePtr;
sl@0
   973
    if ((typePtr != NULL) && (typePtr->freeIntRepProc) != NULL) {
sl@0
   974
	(*typePtr->freeIntRepProc)(objPtr);
sl@0
   975
    }
sl@0
   976
    objPtr->typePtr = &tclStringType;
sl@0
   977
sl@0
   978
    /*
sl@0
   979
     * Allocate enough space for the String structure + Unicode string.
sl@0
   980
     */
sl@0
   981
	
sl@0
   982
    stringPtr = (String *) ckalloc(STRING_SIZE(uallocated));
sl@0
   983
    stringPtr->numChars = numChars;
sl@0
   984
    stringPtr->uallocated = uallocated;
sl@0
   985
    stringPtr->hasUnicode = (numChars > 0);
sl@0
   986
    stringPtr->allocated = 0;
sl@0
   987
    memcpy((VOID *) stringPtr->unicode, (VOID *) unicode, uallocated);
sl@0
   988
    stringPtr->unicode[numChars] = 0;
sl@0
   989
    SET_STRING(objPtr, stringPtr);
sl@0
   990
    Tcl_InvalidateStringRep(objPtr);
sl@0
   991
    return;
sl@0
   992
}
sl@0
   993

sl@0
   994
/*
sl@0
   995
 *----------------------------------------------------------------------
sl@0
   996
 *
sl@0
   997
 * Tcl_AppendToObj --
sl@0
   998
 *
sl@0
   999
 *	This procedure appends a sequence of bytes to an object.
sl@0
  1000
 *
sl@0
  1001
 * Results:
sl@0
  1002
 *	None.
sl@0
  1003
 *
sl@0
  1004
 * Side effects:
sl@0
  1005
 *	The bytes at *bytes are appended to the string representation
sl@0
  1006
 *	of objPtr.
sl@0
  1007
 *
sl@0
  1008
 *----------------------------------------------------------------------
sl@0
  1009
 */
sl@0
  1010
sl@0
  1011
EXPORT_C void
sl@0
  1012
Tcl_AppendToObj(objPtr, bytes, length)
sl@0
  1013
    register Tcl_Obj *objPtr;	/* Points to the object to append to. */
sl@0
  1014
    CONST char *bytes;		/* Points to the bytes to append to the
sl@0
  1015
				 * object. */
sl@0
  1016
    register int length;	/* The number of bytes to append from
sl@0
  1017
				 * "bytes". If < 0, then append all bytes
sl@0
  1018
				 * up to NULL byte. */
sl@0
  1019
{
sl@0
  1020
    String *stringPtr;
sl@0
  1021
sl@0
  1022
    if (Tcl_IsShared(objPtr)) {
sl@0
  1023
	panic("Tcl_AppendToObj called with shared object");
sl@0
  1024
    }
sl@0
  1025
    
sl@0
  1026
    SetStringFromAny(NULL, objPtr);
sl@0
  1027
sl@0
  1028
    if (length < 0) {
sl@0
  1029
	length = (bytes ? strlen(bytes) : 0);
sl@0
  1030
    }
sl@0
  1031
    if (length == 0) {
sl@0
  1032
	return;
sl@0
  1033
    }
sl@0
  1034
sl@0
  1035
    /*
sl@0
  1036
     * If objPtr has a valid Unicode rep, then append the Unicode
sl@0
  1037
     * conversion of "bytes" to the objPtr's Unicode rep, otherwise
sl@0
  1038
     * append "bytes" to objPtr's string rep.
sl@0
  1039
     */
sl@0
  1040
sl@0
  1041
    stringPtr = GET_STRING(objPtr);
sl@0
  1042
    if (stringPtr->hasUnicode != 0) {
sl@0
  1043
	AppendUtfToUnicodeRep(objPtr, bytes, length);
sl@0
  1044
sl@0
  1045
	stringPtr = GET_STRING(objPtr);
sl@0
  1046
    } else {
sl@0
  1047
	AppendUtfToUtfRep(objPtr, bytes, length);
sl@0
  1048
    }
sl@0
  1049
}
sl@0
  1050

sl@0
  1051
/*
sl@0
  1052
 *----------------------------------------------------------------------
sl@0
  1053
 *
sl@0
  1054
 * Tcl_AppendUnicodeToObj --
sl@0
  1055
 *
sl@0
  1056
 *	This procedure appends a Unicode string to an object in the
sl@0
  1057
 *	most efficient manner possible.  Length must be >= 0.
sl@0
  1058
 *
sl@0
  1059
 * Results:
sl@0
  1060
 *	None.
sl@0
  1061
 *
sl@0
  1062
 * Side effects:
sl@0
  1063
 *	Invalidates the string rep and creates a new Unicode string.
sl@0
  1064
 *
sl@0
  1065
 *----------------------------------------------------------------------
sl@0
  1066
 */
sl@0
  1067
sl@0
  1068
EXPORT_C void
sl@0
  1069
Tcl_AppendUnicodeToObj(objPtr, unicode, length)
sl@0
  1070
    register Tcl_Obj *objPtr;	/* Points to the object to append to. */
sl@0
  1071
    CONST Tcl_UniChar *unicode;	/* The unicode string to append to the
sl@0
  1072
			         * object. */
sl@0
  1073
    int length;			/* Number of chars in "unicode". */
sl@0
  1074
{
sl@0
  1075
    String *stringPtr;
sl@0
  1076
sl@0
  1077
    if (Tcl_IsShared(objPtr)) {
sl@0
  1078
	panic("Tcl_AppendUnicodeToObj called with shared object");
sl@0
  1079
    }
sl@0
  1080
sl@0
  1081
    if (length == 0) {
sl@0
  1082
	return;
sl@0
  1083
    }
sl@0
  1084
sl@0
  1085
    SetStringFromAny(NULL, objPtr);
sl@0
  1086
    stringPtr = GET_STRING(objPtr);
sl@0
  1087
sl@0
  1088
    /*
sl@0
  1089
     * If objPtr has a valid Unicode rep, then append the "unicode"
sl@0
  1090
     * to the objPtr's Unicode rep, otherwise the UTF conversion of
sl@0
  1091
     * "unicode" to objPtr's string rep.
sl@0
  1092
     */
sl@0
  1093
sl@0
  1094
    if (stringPtr->hasUnicode != 0) {
sl@0
  1095
	AppendUnicodeToUnicodeRep(objPtr, unicode, length);
sl@0
  1096
    } else {
sl@0
  1097
	AppendUnicodeToUtfRep(objPtr, unicode, length);
sl@0
  1098
    }
sl@0
  1099
}
sl@0
  1100

sl@0
  1101
/*
sl@0
  1102
 *----------------------------------------------------------------------
sl@0
  1103
 *
sl@0
  1104
 * Tcl_AppendObjToObj --
sl@0
  1105
 *
sl@0
  1106
 *	This procedure appends the string rep of one object to another.
sl@0
  1107
 *	"objPtr" cannot be a shared object.
sl@0
  1108
 *
sl@0
  1109
 * Results:
sl@0
  1110
 *	None.
sl@0
  1111
 *
sl@0
  1112
 * Side effects:
sl@0
  1113
 *	The string rep of appendObjPtr is appended to the string 
sl@0
  1114
 *	representation of objPtr.
sl@0
  1115
 *
sl@0
  1116
 *----------------------------------------------------------------------
sl@0
  1117
 */
sl@0
  1118
sl@0
  1119
EXPORT_C void
sl@0
  1120
Tcl_AppendObjToObj(objPtr, appendObjPtr)
sl@0
  1121
    Tcl_Obj *objPtr;		/* Points to the object to append to. */
sl@0
  1122
    Tcl_Obj *appendObjPtr;	/* Object to append. */
sl@0
  1123
{
sl@0
  1124
    String *stringPtr;
sl@0
  1125
    int length, numChars, allOneByteChars;
sl@0
  1126
    char *bytes;
sl@0
  1127
sl@0
  1128
    SetStringFromAny(NULL, objPtr);
sl@0
  1129
sl@0
  1130
    /*
sl@0
  1131
     * If objPtr has a valid Unicode rep, then get a Unicode string
sl@0
  1132
     * from appendObjPtr and append it.
sl@0
  1133
     */
sl@0
  1134
sl@0
  1135
    stringPtr = GET_STRING(objPtr);
sl@0
  1136
    if (stringPtr->hasUnicode != 0) {
sl@0
  1137
	
sl@0
  1138
	/*
sl@0
  1139
	 * If appendObjPtr is not of the "String" type, don't convert it.
sl@0
  1140
	 */
sl@0
  1141
sl@0
  1142
	if (appendObjPtr->typePtr == &tclStringType) {
sl@0
  1143
	    stringPtr = GET_STRING(appendObjPtr);
sl@0
  1144
	    if ((stringPtr->numChars == -1)
sl@0
  1145
		    || (stringPtr->hasUnicode == 0)) {
sl@0
  1146
		
sl@0
  1147
		/*
sl@0
  1148
		 * If appendObjPtr is a string obj with no valid Unicode
sl@0
  1149
		 * rep, then fill its unicode rep.
sl@0
  1150
		 */
sl@0
  1151
sl@0
  1152
		FillUnicodeRep(appendObjPtr);
sl@0
  1153
		stringPtr = GET_STRING(appendObjPtr);
sl@0
  1154
	    }
sl@0
  1155
	    AppendUnicodeToUnicodeRep(objPtr, stringPtr->unicode,
sl@0
  1156
		    stringPtr->numChars);
sl@0
  1157
	} else {
sl@0
  1158
	    bytes = Tcl_GetStringFromObj(appendObjPtr, &length);
sl@0
  1159
	    AppendUtfToUnicodeRep(objPtr, bytes, length);
sl@0
  1160
	}
sl@0
  1161
	return;
sl@0
  1162
    }
sl@0
  1163
sl@0
  1164
    /*
sl@0
  1165
     * Append to objPtr's UTF string rep.  If we know the number of
sl@0
  1166
     * characters in both objects before appending, then set the combined
sl@0
  1167
     * number of characters in the final (appended-to) object.
sl@0
  1168
     */
sl@0
  1169
sl@0
  1170
    bytes = Tcl_GetStringFromObj(appendObjPtr, &length);
sl@0
  1171
sl@0
  1172
    allOneByteChars = 0;
sl@0
  1173
    numChars = stringPtr->numChars;
sl@0
  1174
    if ((numChars >= 0) && (appendObjPtr->typePtr == &tclStringType)) {
sl@0
  1175
	stringPtr = GET_STRING(appendObjPtr);
sl@0
  1176
	if ((stringPtr->numChars >= 0) && (stringPtr->numChars == length)) {
sl@0
  1177
	    numChars += stringPtr->numChars;
sl@0
  1178
	    allOneByteChars = 1;
sl@0
  1179
	}
sl@0
  1180
    }
sl@0
  1181
sl@0
  1182
    AppendUtfToUtfRep(objPtr, bytes, length);
sl@0
  1183
sl@0
  1184
    if (allOneByteChars) {
sl@0
  1185
	stringPtr = GET_STRING(objPtr);
sl@0
  1186
	stringPtr->numChars = numChars;
sl@0
  1187
    }
sl@0
  1188
}
sl@0
  1189

sl@0
  1190
/*
sl@0
  1191
 *----------------------------------------------------------------------
sl@0
  1192
 *
sl@0
  1193
 * AppendUnicodeToUnicodeRep --
sl@0
  1194
 *
sl@0
  1195
 *	This procedure appends the contents of "unicode" to the Unicode
sl@0
  1196
 *	rep of "objPtr".  objPtr must already have a valid Unicode rep.
sl@0
  1197
 *
sl@0
  1198
 * Results:
sl@0
  1199
 *	None.
sl@0
  1200
 *
sl@0
  1201
 * Side effects:
sl@0
  1202
 *	objPtr's internal rep is reallocated.
sl@0
  1203
 *
sl@0
  1204
 *----------------------------------------------------------------------
sl@0
  1205
 */
sl@0
  1206
sl@0
  1207
static void
sl@0
  1208
AppendUnicodeToUnicodeRep(objPtr, unicode, appendNumChars)
sl@0
  1209
    Tcl_Obj *objPtr;	        /* Points to the object to append to. */
sl@0
  1210
    CONST Tcl_UniChar *unicode; /* String to append. */
sl@0
  1211
    int appendNumChars;	        /* Number of chars of "unicode" to append. */
sl@0
  1212
{
sl@0
  1213
    String *stringPtr, *tmpString;
sl@0
  1214
    size_t numChars;
sl@0
  1215
sl@0
  1216
    if (appendNumChars < 0) {
sl@0
  1217
	appendNumChars = 0;
sl@0
  1218
	if (unicode) {
sl@0
  1219
	    while (unicode[appendNumChars] != 0) { appendNumChars++; }
sl@0
  1220
	}
sl@0
  1221
    }
sl@0
  1222
    if (appendNumChars == 0) {
sl@0
  1223
	return;
sl@0
  1224
    }
sl@0
  1225
sl@0
  1226
    SetStringFromAny(NULL, objPtr);
sl@0
  1227
    stringPtr = GET_STRING(objPtr);
sl@0
  1228
sl@0
  1229
    /*
sl@0
  1230
     * If not enough space has been allocated for the unicode rep,
sl@0
  1231
     * reallocate the internal rep object with additional space.  First
sl@0
  1232
     * try to double the required allocation; if that fails, try a more
sl@0
  1233
     * modest increase.  See the "TCL STRING GROWTH ALGORITHM" comment at
sl@0
  1234
     * the top of this file for an explanation of this growth algorithm.
sl@0
  1235
     */
sl@0
  1236
sl@0
  1237
    numChars = stringPtr->numChars + appendNumChars;
sl@0
  1238
sl@0
  1239
    if (STRING_UALLOC(numChars) >= stringPtr->uallocated) {
sl@0
  1240
     	stringPtr->uallocated = STRING_UALLOC(2 * numChars);
sl@0
  1241
	tmpString = (String *) attemptckrealloc((char *)stringPtr,
sl@0
  1242
		STRING_SIZE(stringPtr->uallocated));
sl@0
  1243
	if (tmpString == NULL) {
sl@0
  1244
	    stringPtr->uallocated =
sl@0
  1245
	        STRING_UALLOC(numChars + appendNumChars) 
sl@0
  1246
		+ TCL_GROWTH_MIN_ALLOC;
sl@0
  1247
	    tmpString = (String *) ckrealloc((char *)stringPtr,
sl@0
  1248
		    STRING_SIZE(stringPtr->uallocated));
sl@0
  1249
	}
sl@0
  1250
	stringPtr = tmpString;
sl@0
  1251
	SET_STRING(objPtr, stringPtr);
sl@0
  1252
    }
sl@0
  1253
sl@0
  1254
    /*
sl@0
  1255
     * Copy the new string onto the end of the old string, then add the
sl@0
  1256
     * trailing null.
sl@0
  1257
     */
sl@0
  1258
sl@0
  1259
    memcpy((VOID*) (stringPtr->unicode + stringPtr->numChars), unicode,
sl@0
  1260
	    appendNumChars * sizeof(Tcl_UniChar));
sl@0
  1261
    stringPtr->unicode[numChars] = 0;
sl@0
  1262
    stringPtr->numChars = numChars;
sl@0
  1263
sl@0
  1264
    Tcl_InvalidateStringRep(objPtr);
sl@0
  1265
}
sl@0
  1266

sl@0
  1267
/*
sl@0
  1268
 *----------------------------------------------------------------------
sl@0
  1269
 *
sl@0
  1270
 * AppendUnicodeToUtfRep --
sl@0
  1271
 *
sl@0
  1272
 *	This procedure converts the contents of "unicode" to UTF and
sl@0
  1273
 *	appends the UTF to the string rep of "objPtr".
sl@0
  1274
 *
sl@0
  1275
 * Results:
sl@0
  1276
 *	None.
sl@0
  1277
 *
sl@0
  1278
 * Side effects:
sl@0
  1279
 *	objPtr's internal rep is reallocated.
sl@0
  1280
 *
sl@0
  1281
 *----------------------------------------------------------------------
sl@0
  1282
 */
sl@0
  1283
sl@0
  1284
static void
sl@0
  1285
AppendUnicodeToUtfRep(objPtr, unicode, numChars)
sl@0
  1286
    Tcl_Obj *objPtr;	        /* Points to the object to append to. */
sl@0
  1287
    CONST Tcl_UniChar *unicode; /* String to convert to UTF. */
sl@0
  1288
    int numChars;	        /* Number of chars of "unicode" to convert. */
sl@0
  1289
{
sl@0
  1290
    Tcl_DString dsPtr;
sl@0
  1291
    CONST char *bytes;
sl@0
  1292
    
sl@0
  1293
    if (numChars < 0) {
sl@0
  1294
	numChars = 0;
sl@0
  1295
	if (unicode) {
sl@0
  1296
	    while (unicode[numChars] != 0) { numChars++; }
sl@0
  1297
	}
sl@0
  1298
    }
sl@0
  1299
    if (numChars == 0) {
sl@0
  1300
	return;
sl@0
  1301
    }
sl@0
  1302
sl@0
  1303
    Tcl_DStringInit(&dsPtr);
sl@0
  1304
    bytes = Tcl_UniCharToUtfDString(unicode, numChars, &dsPtr);
sl@0
  1305
    AppendUtfToUtfRep(objPtr, bytes, Tcl_DStringLength(&dsPtr));
sl@0
  1306
    Tcl_DStringFree(&dsPtr);
sl@0
  1307
}
sl@0
  1308

sl@0
  1309
/*
sl@0
  1310
 *----------------------------------------------------------------------
sl@0
  1311
 *
sl@0
  1312
 * AppendUtfToUnicodeRep --
sl@0
  1313
 *
sl@0
  1314
 *	This procedure converts the contents of "bytes" to Unicode and
sl@0
  1315
 *	appends the Unicode to the Unicode rep of "objPtr".  objPtr must
sl@0
  1316
 *	already have a valid Unicode rep.
sl@0
  1317
 *
sl@0
  1318
 * Results:
sl@0
  1319
 *	None.
sl@0
  1320
 *
sl@0
  1321
 * Side effects:
sl@0
  1322
 *	objPtr's internal rep is reallocated.
sl@0
  1323
 *
sl@0
  1324
 *----------------------------------------------------------------------
sl@0
  1325
 */
sl@0
  1326
sl@0
  1327
static void
sl@0
  1328
AppendUtfToUnicodeRep(objPtr, bytes, numBytes)
sl@0
  1329
    Tcl_Obj *objPtr;	/* Points to the object to append to. */
sl@0
  1330
    CONST char *bytes;	/* String to convert to Unicode. */
sl@0
  1331
    int numBytes;	/* Number of bytes of "bytes" to convert. */
sl@0
  1332
{
sl@0
  1333
    Tcl_DString dsPtr;
sl@0
  1334
    int numChars;
sl@0
  1335
    Tcl_UniChar *unicode;
sl@0
  1336
sl@0
  1337
    if (numBytes < 0) {
sl@0
  1338
	numBytes = (bytes ? strlen(bytes) : 0);
sl@0
  1339
    }
sl@0
  1340
    if (numBytes == 0) {
sl@0
  1341
	return;
sl@0
  1342
    }
sl@0
  1343
    
sl@0
  1344
    Tcl_DStringInit(&dsPtr);
sl@0
  1345
    numChars = Tcl_NumUtfChars(bytes, numBytes);
sl@0
  1346
    unicode = (Tcl_UniChar *)Tcl_UtfToUniCharDString(bytes, numBytes, &dsPtr);
sl@0
  1347
    AppendUnicodeToUnicodeRep(objPtr, unicode, numChars);
sl@0
  1348
    Tcl_DStringFree(&dsPtr);
sl@0
  1349
}
sl@0
  1350

sl@0
  1351
/*
sl@0
  1352
 *----------------------------------------------------------------------
sl@0
  1353
 *
sl@0
  1354
 * AppendUtfToUtfRep --
sl@0
  1355
 *
sl@0
  1356
 *	This procedure appends "numBytes" bytes of "bytes" to the UTF string
sl@0
  1357
 *	rep of "objPtr".  objPtr must already have a valid String rep.
sl@0
  1358
 *
sl@0
  1359
 * Results:
sl@0
  1360
 *	None.
sl@0
  1361
 *
sl@0
  1362
 * Side effects:
sl@0
  1363
 *	objPtr's internal rep is reallocated.
sl@0
  1364
 *
sl@0
  1365
 *----------------------------------------------------------------------
sl@0
  1366
 */
sl@0
  1367
sl@0
  1368
static void
sl@0
  1369
AppendUtfToUtfRep(objPtr, bytes, numBytes)
sl@0
  1370
    Tcl_Obj *objPtr;	/* Points to the object to append to. */
sl@0
  1371
    CONST char *bytes;	/* String to append. */
sl@0
  1372
    int numBytes;	/* Number of bytes of "bytes" to append. */
sl@0
  1373
{
sl@0
  1374
    String *stringPtr;
sl@0
  1375
    int newLength, oldLength;
sl@0
  1376
sl@0
  1377
    if (numBytes < 0) {
sl@0
  1378
	numBytes = (bytes ? strlen(bytes) : 0);
sl@0
  1379
    }
sl@0
  1380
    if (numBytes == 0) {
sl@0
  1381
	return;
sl@0
  1382
    }
sl@0
  1383
sl@0
  1384
    /*
sl@0
  1385
     * Copy the new string onto the end of the old string, then add the
sl@0
  1386
     * trailing null.
sl@0
  1387
     */
sl@0
  1388
sl@0
  1389
    oldLength = objPtr->length;
sl@0
  1390
    newLength = numBytes + oldLength;
sl@0
  1391
sl@0
  1392
    stringPtr = GET_STRING(objPtr);
sl@0
  1393
    if (newLength > (int) stringPtr->allocated) {
sl@0
  1394
sl@0
  1395
	/*
sl@0
  1396
	 * There isn't currently enough space in the string representation
sl@0
  1397
	 * so allocate additional space.  First, try to double the length
sl@0
  1398
	 * required.  If that fails, try a more modest allocation.  See the
sl@0
  1399
	 * "TCL STRING GROWTH ALGORITHM" comment at the top of this file for an
sl@0
  1400
	 * explanation of this growth algorithm.
sl@0
  1401
	 */
sl@0
  1402
sl@0
  1403
	if (Tcl_AttemptSetObjLength(objPtr, 2 * newLength) == 0) {
sl@0
  1404
	    Tcl_SetObjLength(objPtr,
sl@0
  1405
		    newLength + numBytes + TCL_GROWTH_MIN_ALLOC);
sl@0
  1406
	}
sl@0
  1407
    }
sl@0
  1408
sl@0
  1409
    /*
sl@0
  1410
     * Invalidate the unicode data.
sl@0
  1411
     */
sl@0
  1412
    
sl@0
  1413
    stringPtr->numChars = -1;
sl@0
  1414
    stringPtr->hasUnicode = 0;
sl@0
  1415
    
sl@0
  1416
    memcpy((VOID *) (objPtr->bytes + oldLength), (VOID *) bytes,
sl@0
  1417
	    (size_t) numBytes);
sl@0
  1418
    objPtr->bytes[newLength] = 0;
sl@0
  1419
    objPtr->length = newLength;
sl@0
  1420
}
sl@0
  1421

sl@0
  1422
/*
sl@0
  1423
 *----------------------------------------------------------------------
sl@0
  1424
 *
sl@0
  1425
 * Tcl_AppendStringsToObjVA --
sl@0
  1426
 *
sl@0
  1427
 *	This procedure appends one or more null-terminated strings
sl@0
  1428
 *	to an object.
sl@0
  1429
 *
sl@0
  1430
 * Results:
sl@0
  1431
 *	None.
sl@0
  1432
 *
sl@0
  1433
 * Side effects:
sl@0
  1434
 *	The contents of all the string arguments are appended to the
sl@0
  1435
 *	string representation of objPtr.
sl@0
  1436
 *
sl@0
  1437
 *----------------------------------------------------------------------
sl@0
  1438
 */
sl@0
  1439
sl@0
  1440
EXPORT_C void
sl@0
  1441
Tcl_AppendStringsToObjVA (objPtr, argList)
sl@0
  1442
    Tcl_Obj *objPtr;		/* Points to the object to append to. */
sl@0
  1443
    va_list argList;		/* Variable argument list. */
sl@0
  1444
{
sl@0
  1445
#define STATIC_LIST_SIZE 16
sl@0
  1446
    String *stringPtr;
sl@0
  1447
    int newLength, oldLength, attemptLength;
sl@0
  1448
    register char *string, *dst;
sl@0
  1449
    char *static_list[STATIC_LIST_SIZE];
sl@0
  1450
    char **args = static_list;
sl@0
  1451
    int nargs_space = STATIC_LIST_SIZE;
sl@0
  1452
    int nargs, i;
sl@0
  1453
sl@0
  1454
    if (Tcl_IsShared(objPtr)) {
sl@0
  1455
	panic("Tcl_AppendStringsToObj called with shared object");
sl@0
  1456
    }
sl@0
  1457
sl@0
  1458
    SetStringFromAny(NULL, objPtr);
sl@0
  1459
sl@0
  1460
    /*
sl@0
  1461
     * Figure out how much space is needed for all the strings, and
sl@0
  1462
     * expand the string representation if it isn't big enough. If no
sl@0
  1463
     * bytes would be appended, just return.  Note that on some platforms
sl@0
  1464
     * (notably OS/390) the argList is an array so we need to use memcpy.
sl@0
  1465
     */
sl@0
  1466
sl@0
  1467
    nargs = 0;
sl@0
  1468
    newLength = 0;
sl@0
  1469
    oldLength = objPtr->length;
sl@0
  1470
    while (1) {
sl@0
  1471
	string = va_arg(argList, char *);
sl@0
  1472
	if (string == NULL) {
sl@0
  1473
	    break;
sl@0
  1474
	}
sl@0
  1475
 	if (nargs >= nargs_space) {
sl@0
  1476
 	    /* 
sl@0
  1477
 	     * Expand the args buffer
sl@0
  1478
 	     */
sl@0
  1479
 	    nargs_space += STATIC_LIST_SIZE;
sl@0
  1480
 	    if (args == static_list) {
sl@0
  1481
 	    	args = (void *)ckalloc(nargs_space * sizeof(char *));
sl@0
  1482
 		for (i = 0; i < nargs; ++i) {
sl@0
  1483
 		    args[i] = static_list[i];
sl@0
  1484
 		}
sl@0
  1485
 	    } else {
sl@0
  1486
 		args = (void *)ckrealloc((void *)args,
sl@0
  1487
			nargs_space * sizeof(char *));
sl@0
  1488
 	    }
sl@0
  1489
 	}
sl@0
  1490
	newLength += strlen(string);
sl@0
  1491
	args[nargs++] = string;
sl@0
  1492
    }
sl@0
  1493
    if (newLength == 0) {
sl@0
  1494
	goto done;
sl@0
  1495
    }
sl@0
  1496
sl@0
  1497
    stringPtr = GET_STRING(objPtr);
sl@0
  1498
    if (oldLength + newLength > (int) stringPtr->allocated) {
sl@0
  1499
sl@0
  1500
	/*
sl@0
  1501
	 * There isn't currently enough space in the string
sl@0
  1502
	 * representation, so allocate additional space.  If the current
sl@0
  1503
	 * string representation isn't empty (i.e. it looks like we're
sl@0
  1504
	 * doing a series of appends) then try to allocate extra space to
sl@0
  1505
	 * accomodate future growth: first try to double the required memory;
sl@0
  1506
	 * if that fails, try a more modest allocation.  See the "TCL STRING
sl@0
  1507
	 * GROWTH ALGORITHM" comment at the top of this file for an explanation
sl@0
  1508
	 * of this growth algorithm.  Otherwise, if the current string
sl@0
  1509
	 * representation is empty, exactly enough memory is allocated.
sl@0
  1510
	 */
sl@0
  1511
sl@0
  1512
	if (oldLength == 0) {
sl@0
  1513
	    Tcl_SetObjLength(objPtr, newLength);
sl@0
  1514
	} else {
sl@0
  1515
	    attemptLength = 2 * (oldLength + newLength);
sl@0
  1516
	    if (Tcl_AttemptSetObjLength(objPtr, attemptLength) == 0) {
sl@0
  1517
		attemptLength = oldLength + (2 * newLength) +
sl@0
  1518
		    TCL_GROWTH_MIN_ALLOC;
sl@0
  1519
		Tcl_SetObjLength(objPtr, attemptLength);
sl@0
  1520
	    }
sl@0
  1521
	}
sl@0
  1522
    }
sl@0
  1523
sl@0
  1524
    /*
sl@0
  1525
     * Make a second pass through the arguments, appending all the
sl@0
  1526
     * strings to the object.
sl@0
  1527
     */
sl@0
  1528
sl@0
  1529
    dst = objPtr->bytes + oldLength;
sl@0
  1530
    for (i = 0; i < nargs; ++i) {
sl@0
  1531
 	string = args[i];
sl@0
  1532
	if (string == NULL) {
sl@0
  1533
	    break;
sl@0
  1534
	}
sl@0
  1535
	while (*string != 0) {
sl@0
  1536
	    *dst = *string;
sl@0
  1537
	    dst++;
sl@0
  1538
	    string++;
sl@0
  1539
	}
sl@0
  1540
    }
sl@0
  1541
sl@0
  1542
    /*
sl@0
  1543
     * Add a null byte to terminate the string.  However, be careful:
sl@0
  1544
     * it's possible that the object is totally empty (if it was empty
sl@0
  1545
     * originally and there was nothing to append).  In this case dst is
sl@0
  1546
     * NULL; just leave everything alone.
sl@0
  1547
     */
sl@0
  1548
sl@0
  1549
    if (dst != NULL) {
sl@0
  1550
	*dst = 0;
sl@0
  1551
    }
sl@0
  1552
    objPtr->length = oldLength + newLength;
sl@0
  1553
sl@0
  1554
    done:
sl@0
  1555
    /*
sl@0
  1556
     * If we had to allocate a buffer from the heap, 
sl@0
  1557
     * free it now.
sl@0
  1558
     */
sl@0
  1559
 
sl@0
  1560
    if (args != static_list) {
sl@0
  1561
     	ckfree((void *)args);
sl@0
  1562
    }
sl@0
  1563
#undef STATIC_LIST_SIZE
sl@0
  1564
}
sl@0
  1565

sl@0
  1566
/*
sl@0
  1567
 *----------------------------------------------------------------------
sl@0
  1568
 *
sl@0
  1569
 * Tcl_AppendStringsToObj --
sl@0
  1570
 *
sl@0
  1571
 *	This procedure appends one or more null-terminated strings
sl@0
  1572
 *	to an object.
sl@0
  1573
 *
sl@0
  1574
 * Results:
sl@0
  1575
 *	None.
sl@0
  1576
 *
sl@0
  1577
 * Side effects:
sl@0
  1578
 *	The contents of all the string arguments are appended to the
sl@0
  1579
 *	string representation of objPtr.
sl@0
  1580
 *
sl@0
  1581
 *----------------------------------------------------------------------
sl@0
  1582
 */
sl@0
  1583
sl@0
  1584
EXPORT_C void
sl@0
  1585
Tcl_AppendStringsToObj TCL_VARARGS_DEF(Tcl_Obj *,arg1)
sl@0
  1586
{
sl@0
  1587
    register Tcl_Obj *objPtr;
sl@0
  1588
    va_list argList;
sl@0
  1589
sl@0
  1590
    objPtr = TCL_VARARGS_START(Tcl_Obj *,arg1,argList);
sl@0
  1591
    Tcl_AppendStringsToObjVA(objPtr, argList);
sl@0
  1592
    va_end(argList);
sl@0
  1593
}
sl@0
  1594

sl@0
  1595
/*
sl@0
  1596
 *---------------------------------------------------------------------------
sl@0
  1597
 *
sl@0
  1598
 * FillUnicodeRep --
sl@0
  1599
 *
sl@0
  1600
 *	Populate the Unicode internal rep with the Unicode form of its string
sl@0
  1601
 *	rep.  The object must alread have a "String" internal rep.
sl@0
  1602
 *
sl@0
  1603
 * Results:
sl@0
  1604
 *	None.
sl@0
  1605
 *
sl@0
  1606
 * Side effects:
sl@0
  1607
 *	Reallocates the String internal rep.
sl@0
  1608
 *
sl@0
  1609
 *---------------------------------------------------------------------------
sl@0
  1610
 */
sl@0
  1611
sl@0
  1612
static void
sl@0
  1613
FillUnicodeRep(objPtr)
sl@0
  1614
    Tcl_Obj *objPtr;	/* The object in which to fill the unicode rep. */
sl@0
  1615
{
sl@0
  1616
    String *stringPtr;
sl@0
  1617
    size_t uallocated;
sl@0
  1618
    char *src, *srcEnd;
sl@0
  1619
    Tcl_UniChar *dst;
sl@0
  1620
    src = objPtr->bytes;
sl@0
  1621
    
sl@0
  1622
    stringPtr = GET_STRING(objPtr);
sl@0
  1623
    if (stringPtr->numChars == -1) {
sl@0
  1624
	stringPtr->numChars = Tcl_NumUtfChars(src, objPtr->length);
sl@0
  1625
    }
sl@0
  1626
    stringPtr->hasUnicode = (stringPtr->numChars > 0);
sl@0
  1627
sl@0
  1628
    uallocated = STRING_UALLOC(stringPtr->numChars);
sl@0
  1629
    if (uallocated > stringPtr->uallocated) {
sl@0
  1630
    
sl@0
  1631
	/*
sl@0
  1632
	 * If not enough space has been allocated for the unicode rep,
sl@0
  1633
	 * reallocate the internal rep object.
sl@0
  1634
	 */
sl@0
  1635
sl@0
  1636
	/*
sl@0
  1637
	 * There isn't currently enough space in the Unicode
sl@0
  1638
	 * representation so allocate additional space.  If the current
sl@0
  1639
	 * Unicode representation isn't empty (i.e. it looks like we've
sl@0
  1640
	 * done some appends) then overallocate the space so
sl@0
  1641
	 * that we won't have to do as much reallocation in the future.
sl@0
  1642
	 */
sl@0
  1643
sl@0
  1644
	if (stringPtr->uallocated > 0) {
sl@0
  1645
	    uallocated *= 2;
sl@0
  1646
	}
sl@0
  1647
	stringPtr = (String *) ckrealloc((char*) stringPtr,
sl@0
  1648
		STRING_SIZE(uallocated));
sl@0
  1649
	stringPtr->uallocated = uallocated;
sl@0
  1650
    }
sl@0
  1651
sl@0
  1652
    /*
sl@0
  1653
     * Convert src to Unicode and store the coverted data in "unicode".
sl@0
  1654
     */
sl@0
  1655
    
sl@0
  1656
    srcEnd = src + objPtr->length;
sl@0
  1657
    for (dst = stringPtr->unicode; src < srcEnd; dst++) {
sl@0
  1658
	src += TclUtfToUniChar(src, dst);
sl@0
  1659
    }
sl@0
  1660
    *dst = 0;
sl@0
  1661
    
sl@0
  1662
    SET_STRING(objPtr, stringPtr);
sl@0
  1663
}
sl@0
  1664

sl@0
  1665
/*
sl@0
  1666
 *----------------------------------------------------------------------
sl@0
  1667
 *
sl@0
  1668
 * DupStringInternalRep --
sl@0
  1669
 *
sl@0
  1670
 *	Initialize the internal representation of a new Tcl_Obj to a
sl@0
  1671
 *	copy of the internal representation of an existing string object.
sl@0
  1672
 *
sl@0
  1673
 * Results:
sl@0
  1674
 *	None.
sl@0
  1675
 *
sl@0
  1676
 * Side effects:
sl@0
  1677
 *	copyPtr's internal rep is set to a copy of srcPtr's internal
sl@0
  1678
 *	representation.
sl@0
  1679
 *
sl@0
  1680
 *----------------------------------------------------------------------
sl@0
  1681
 */
sl@0
  1682
sl@0
  1683
static void
sl@0
  1684
DupStringInternalRep(srcPtr, copyPtr)
sl@0
  1685
    register Tcl_Obj *srcPtr;	/* Object with internal rep to copy.  Must
sl@0
  1686
				 * have an internal rep of type "String". */
sl@0
  1687
    register Tcl_Obj *copyPtr;	/* Object with internal rep to set.  Must
sl@0
  1688
				 * not currently have an internal rep.*/
sl@0
  1689
{
sl@0
  1690
    String *srcStringPtr = GET_STRING(srcPtr);
sl@0
  1691
    String *copyStringPtr = NULL;
sl@0
  1692
sl@0
  1693
    /*
sl@0
  1694
     * If the src obj is a string of 1-byte Utf chars, then copy the
sl@0
  1695
     * string rep of the source object and create an "empty" Unicode
sl@0
  1696
     * internal rep for the new object.  Otherwise, copy Unicode
sl@0
  1697
     * internal rep, and invalidate the string rep of the new object.
sl@0
  1698
     */
sl@0
  1699
    
sl@0
  1700
    if (srcStringPtr->hasUnicode == 0) {
sl@0
  1701
    	copyStringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0)));
sl@0
  1702
	copyStringPtr->uallocated = STRING_UALLOC(0);
sl@0
  1703
    } else {
sl@0
  1704
	copyStringPtr = (String *) ckalloc(
sl@0
  1705
	    STRING_SIZE(srcStringPtr->uallocated));
sl@0
  1706
	copyStringPtr->uallocated = srcStringPtr->uallocated;
sl@0
  1707
sl@0
  1708
	memcpy((VOID *) copyStringPtr->unicode,
sl@0
  1709
		(VOID *) srcStringPtr->unicode,
sl@0
  1710
		(size_t) srcStringPtr->numChars * sizeof(Tcl_UniChar));
sl@0
  1711
	copyStringPtr->unicode[srcStringPtr->numChars] = 0;
sl@0
  1712
    }
sl@0
  1713
    copyStringPtr->numChars = srcStringPtr->numChars;
sl@0
  1714
    copyStringPtr->hasUnicode = srcStringPtr->hasUnicode;
sl@0
  1715
    copyStringPtr->allocated = srcStringPtr->allocated;
sl@0
  1716
sl@0
  1717
    /*
sl@0
  1718
     * Tricky point: the string value was copied by generic object
sl@0
  1719
     * management code, so it doesn't contain any extra bytes that
sl@0
  1720
     * might exist in the source object.
sl@0
  1721
     */
sl@0
  1722
sl@0
  1723
    copyStringPtr->allocated = copyPtr->length;
sl@0
  1724
sl@0
  1725
    SET_STRING(copyPtr, copyStringPtr);
sl@0
  1726
    copyPtr->typePtr = &tclStringType;
sl@0
  1727
}
sl@0
  1728

sl@0
  1729
/*
sl@0
  1730
 *----------------------------------------------------------------------
sl@0
  1731
 *
sl@0
  1732
 * SetStringFromAny --
sl@0
  1733
 *
sl@0
  1734
 *	Create an internal representation of type "String" for an object.
sl@0
  1735
 *
sl@0
  1736
 * Results:
sl@0
  1737
 *	This operation always succeeds and returns TCL_OK.
sl@0
  1738
 *
sl@0
  1739
 * Side effects:
sl@0
  1740
 *	Any old internal reputation for objPtr is freed and the
sl@0
  1741
 *	internal representation is set to "String".
sl@0
  1742
 *
sl@0
  1743
 *----------------------------------------------------------------------
sl@0
  1744
 */
sl@0
  1745
sl@0
  1746
static int
sl@0
  1747
SetStringFromAny(interp, objPtr)
sl@0
  1748
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
sl@0
  1749
    register Tcl_Obj *objPtr;	/* The object to convert. */
sl@0
  1750
{
sl@0
  1751
    /*
sl@0
  1752
     * The Unicode object is optimized for the case where each UTF char
sl@0
  1753
     * in a string is only one byte.  In this case, we store the value of
sl@0
  1754
     * numChars, but we don't copy the bytes to the unicodeObj->unicode.
sl@0
  1755
     */
sl@0
  1756
sl@0
  1757
    if (objPtr->typePtr != &tclStringType) {
sl@0
  1758
	String *stringPtr;
sl@0
  1759
sl@0
  1760
	if (objPtr->typePtr != NULL) {
sl@0
  1761
	    if (objPtr->bytes == NULL) {
sl@0
  1762
		objPtr->typePtr->updateStringProc(objPtr);
sl@0
  1763
	    }
sl@0
  1764
	    if ((objPtr->typePtr->freeIntRepProc) != NULL) {
sl@0
  1765
		(*objPtr->typePtr->freeIntRepProc)(objPtr);
sl@0
  1766
	    }
sl@0
  1767
	}
sl@0
  1768
	objPtr->typePtr = &tclStringType;
sl@0
  1769
sl@0
  1770
	/*
sl@0
  1771
	 * Allocate enough space for the basic String structure.
sl@0
  1772
	 */
sl@0
  1773
sl@0
  1774
	stringPtr = (String *) ckalloc(STRING_SIZE(STRING_UALLOC(0)));
sl@0
  1775
	stringPtr->numChars = -1;
sl@0
  1776
	stringPtr->uallocated = STRING_UALLOC(0);
sl@0
  1777
	stringPtr->hasUnicode = 0;
sl@0
  1778
sl@0
  1779
	if (objPtr->bytes != NULL) {
sl@0
  1780
	    stringPtr->allocated = objPtr->length;	    
sl@0
  1781
 	    objPtr->bytes[objPtr->length] = 0;
sl@0
  1782
	} else {
sl@0
  1783
	    objPtr->length = 0;
sl@0
  1784
	}
sl@0
  1785
	SET_STRING(objPtr, stringPtr);
sl@0
  1786
    }
sl@0
  1787
    return TCL_OK;
sl@0
  1788
}
sl@0
  1789

sl@0
  1790
/*
sl@0
  1791
 *----------------------------------------------------------------------
sl@0
  1792
 *
sl@0
  1793
 * UpdateStringOfString --
sl@0
  1794
 *
sl@0
  1795
 *	Update the string representation for an object whose internal
sl@0
  1796
 *	representation is "String".
sl@0
  1797
 *
sl@0
  1798
 * Results:
sl@0
  1799
 *	None.
sl@0
  1800
 *
sl@0
  1801
 * Side effects:
sl@0
  1802
 *	The object's string may be set by converting its Unicode
sl@0
  1803
 *	represention to UTF format.
sl@0
  1804
 *
sl@0
  1805
 *----------------------------------------------------------------------
sl@0
  1806
 */
sl@0
  1807
sl@0
  1808
static void
sl@0
  1809
UpdateStringOfString(objPtr)
sl@0
  1810
    Tcl_Obj *objPtr;		/* Object with string rep to update. */
sl@0
  1811
{
sl@0
  1812
    int i, size;
sl@0
  1813
    Tcl_UniChar *unicode;
sl@0
  1814
    char dummy[TCL_UTF_MAX];
sl@0
  1815
    char *dst;
sl@0
  1816
    String *stringPtr;
sl@0
  1817
sl@0
  1818
    stringPtr = GET_STRING(objPtr);
sl@0
  1819
    if ((objPtr->bytes == NULL) || (stringPtr->allocated == 0)) {
sl@0
  1820
sl@0
  1821
	if (stringPtr->numChars <= 0) {
sl@0
  1822
sl@0
  1823
	    /*
sl@0
  1824
	     * If there is no Unicode rep, or the string has 0 chars,
sl@0
  1825
	     * then set the string rep to an empty string.
sl@0
  1826
	     */
sl@0
  1827
sl@0
  1828
	    objPtr->bytes = tclEmptyStringRep;
sl@0
  1829
	    objPtr->length = 0;
sl@0
  1830
	    return;
sl@0
  1831
	}
sl@0
  1832
sl@0
  1833
	unicode = stringPtr->unicode;
sl@0
  1834
sl@0
  1835
	/*
sl@0
  1836
	 * Translate the Unicode string to UTF.  "size" will hold the
sl@0
  1837
	 * amount of space the UTF string needs.
sl@0
  1838
	 */
sl@0
  1839
sl@0
  1840
	size = 0;
sl@0
  1841
	for (i = 0; i < stringPtr->numChars; i++) {
sl@0
  1842
	    size += Tcl_UniCharToUtf((int) unicode[i], dummy);
sl@0
  1843
	}
sl@0
  1844
	
sl@0
  1845
	dst = (char *) ckalloc((unsigned) (size + 1));
sl@0
  1846
	objPtr->bytes = dst;
sl@0
  1847
	objPtr->length = size;
sl@0
  1848
	stringPtr->allocated = size;
sl@0
  1849
sl@0
  1850
	for (i = 0; i < stringPtr->numChars; i++) {
sl@0
  1851
	    dst += Tcl_UniCharToUtf(unicode[i], dst);
sl@0
  1852
	}
sl@0
  1853
	*dst = '\0';
sl@0
  1854
    }
sl@0
  1855
    return;
sl@0
  1856
}
sl@0
  1857

sl@0
  1858
/*
sl@0
  1859
 *----------------------------------------------------------------------
sl@0
  1860
 *
sl@0
  1861
 * FreeStringInternalRep --
sl@0
  1862
 *
sl@0
  1863
 *	Deallocate the storage associated with a String data object's
sl@0
  1864
 *	internal representation.
sl@0
  1865
 *
sl@0
  1866
 * Results:
sl@0
  1867
 *	None.
sl@0
  1868
 *
sl@0
  1869
 * Side effects:
sl@0
  1870
 *	Frees memory. 
sl@0
  1871
 *
sl@0
  1872
 *----------------------------------------------------------------------
sl@0
  1873
 */
sl@0
  1874
sl@0
  1875
static void
sl@0
  1876
FreeStringInternalRep(objPtr)
sl@0
  1877
    Tcl_Obj *objPtr;		/* Object with internal rep to free. */
sl@0
  1878
{
sl@0
  1879
    ckfree((char *) GET_STRING(objPtr));
sl@0
  1880
}