os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclUtil.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* 
sl@0
     2
 * tclUtil.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains utility procedures that are used by many Tcl
sl@0
     5
 *	commands.
sl@0
     6
 *
sl@0
     7
 * Copyright (c) 1987-1993 The Regents of the University of California.
sl@0
     8
 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
sl@0
     9
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
sl@0
    10
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    11
 *
sl@0
    12
 * See the file "license.terms" for information on usage and redistribution
sl@0
    13
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    14
 *
sl@0
    15
 *  RCS: @(#) $Id: tclUtil.c,v 1.36.2.8 2007/05/10 18:23:58 dgp Exp $
sl@0
    16
 */
sl@0
    17
sl@0
    18
#include "tclInt.h"
sl@0
    19
#include "tclPort.h"
sl@0
    20
#if defined(__SYMBIAN32__) 
sl@0
    21
#include "tclSymbianGlobals.h"
sl@0
    22
#endif 
sl@0
    23
sl@0
    24
/*
sl@0
    25
 * The following variable holds the full path name of the binary
sl@0
    26
 * from which this application was executed, or NULL if it isn't
sl@0
    27
 * know.  The value of the variable is set by the procedure
sl@0
    28
 * Tcl_FindExecutable.  The storage space is dynamically allocated.
sl@0
    29
 */
sl@0
    30
sl@0
    31
#if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
sl@0
    32
char *tclExecutableName = NULL;
sl@0
    33
char *tclNativeExecutableName = NULL;
sl@0
    34
#endif
sl@0
    35
sl@0
    36
/*
sl@0
    37
 * The following values are used in the flags returned by Tcl_ScanElement
sl@0
    38
 * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
sl@0
    39
 * defined in tcl.h;  make sure its value doesn't overlap with any of the
sl@0
    40
 * values below.
sl@0
    41
 *
sl@0
    42
 * TCL_DONT_USE_BRACES -	1 means the string mustn't be enclosed in
sl@0
    43
 *				braces (e.g. it contains unmatched braces,
sl@0
    44
 *				or ends in a backslash character, or user
sl@0
    45
 *				just doesn't want braces);  handle all
sl@0
    46
 *				special characters by adding backslashes.
sl@0
    47
 * USE_BRACES -			1 means the string contains a special
sl@0
    48
 *				character that can be handled simply by
sl@0
    49
 *				enclosing the entire argument in braces.
sl@0
    50
 * BRACES_UNMATCHED -		1 means that braces aren't properly matched
sl@0
    51
 *				in the argument.
sl@0
    52
 */
sl@0
    53
sl@0
    54
#define USE_BRACES		2
sl@0
    55
#define BRACES_UNMATCHED	4
sl@0
    56
sl@0
    57
/*
sl@0
    58
 * The following values determine the precision used when converting
sl@0
    59
 * floating-point values to strings.  This information is linked to all
sl@0
    60
 * of the tcl_precision variables in all interpreters via the procedure
sl@0
    61
 * TclPrecTraceProc.
sl@0
    62
 */
sl@0
    63
sl@0
    64
static char precisionString[10] = "12";
sl@0
    65
				/* The string value of all the tcl_precision
sl@0
    66
				 * variables. */
sl@0
    67
static char precisionFormat[10] = "%.12g";
sl@0
    68
				/* The format string actually used in calls
sl@0
    69
				 * to sprintf. */
sl@0
    70
TCL_DECLARE_MUTEX(precisionMutex)
sl@0
    71
sl@0
    72
/*
sl@0
    73
 * Prototypes for procedures defined later in this file.
sl@0
    74
 */
sl@0
    75
sl@0
    76
static void UpdateStringOfEndOffset _ANSI_ARGS_((Tcl_Obj* objPtr));
sl@0
    77
static int SetEndOffsetFromAny _ANSI_ARGS_((Tcl_Interp* interp,
sl@0
    78
					    Tcl_Obj* objPtr));
sl@0
    79
sl@0
    80
/*
sl@0
    81
 * The following is the Tcl object type definition for an object
sl@0
    82
 * that represents a list index in the form, "end-offset".  It is
sl@0
    83
 * used as a performance optimization in TclGetIntForIndex.  The
sl@0
    84
 * internal rep is an integer, so no memory management is required
sl@0
    85
 * for it.
sl@0
    86
 */
sl@0
    87
sl@0
    88
Tcl_ObjType tclEndOffsetType = {
sl@0
    89
    "end-offset",			/* name */
sl@0
    90
    (Tcl_FreeInternalRepProc*) NULL,    /* freeIntRepProc */
sl@0
    91
    (Tcl_DupInternalRepProc*) NULL,     /* dupIntRepProc */
sl@0
    92
    UpdateStringOfEndOffset,		/* updateStringProc */
sl@0
    93
    SetEndOffsetFromAny    
sl@0
    94
};
sl@0
    95
sl@0
    96

sl@0
    97
/*
sl@0
    98
 *----------------------------------------------------------------------
sl@0
    99
 *
sl@0
   100
 * TclFindElement --
sl@0
   101
 *
sl@0
   102
 *	Given a pointer into a Tcl list, locate the first (or next)
sl@0
   103
 *	element in the list.
sl@0
   104
 *
sl@0
   105
 * Results:
sl@0
   106
 *	The return value is normally TCL_OK, which means that the
sl@0
   107
 *	element was successfully located.  If TCL_ERROR is returned
sl@0
   108
 *	it means that list didn't have proper list structure;
sl@0
   109
 *	the interp's result contains a more detailed error message.
sl@0
   110
 *
sl@0
   111
 *	If TCL_OK is returned, then *elementPtr will be set to point to the
sl@0
   112
 *	first element of list, and *nextPtr will be set to point to the
sl@0
   113
 *	character just after any white space following the last character
sl@0
   114
 *	that's part of the element. If this is the last argument in the
sl@0
   115
 *	list, then *nextPtr will point just after the last character in the
sl@0
   116
 *	list (i.e., at the character at list+listLength). If sizePtr is
sl@0
   117
 *	non-NULL, *sizePtr is filled in with the number of characters in the
sl@0
   118
 *	element.  If the element is in braces, then *elementPtr will point
sl@0
   119
 *	to the character after the opening brace and *sizePtr will not
sl@0
   120
 *	include either of the braces. If there isn't an element in the list,
sl@0
   121
 *	*sizePtr will be zero, and both *elementPtr and *termPtr will point
sl@0
   122
 *	just after the last character in the list. Note: this procedure does
sl@0
   123
 *	NOT collapse backslash sequences.
sl@0
   124
 *
sl@0
   125
 * Side effects:
sl@0
   126
 *	None.
sl@0
   127
 *
sl@0
   128
 *----------------------------------------------------------------------
sl@0
   129
 */
sl@0
   130
sl@0
   131
int
sl@0
   132
TclFindElement(interp, list, listLength, elementPtr, nextPtr, sizePtr,
sl@0
   133
	       bracePtr)
sl@0
   134
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. 
sl@0
   135
				 * If NULL, then no error message is left
sl@0
   136
				 * after errors. */
sl@0
   137
    CONST char *list;		/* Points to the first byte of a string
sl@0
   138
				 * containing a Tcl list with zero or more
sl@0
   139
				 * elements (possibly in braces). */
sl@0
   140
    int listLength;		/* Number of bytes in the list's string. */
sl@0
   141
    CONST char **elementPtr;	/* Where to put address of first significant
sl@0
   142
				 * character in first element of list. */
sl@0
   143
    CONST char **nextPtr;	/* Fill in with location of character just
sl@0
   144
				 * after all white space following end of
sl@0
   145
				 * argument (next arg or end of list). */
sl@0
   146
    int *sizePtr;		/* If non-zero, fill in with size of
sl@0
   147
				 * element. */
sl@0
   148
    int *bracePtr;		/* If non-zero, fill in with non-zero/zero
sl@0
   149
				 * to indicate that arg was/wasn't
sl@0
   150
				 * in braces. */
sl@0
   151
{
sl@0
   152
    CONST char *p = list;
sl@0
   153
    CONST char *elemStart;	/* Points to first byte of first element. */
sl@0
   154
    CONST char *limit;		/* Points just after list's last byte. */
sl@0
   155
    int openBraces = 0;		/* Brace nesting level during parse. */
sl@0
   156
    int inQuotes = 0;
sl@0
   157
    int size = 0;		/* lint. */
sl@0
   158
    int numChars;
sl@0
   159
    CONST char *p2;
sl@0
   160
    
sl@0
   161
    /*
sl@0
   162
     * Skim off leading white space and check for an opening brace or
sl@0
   163
     * quote. We treat embedded NULLs in the list as bytes belonging to
sl@0
   164
     * a list element.
sl@0
   165
     */
sl@0
   166
sl@0
   167
    limit = (list + listLength);
sl@0
   168
    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
sl@0
   169
	p++;
sl@0
   170
    }
sl@0
   171
    if (p == limit) {		/* no element found */
sl@0
   172
	elemStart = limit;
sl@0
   173
	goto done;
sl@0
   174
    }
sl@0
   175
sl@0
   176
    if (*p == '{') {
sl@0
   177
	openBraces = 1;
sl@0
   178
	p++;
sl@0
   179
    } else if (*p == '"') {
sl@0
   180
	inQuotes = 1;
sl@0
   181
	p++;
sl@0
   182
    }
sl@0
   183
    elemStart = p;
sl@0
   184
    if (bracePtr != 0) {
sl@0
   185
	*bracePtr = openBraces;
sl@0
   186
    }
sl@0
   187
sl@0
   188
    /*
sl@0
   189
     * Find element's end (a space, close brace, or the end of the string).
sl@0
   190
     */
sl@0
   191
sl@0
   192
    while (p < limit) {
sl@0
   193
	switch (*p) {
sl@0
   194
sl@0
   195
	    /*
sl@0
   196
	     * Open brace: don't treat specially unless the element is in
sl@0
   197
	     * braces. In this case, keep a nesting count.
sl@0
   198
	     */
sl@0
   199
sl@0
   200
	    case '{':
sl@0
   201
		if (openBraces != 0) {
sl@0
   202
		    openBraces++;
sl@0
   203
		}
sl@0
   204
		break;
sl@0
   205
sl@0
   206
	    /*
sl@0
   207
	     * Close brace: if element is in braces, keep nesting count and
sl@0
   208
	     * quit when the last close brace is seen.
sl@0
   209
	     */
sl@0
   210
sl@0
   211
	    case '}':
sl@0
   212
		if (openBraces > 1) {
sl@0
   213
		    openBraces--;
sl@0
   214
		} else if (openBraces == 1) {
sl@0
   215
		    size = (p - elemStart);
sl@0
   216
		    p++;
sl@0
   217
		    if ((p >= limit)
sl@0
   218
			    || isspace(UCHAR(*p))) { /* INTL: ISO space. */
sl@0
   219
			goto done;
sl@0
   220
		    }
sl@0
   221
sl@0
   222
		    /*
sl@0
   223
		     * Garbage after the closing brace; return an error.
sl@0
   224
		     */
sl@0
   225
		    
sl@0
   226
		    if (interp != NULL) {
sl@0
   227
			char buf[100];
sl@0
   228
			
sl@0
   229
			p2 = p;
sl@0
   230
			while ((p2 < limit)
sl@0
   231
				&& (!isspace(UCHAR(*p2))) /* INTL: ISO space. */
sl@0
   232
			        && (p2 < p+20)) {
sl@0
   233
			    p2++;
sl@0
   234
			}
sl@0
   235
			sprintf(buf,
sl@0
   236
				"list element in braces followed by \"%.*s\" instead of space",
sl@0
   237
				(int) (p2-p), p);
sl@0
   238
			Tcl_SetResult(interp, buf, TCL_VOLATILE);
sl@0
   239
		    }
sl@0
   240
		    return TCL_ERROR;
sl@0
   241
		}
sl@0
   242
		break;
sl@0
   243
sl@0
   244
	    /*
sl@0
   245
	     * Backslash:  skip over everything up to the end of the
sl@0
   246
	     * backslash sequence.
sl@0
   247
	     */
sl@0
   248
sl@0
   249
	    case '\\': {
sl@0
   250
		Tcl_UtfBackslash(p, &numChars, NULL);
sl@0
   251
		p += (numChars - 1);
sl@0
   252
		break;
sl@0
   253
	    }
sl@0
   254
sl@0
   255
	    /*
sl@0
   256
	     * Space: ignore if element is in braces or quotes; otherwise
sl@0
   257
	     * terminate element.
sl@0
   258
	     */
sl@0
   259
sl@0
   260
	    case ' ':
sl@0
   261
	    case '\f':
sl@0
   262
	    case '\n':
sl@0
   263
	    case '\r':
sl@0
   264
	    case '\t':
sl@0
   265
	    case '\v':
sl@0
   266
		if ((openBraces == 0) && !inQuotes) {
sl@0
   267
		    size = (p - elemStart);
sl@0
   268
		    goto done;
sl@0
   269
		}
sl@0
   270
		break;
sl@0
   271
sl@0
   272
	    /*
sl@0
   273
	     * Double-quote: if element is in quotes then terminate it.
sl@0
   274
	     */
sl@0
   275
sl@0
   276
	    case '"':
sl@0
   277
		if (inQuotes) {
sl@0
   278
		    size = (p - elemStart);
sl@0
   279
		    p++;
sl@0
   280
		    if ((p >= limit)
sl@0
   281
			    || isspace(UCHAR(*p))) { /* INTL: ISO space */
sl@0
   282
			goto done;
sl@0
   283
		    }
sl@0
   284
sl@0
   285
		    /*
sl@0
   286
		     * Garbage after the closing quote; return an error.
sl@0
   287
		     */
sl@0
   288
		    
sl@0
   289
		    if (interp != NULL) {
sl@0
   290
			char buf[100];
sl@0
   291
			
sl@0
   292
			p2 = p;
sl@0
   293
			while ((p2 < limit)
sl@0
   294
				&& (!isspace(UCHAR(*p2))) /* INTL: ISO space */
sl@0
   295
				 && (p2 < p+20)) {
sl@0
   296
			    p2++;
sl@0
   297
			}
sl@0
   298
			sprintf(buf,
sl@0
   299
				"list element in quotes followed by \"%.*s\" %s",
sl@0
   300
				(int) (p2-p), p, "instead of space");
sl@0
   301
			Tcl_SetResult(interp, buf, TCL_VOLATILE);
sl@0
   302
		    }
sl@0
   303
		    return TCL_ERROR;
sl@0
   304
		}
sl@0
   305
		break;
sl@0
   306
	}
sl@0
   307
	p++;
sl@0
   308
    }
sl@0
   309
sl@0
   310
sl@0
   311
    /*
sl@0
   312
     * End of list: terminate element.
sl@0
   313
     */
sl@0
   314
sl@0
   315
    if (p == limit) {
sl@0
   316
	if (openBraces != 0) {
sl@0
   317
	    if (interp != NULL) {
sl@0
   318
		Tcl_SetResult(interp, "unmatched open brace in list",
sl@0
   319
			TCL_STATIC);
sl@0
   320
	    }
sl@0
   321
	    return TCL_ERROR;
sl@0
   322
	} else if (inQuotes) {
sl@0
   323
	    if (interp != NULL) {
sl@0
   324
		Tcl_SetResult(interp, "unmatched open quote in list",
sl@0
   325
			TCL_STATIC);
sl@0
   326
	    }
sl@0
   327
	    return TCL_ERROR;
sl@0
   328
	}
sl@0
   329
	size = (p - elemStart);
sl@0
   330
    }
sl@0
   331
sl@0
   332
    done:
sl@0
   333
    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
sl@0
   334
	p++;
sl@0
   335
    }
sl@0
   336
    *elementPtr = elemStart;
sl@0
   337
    *nextPtr = p;
sl@0
   338
    if (sizePtr != 0) {
sl@0
   339
	*sizePtr = size;
sl@0
   340
    }
sl@0
   341
    return TCL_OK;
sl@0
   342
}
sl@0
   343

sl@0
   344
/*
sl@0
   345
 *----------------------------------------------------------------------
sl@0
   346
 *
sl@0
   347
 * TclCopyAndCollapse --
sl@0
   348
 *
sl@0
   349
 *	Copy a string and eliminate any backslashes that aren't in braces.
sl@0
   350
 *
sl@0
   351
 * Results:
sl@0
   352
 *	Count characters get copied from src to	dst. Along the way, if
sl@0
   353
 *	backslash sequences are found outside braces, the backslashes are
sl@0
   354
 *	eliminated in the copy. After scanning count chars from source, a
sl@0
   355
 *	null character is placed at the end of dst.  Returns the number
sl@0
   356
 *	of characters that got copied.
sl@0
   357
 *
sl@0
   358
 * Side effects:
sl@0
   359
 *	None.
sl@0
   360
 *
sl@0
   361
 *----------------------------------------------------------------------
sl@0
   362
 */
sl@0
   363
sl@0
   364
int
sl@0
   365
TclCopyAndCollapse(count, src, dst)
sl@0
   366
    int count;			/* Number of characters to copy from src. */
sl@0
   367
    CONST char *src;		/* Copy from here... */
sl@0
   368
    char *dst;			/* ... to here. */
sl@0
   369
{
sl@0
   370
    register char c;
sl@0
   371
    int numRead;
sl@0
   372
    int newCount = 0;
sl@0
   373
    int backslashCount;
sl@0
   374
sl@0
   375
    for (c = *src;  count > 0;  src++, c = *src, count--) {
sl@0
   376
	if (c == '\\') {
sl@0
   377
	    backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
sl@0
   378
	    dst += backslashCount;
sl@0
   379
	    newCount += backslashCount;
sl@0
   380
	    src += numRead-1;
sl@0
   381
	    count -= numRead-1;
sl@0
   382
	} else {
sl@0
   383
	    *dst = c;
sl@0
   384
	    dst++;
sl@0
   385
	    newCount++;
sl@0
   386
	}
sl@0
   387
    }
sl@0
   388
    *dst = 0;
sl@0
   389
    return newCount;
sl@0
   390
}
sl@0
   391

sl@0
   392
/*
sl@0
   393
 *----------------------------------------------------------------------
sl@0
   394
 *
sl@0
   395
 * Tcl_SplitList --
sl@0
   396
 *
sl@0
   397
 *	Splits a list up into its constituent fields.
sl@0
   398
 *
sl@0
   399
 * Results
sl@0
   400
 *	The return value is normally TCL_OK, which means that
sl@0
   401
 *	the list was successfully split up.  If TCL_ERROR is
sl@0
   402
 *	returned, it means that "list" didn't have proper list
sl@0
   403
 *	structure;  the interp's result will contain a more detailed
sl@0
   404
 *	error message.
sl@0
   405
 *
sl@0
   406
 *	*argvPtr will be filled in with the address of an array
sl@0
   407
 *	whose elements point to the elements of list, in order.
sl@0
   408
 *	*argcPtr will get filled in with the number of valid elements
sl@0
   409
 *	in the array.  A single block of memory is dynamically allocated
sl@0
   410
 *	to hold both the argv array and a copy of the list (with
sl@0
   411
 *	backslashes and braces removed in the standard way).
sl@0
   412
 *	The caller must eventually free this memory by calling free()
sl@0
   413
 *	on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
sl@0
   414
 *	if the procedure returns normally.
sl@0
   415
 *
sl@0
   416
 * Side effects:
sl@0
   417
 *	Memory is allocated.
sl@0
   418
 *
sl@0
   419
 *----------------------------------------------------------------------
sl@0
   420
 */
sl@0
   421
sl@0
   422
EXPORT_C int
sl@0
   423
Tcl_SplitList(interp, list, argcPtr, argvPtr)
sl@0
   424
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. 
sl@0
   425
				 * If NULL, no error message is left. */
sl@0
   426
    CONST char *list;		/* Pointer to string with list structure. */
sl@0
   427
    int *argcPtr;		/* Pointer to location to fill in with
sl@0
   428
				 * the number of elements in the list. */
sl@0
   429
    CONST char ***argvPtr;	/* Pointer to place to store pointer to
sl@0
   430
				 * array of pointers to list elements. */
sl@0
   431
{
sl@0
   432
    CONST char **argv;
sl@0
   433
    CONST char *l;
sl@0
   434
    char *p;
sl@0
   435
    int length, size, i, result, elSize, brace;
sl@0
   436
    CONST char *element;
sl@0
   437
sl@0
   438
    /*
sl@0
   439
     * Figure out how much space to allocate.  There must be enough
sl@0
   440
     * space for both the array of pointers and also for a copy of
sl@0
   441
     * the list.  To estimate the number of pointers needed, count
sl@0
   442
     * the number of space characters in the list.
sl@0
   443
     */
sl@0
   444
sl@0
   445
    for (size = 2, l = list; *l != 0; l++) {
sl@0
   446
	if (isspace(UCHAR(*l))) { /* INTL: ISO space. */
sl@0
   447
	    size++;
sl@0
   448
	    /* Consecutive space can only count as a single list delimiter */
sl@0
   449
	    while (1) {
sl@0
   450
		char next = *(l + 1);
sl@0
   451
		if (next == '\0') {
sl@0
   452
		    break;
sl@0
   453
		}
sl@0
   454
		++l;
sl@0
   455
		if (isspace(UCHAR(next))) {
sl@0
   456
		    continue;
sl@0
   457
		}
sl@0
   458
		break;
sl@0
   459
	    }
sl@0
   460
	}
sl@0
   461
    }
sl@0
   462
    length = l - list;
sl@0
   463
    argv = (CONST char **) ckalloc((unsigned)
sl@0
   464
	    ((size * sizeof(char *)) + length + 1));
sl@0
   465
    for (i = 0, p = ((char *) argv) + size*sizeof(char *);
sl@0
   466
	    *list != 0;  i++) {
sl@0
   467
	CONST char *prevList = list;
sl@0
   468
	
sl@0
   469
	result = TclFindElement(interp, list, length, &element,
sl@0
   470
				&list, &elSize, &brace);
sl@0
   471
	length -= (list - prevList);
sl@0
   472
	if (result != TCL_OK) {
sl@0
   473
	    ckfree((char *) argv);
sl@0
   474
	    return result;
sl@0
   475
	}
sl@0
   476
	if (*element == 0) {
sl@0
   477
	    break;
sl@0
   478
	}
sl@0
   479
	if (i >= size) {
sl@0
   480
	    ckfree((char *) argv);
sl@0
   481
	    if (interp != NULL) {
sl@0
   482
		Tcl_SetResult(interp, "internal error in Tcl_SplitList",
sl@0
   483
			TCL_STATIC);
sl@0
   484
	    }
sl@0
   485
	    return TCL_ERROR;
sl@0
   486
	}
sl@0
   487
	argv[i] = p;
sl@0
   488
	if (brace) {
sl@0
   489
	    memcpy((VOID *) p, (VOID *) element, (size_t) elSize);
sl@0
   490
	    p += elSize;
sl@0
   491
	    *p = 0;
sl@0
   492
	    p++;
sl@0
   493
	} else {
sl@0
   494
	    TclCopyAndCollapse(elSize, element, p);
sl@0
   495
	    p += elSize+1;
sl@0
   496
	}
sl@0
   497
    }
sl@0
   498
sl@0
   499
    argv[i] = NULL;
sl@0
   500
    *argvPtr = argv;
sl@0
   501
    *argcPtr = i;
sl@0
   502
    return TCL_OK;
sl@0
   503
}
sl@0
   504

sl@0
   505
/*
sl@0
   506
 *----------------------------------------------------------------------
sl@0
   507
 *
sl@0
   508
 * Tcl_ScanElement --
sl@0
   509
 *
sl@0
   510
 *	This procedure is a companion procedure to Tcl_ConvertElement.
sl@0
   511
 *	It scans a string to see what needs to be done to it (e.g. add
sl@0
   512
 *	backslashes or enclosing braces) to make the string into a
sl@0
   513
 *	valid Tcl list element.
sl@0
   514
 *
sl@0
   515
 * Results:
sl@0
   516
 *	The return value is an overestimate of the number of characters
sl@0
   517
 *	that will be needed by Tcl_ConvertElement to produce a valid
sl@0
   518
 *	list element from string.  The word at *flagPtr is filled in
sl@0
   519
 *	with a value needed by Tcl_ConvertElement when doing the actual
sl@0
   520
 *	conversion.
sl@0
   521
 *
sl@0
   522
 * Side effects:
sl@0
   523
 *	None.
sl@0
   524
 *
sl@0
   525
 *----------------------------------------------------------------------
sl@0
   526
 */
sl@0
   527
sl@0
   528
EXPORT_C int
sl@0
   529
Tcl_ScanElement(string, flagPtr)
sl@0
   530
    register CONST char *string; /* String to convert to list element. */
sl@0
   531
    register int *flagPtr;	 /* Where to store information to guide
sl@0
   532
				  * Tcl_ConvertCountedElement. */
sl@0
   533
{
sl@0
   534
    return Tcl_ScanCountedElement(string, -1, flagPtr);
sl@0
   535
}
sl@0
   536

sl@0
   537
/*
sl@0
   538
 *----------------------------------------------------------------------
sl@0
   539
 *
sl@0
   540
 * Tcl_ScanCountedElement --
sl@0
   541
 *
sl@0
   542
 *	This procedure is a companion procedure to
sl@0
   543
 *	Tcl_ConvertCountedElement.  It scans a string to see what
sl@0
   544
 *	needs to be done to it (e.g. add backslashes or enclosing
sl@0
   545
 *	braces) to make the string into a valid Tcl list element.
sl@0
   546
 *	If length is -1, then the string is scanned up to the first
sl@0
   547
 *	null byte.
sl@0
   548
 *
sl@0
   549
 * Results:
sl@0
   550
 *	The return value is an overestimate of the number of characters
sl@0
   551
 *	that will be needed by Tcl_ConvertCountedElement to produce a
sl@0
   552
 *	valid list element from string.  The word at *flagPtr is
sl@0
   553
 *	filled in with a value needed by Tcl_ConvertCountedElement
sl@0
   554
 *	when doing the actual conversion.
sl@0
   555
 *
sl@0
   556
 * Side effects:
sl@0
   557
 *	None.
sl@0
   558
 *
sl@0
   559
 *----------------------------------------------------------------------
sl@0
   560
 */
sl@0
   561
sl@0
   562
EXPORT_C int
sl@0
   563
Tcl_ScanCountedElement(string, length, flagPtr)
sl@0
   564
    CONST char *string;		/* String to convert to Tcl list element. */
sl@0
   565
    int length;			/* Number of bytes in string, or -1. */
sl@0
   566
    int *flagPtr;		/* Where to store information to guide
sl@0
   567
				 * Tcl_ConvertElement. */
sl@0
   568
{
sl@0
   569
    int flags, nestingLevel;
sl@0
   570
    register CONST char *p, *lastChar;
sl@0
   571
sl@0
   572
    /*
sl@0
   573
     * This procedure and Tcl_ConvertElement together do two things:
sl@0
   574
     *
sl@0
   575
     * 1. They produce a proper list, one that will yield back the
sl@0
   576
     * argument strings when evaluated or when disassembled with
sl@0
   577
     * Tcl_SplitList.  This is the most important thing.
sl@0
   578
     * 
sl@0
   579
     * 2. They try to produce legible output, which means minimizing the
sl@0
   580
     * use of backslashes (using braces instead).  However, there are
sl@0
   581
     * some situations where backslashes must be used (e.g. an element
sl@0
   582
     * like "{abc": the leading brace will have to be backslashed.
sl@0
   583
     * For each element, one of three things must be done:
sl@0
   584
     *
sl@0
   585
     * (a) Use the element as-is (it doesn't contain any special
sl@0
   586
     * characters).  This is the most desirable option.
sl@0
   587
     *
sl@0
   588
     * (b) Enclose the element in braces, but leave the contents alone.
sl@0
   589
     * This happens if the element contains embedded space, or if it
sl@0
   590
     * contains characters with special interpretation ($, [, ;, or \),
sl@0
   591
     * or if it starts with a brace or double-quote, or if there are
sl@0
   592
     * no characters in the element.
sl@0
   593
     *
sl@0
   594
     * (c) Don't enclose the element in braces, but add backslashes to
sl@0
   595
     * prevent special interpretation of special characters.  This is a
sl@0
   596
     * last resort used when the argument would normally fall under case
sl@0
   597
     * (b) but contains unmatched braces.  It also occurs if the last
sl@0
   598
     * character of the argument is a backslash or if the element contains
sl@0
   599
     * a backslash followed by newline.
sl@0
   600
     *
sl@0
   601
     * The procedure figures out how many bytes will be needed to store
sl@0
   602
     * the result (actually, it overestimates). It also collects information
sl@0
   603
     * about the element in the form of a flags word.
sl@0
   604
     *
sl@0
   605
     * Note: list elements produced by this procedure and
sl@0
   606
     * Tcl_ConvertCountedElement must have the property that they can be
sl@0
   607
     * enclosing in curly braces to make sub-lists.  This means, for
sl@0
   608
     * example, that we must not leave unmatched curly braces in the
sl@0
   609
     * resulting list element.  This property is necessary in order for
sl@0
   610
     * procedures like Tcl_DStringStartSublist to work.
sl@0
   611
     */
sl@0
   612
sl@0
   613
    nestingLevel = 0;
sl@0
   614
    flags = 0;
sl@0
   615
    if (string == NULL) {
sl@0
   616
	string = "";
sl@0
   617
    }
sl@0
   618
    if (length == -1) {
sl@0
   619
	length = strlen(string);
sl@0
   620
    }
sl@0
   621
    lastChar = string + length;
sl@0
   622
    p = string;
sl@0
   623
    if ((p == lastChar) || (*p == '{') || (*p == '"')) {
sl@0
   624
	flags |= USE_BRACES;
sl@0
   625
    }
sl@0
   626
    for ( ; p < lastChar; p++) {
sl@0
   627
	switch (*p) {
sl@0
   628
	    case '{':
sl@0
   629
		nestingLevel++;
sl@0
   630
		break;
sl@0
   631
	    case '}':
sl@0
   632
		nestingLevel--;
sl@0
   633
		if (nestingLevel < 0) {
sl@0
   634
		    flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
sl@0
   635
		}
sl@0
   636
		break;
sl@0
   637
	    case '[':
sl@0
   638
	    case '$':
sl@0
   639
	    case ';':
sl@0
   640
	    case ' ':
sl@0
   641
	    case '\f':
sl@0
   642
	    case '\n':
sl@0
   643
	    case '\r':
sl@0
   644
	    case '\t':
sl@0
   645
	    case '\v':
sl@0
   646
		flags |= USE_BRACES;
sl@0
   647
		break;
sl@0
   648
	    case '\\':
sl@0
   649
		if ((p+1 == lastChar) || (p[1] == '\n')) {
sl@0
   650
		    flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
sl@0
   651
		} else {
sl@0
   652
		    int size;
sl@0
   653
sl@0
   654
		    Tcl_UtfBackslash(p, &size, NULL);
sl@0
   655
		    p += size-1;
sl@0
   656
		    flags |= USE_BRACES;
sl@0
   657
		}
sl@0
   658
		break;
sl@0
   659
	}
sl@0
   660
    }
sl@0
   661
    if (nestingLevel != 0) {
sl@0
   662
	flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
sl@0
   663
    }
sl@0
   664
    *flagPtr = flags;
sl@0
   665
sl@0
   666
    /*
sl@0
   667
     * Allow enough space to backslash every character plus leave
sl@0
   668
     * two spaces for braces.
sl@0
   669
     */
sl@0
   670
sl@0
   671
    return 2*(p-string) + 2;
sl@0
   672
}
sl@0
   673

sl@0
   674
/*
sl@0
   675
 *----------------------------------------------------------------------
sl@0
   676
 *
sl@0
   677
 * Tcl_ConvertElement --
sl@0
   678
 *
sl@0
   679
 *	This is a companion procedure to Tcl_ScanElement.  Given
sl@0
   680
 *	the information produced by Tcl_ScanElement, this procedure
sl@0
   681
 *	converts a string to a list element equal to that string.
sl@0
   682
 *
sl@0
   683
 * Results:
sl@0
   684
 *	Information is copied to *dst in the form of a list element
sl@0
   685
 *	identical to src (i.e. if Tcl_SplitList is applied to dst it
sl@0
   686
 *	will produce a string identical to src).  The return value is
sl@0
   687
 *	a count of the number of characters copied (not including the
sl@0
   688
 *	terminating NULL character).
sl@0
   689
 *
sl@0
   690
 * Side effects:
sl@0
   691
 *	None.
sl@0
   692
 *
sl@0
   693
 *----------------------------------------------------------------------
sl@0
   694
 */
sl@0
   695
sl@0
   696
EXPORT_C int
sl@0
   697
Tcl_ConvertElement(src, dst, flags)
sl@0
   698
    register CONST char *src;	/* Source information for list element. */
sl@0
   699
    register char *dst;		/* Place to put list-ified element. */
sl@0
   700
    register int flags;		/* Flags produced by Tcl_ScanElement. */
sl@0
   701
{
sl@0
   702
    return Tcl_ConvertCountedElement(src, -1, dst, flags);
sl@0
   703
}
sl@0
   704

sl@0
   705
/*
sl@0
   706
 *----------------------------------------------------------------------
sl@0
   707
 *
sl@0
   708
 * Tcl_ConvertCountedElement --
sl@0
   709
 *
sl@0
   710
 *	This is a companion procedure to Tcl_ScanCountedElement.  Given
sl@0
   711
 *	the information produced by Tcl_ScanCountedElement, this
sl@0
   712
 *	procedure converts a string to a list element equal to that
sl@0
   713
 *	string.
sl@0
   714
 *
sl@0
   715
 * Results:
sl@0
   716
 *	Information is copied to *dst in the form of a list element
sl@0
   717
 *	identical to src (i.e. if Tcl_SplitList is applied to dst it
sl@0
   718
 *	will produce a string identical to src).  The return value is
sl@0
   719
 *	a count of the number of characters copied (not including the
sl@0
   720
 *	terminating NULL character).
sl@0
   721
 *
sl@0
   722
 * Side effects:
sl@0
   723
 *	None.
sl@0
   724
 *
sl@0
   725
 *----------------------------------------------------------------------
sl@0
   726
 */
sl@0
   727
sl@0
   728
EXPORT_C int
sl@0
   729
Tcl_ConvertCountedElement(src, length, dst, flags)
sl@0
   730
    register CONST char *src;	/* Source information for list element. */
sl@0
   731
    int length;			/* Number of bytes in src, or -1. */
sl@0
   732
    char *dst;			/* Place to put list-ified element. */
sl@0
   733
    int flags;			/* Flags produced by Tcl_ScanElement. */
sl@0
   734
{
sl@0
   735
    register char *p = dst;
sl@0
   736
    register CONST char *lastChar;
sl@0
   737
sl@0
   738
    /*
sl@0
   739
     * See the comment block at the beginning of the Tcl_ScanElement
sl@0
   740
     * code for details of how this works.
sl@0
   741
     */
sl@0
   742
sl@0
   743
    if (src && length == -1) {
sl@0
   744
	length = strlen(src);
sl@0
   745
    }
sl@0
   746
    if ((src == NULL) || (length == 0)) {
sl@0
   747
	p[0] = '{';
sl@0
   748
	p[1] = '}';
sl@0
   749
	p[2] = 0;
sl@0
   750
	return 2;
sl@0
   751
    }
sl@0
   752
    lastChar = src + length;
sl@0
   753
    if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
sl@0
   754
	*p = '{';
sl@0
   755
	p++;
sl@0
   756
	for ( ; src != lastChar; src++, p++) {
sl@0
   757
	    *p = *src;
sl@0
   758
	}
sl@0
   759
	*p = '}';
sl@0
   760
	p++;
sl@0
   761
    } else {
sl@0
   762
	if (*src == '{') {
sl@0
   763
	    /*
sl@0
   764
	     * Can't have a leading brace unless the whole element is
sl@0
   765
	     * enclosed in braces.  Add a backslash before the brace.
sl@0
   766
	     * Furthermore, this may destroy the balance between open
sl@0
   767
	     * and close braces, so set BRACES_UNMATCHED.
sl@0
   768
	     */
sl@0
   769
sl@0
   770
	    p[0] = '\\';
sl@0
   771
	    p[1] = '{';
sl@0
   772
	    p += 2;
sl@0
   773
	    src++;
sl@0
   774
	    flags |= BRACES_UNMATCHED;
sl@0
   775
	}
sl@0
   776
	for (; src != lastChar; src++) {
sl@0
   777
	    switch (*src) {
sl@0
   778
		case ']':
sl@0
   779
		case '[':
sl@0
   780
		case '$':
sl@0
   781
		case ';':
sl@0
   782
		case ' ':
sl@0
   783
		case '\\':
sl@0
   784
		case '"':
sl@0
   785
		    *p = '\\';
sl@0
   786
		    p++;
sl@0
   787
		    break;
sl@0
   788
		case '{':
sl@0
   789
		case '}':
sl@0
   790
		    /*
sl@0
   791
		     * It may not seem necessary to backslash braces, but
sl@0
   792
		     * it is.  The reason for this is that the resulting
sl@0
   793
		     * list element may actually be an element of a sub-list
sl@0
   794
		     * enclosed in braces (e.g. if Tcl_DStringStartSublist
sl@0
   795
		     * has been invoked), so there may be a brace mismatch
sl@0
   796
		     * if the braces aren't backslashed.
sl@0
   797
		     */
sl@0
   798
sl@0
   799
		    if (flags & BRACES_UNMATCHED) {
sl@0
   800
			*p = '\\';
sl@0
   801
			p++;
sl@0
   802
		    }
sl@0
   803
		    break;
sl@0
   804
		case '\f':
sl@0
   805
		    *p = '\\';
sl@0
   806
		    p++;
sl@0
   807
		    *p = 'f';
sl@0
   808
		    p++;
sl@0
   809
		    continue;
sl@0
   810
		case '\n':
sl@0
   811
		    *p = '\\';
sl@0
   812
		    p++;
sl@0
   813
		    *p = 'n';
sl@0
   814
		    p++;
sl@0
   815
		    continue;
sl@0
   816
		case '\r':
sl@0
   817
		    *p = '\\';
sl@0
   818
		    p++;
sl@0
   819
		    *p = 'r';
sl@0
   820
		    p++;
sl@0
   821
		    continue;
sl@0
   822
		case '\t':
sl@0
   823
		    *p = '\\';
sl@0
   824
		    p++;
sl@0
   825
		    *p = 't';
sl@0
   826
		    p++;
sl@0
   827
		    continue;
sl@0
   828
		case '\v':
sl@0
   829
		    *p = '\\';
sl@0
   830
		    p++;
sl@0
   831
		    *p = 'v';
sl@0
   832
		    p++;
sl@0
   833
		    continue;
sl@0
   834
	    }
sl@0
   835
	    *p = *src;
sl@0
   836
	    p++;
sl@0
   837
	}
sl@0
   838
    }
sl@0
   839
    *p = '\0';
sl@0
   840
    return p-dst;
sl@0
   841
}
sl@0
   842

sl@0
   843
/*
sl@0
   844
 *----------------------------------------------------------------------
sl@0
   845
 *
sl@0
   846
 * Tcl_Merge --
sl@0
   847
 *
sl@0
   848
 *	Given a collection of strings, merge them together into a
sl@0
   849
 *	single string that has proper Tcl list structured (i.e.
sl@0
   850
 *	Tcl_SplitList may be used to retrieve strings equal to the
sl@0
   851
 *	original elements, and Tcl_Eval will parse the string back
sl@0
   852
 *	into its original elements).
sl@0
   853
 *
sl@0
   854
 * Results:
sl@0
   855
 *	The return value is the address of a dynamically-allocated
sl@0
   856
 *	string containing the merged list.
sl@0
   857
 *
sl@0
   858
 * Side effects:
sl@0
   859
 *	None.
sl@0
   860
 *
sl@0
   861
 *----------------------------------------------------------------------
sl@0
   862
 */
sl@0
   863
sl@0
   864
EXPORT_C char *
sl@0
   865
Tcl_Merge(argc, argv)
sl@0
   866
    int argc;			/* How many strings to merge. */
sl@0
   867
    CONST char * CONST *argv;	/* Array of string values. */
sl@0
   868
{
sl@0
   869
#   define LOCAL_SIZE 20
sl@0
   870
    int localFlags[LOCAL_SIZE], *flagPtr;
sl@0
   871
    int numChars;
sl@0
   872
    char *result;
sl@0
   873
    char *dst;
sl@0
   874
    int i;
sl@0
   875
sl@0
   876
    /*
sl@0
   877
     * Pass 1: estimate space, gather flags.
sl@0
   878
     */
sl@0
   879
sl@0
   880
    if (argc <= LOCAL_SIZE) {
sl@0
   881
	flagPtr = localFlags;
sl@0
   882
    } else {
sl@0
   883
	flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
sl@0
   884
    }
sl@0
   885
    numChars = 1;
sl@0
   886
    for (i = 0; i < argc; i++) {
sl@0
   887
	numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
sl@0
   888
    }
sl@0
   889
sl@0
   890
    /*
sl@0
   891
     * Pass two: copy into the result area.
sl@0
   892
     */
sl@0
   893
sl@0
   894
    result = (char *) ckalloc((unsigned) numChars);
sl@0
   895
    dst = result;
sl@0
   896
    for (i = 0; i < argc; i++) {
sl@0
   897
	numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
sl@0
   898
	dst += numChars;
sl@0
   899
	*dst = ' ';
sl@0
   900
	dst++;
sl@0
   901
    }
sl@0
   902
    if (dst == result) {
sl@0
   903
	*dst = 0;
sl@0
   904
    } else {
sl@0
   905
	dst[-1] = 0;
sl@0
   906
    }
sl@0
   907
sl@0
   908
    if (flagPtr != localFlags) {
sl@0
   909
	ckfree((char *) flagPtr);
sl@0
   910
    }
sl@0
   911
    return result;
sl@0
   912
}
sl@0
   913

sl@0
   914
/*
sl@0
   915
 *----------------------------------------------------------------------
sl@0
   916
 *
sl@0
   917
 * Tcl_Backslash --
sl@0
   918
 *
sl@0
   919
 *	Figure out how to handle a backslash sequence.
sl@0
   920
 *
sl@0
   921
 * Results:
sl@0
   922
 *	The return value is the character that should be substituted
sl@0
   923
 *	in place of the backslash sequence that starts at src.  If
sl@0
   924
 *	readPtr isn't NULL then it is filled in with a count of the
sl@0
   925
 *	number of characters in the backslash sequence.
sl@0
   926
 *
sl@0
   927
 * Side effects:
sl@0
   928
 *	None.
sl@0
   929
 *
sl@0
   930
 *----------------------------------------------------------------------
sl@0
   931
 */
sl@0
   932
sl@0
   933
EXPORT_C char
sl@0
   934
Tcl_Backslash(src, readPtr)
sl@0
   935
    CONST char *src;		/* Points to the backslash character of
sl@0
   936
				 * a backslash sequence. */
sl@0
   937
    int *readPtr;		/* Fill in with number of characters read
sl@0
   938
				 * from src, unless NULL. */
sl@0
   939
{
sl@0
   940
    char buf[TCL_UTF_MAX];
sl@0
   941
    Tcl_UniChar ch;
sl@0
   942
sl@0
   943
    Tcl_UtfBackslash(src, readPtr, buf);
sl@0
   944
    TclUtfToUniChar(buf, &ch);
sl@0
   945
    return (char) ch;
sl@0
   946
}
sl@0
   947

sl@0
   948
/*
sl@0
   949
 *----------------------------------------------------------------------
sl@0
   950
 *
sl@0
   951
 * Tcl_Concat --
sl@0
   952
 *
sl@0
   953
 *	Concatenate a set of strings into a single large string.
sl@0
   954
 *
sl@0
   955
 * Results:
sl@0
   956
 *	The return value is dynamically-allocated string containing
sl@0
   957
 *	a concatenation of all the strings in argv, with spaces between
sl@0
   958
 *	the original argv elements.
sl@0
   959
 *
sl@0
   960
 * Side effects:
sl@0
   961
 *	Memory is allocated for the result;  the caller is responsible
sl@0
   962
 *	for freeing the memory.
sl@0
   963
 *
sl@0
   964
 *----------------------------------------------------------------------
sl@0
   965
 */
sl@0
   966
sl@0
   967
EXPORT_C char *
sl@0
   968
Tcl_Concat(argc, argv)
sl@0
   969
    int argc;			/* Number of strings to concatenate. */
sl@0
   970
    CONST char * CONST *argv;	/* Array of strings to concatenate. */
sl@0
   971
{
sl@0
   972
    int totalSize, i;
sl@0
   973
    char *p;
sl@0
   974
    char *result;
sl@0
   975
sl@0
   976
    for (totalSize = 1, i = 0; i < argc; i++) {
sl@0
   977
	totalSize += strlen(argv[i]) + 1;
sl@0
   978
    }
sl@0
   979
    result = (char *) ckalloc((unsigned) totalSize);
sl@0
   980
    if (argc == 0) {
sl@0
   981
	*result = '\0';
sl@0
   982
	return result;
sl@0
   983
    }
sl@0
   984
    for (p = result, i = 0; i < argc; i++) {
sl@0
   985
	CONST char *element;
sl@0
   986
	int length;
sl@0
   987
sl@0
   988
	/*
sl@0
   989
	 * Clip white space off the front and back of the string
sl@0
   990
	 * to generate a neater result, and ignore any empty
sl@0
   991
	 * elements.
sl@0
   992
	 */
sl@0
   993
sl@0
   994
	element = argv[i];
sl@0
   995
	while (isspace(UCHAR(*element))) { /* INTL: ISO space. */
sl@0
   996
	    element++;
sl@0
   997
	}
sl@0
   998
	for (length = strlen(element);
sl@0
   999
		(length > 0)
sl@0
  1000
		&& (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */
sl@0
  1001
		&& ((length < 2) || (element[length-2] != '\\'));
sl@0
  1002
	        length--) {
sl@0
  1003
	    /* Null loop body. */
sl@0
  1004
	}
sl@0
  1005
	if (length == 0) {
sl@0
  1006
	    continue;
sl@0
  1007
	}
sl@0
  1008
	memcpy((VOID *) p, (VOID *) element, (size_t) length);
sl@0
  1009
	p += length;
sl@0
  1010
	*p = ' ';
sl@0
  1011
	p++;
sl@0
  1012
    }
sl@0
  1013
    if (p != result) {
sl@0
  1014
	p[-1] = 0;
sl@0
  1015
    } else {
sl@0
  1016
	*p = 0;
sl@0
  1017
    }
sl@0
  1018
    return result;
sl@0
  1019
}
sl@0
  1020

sl@0
  1021
/*
sl@0
  1022
 *----------------------------------------------------------------------
sl@0
  1023
 *
sl@0
  1024
 * Tcl_ConcatObj --
sl@0
  1025
 *
sl@0
  1026
 *	Concatenate the strings from a set of objects into a single string
sl@0
  1027
 *	object with spaces between the original strings.
sl@0
  1028
 *
sl@0
  1029
 * Results:
sl@0
  1030
 *	The return value is a new string object containing a concatenation
sl@0
  1031
 *	of the strings in objv. Its ref count is zero.
sl@0
  1032
 *
sl@0
  1033
 * Side effects:
sl@0
  1034
 *	A new object is created.
sl@0
  1035
 *
sl@0
  1036
 *----------------------------------------------------------------------
sl@0
  1037
 */
sl@0
  1038
sl@0
  1039
EXPORT_C Tcl_Obj *
sl@0
  1040
Tcl_ConcatObj(objc, objv)
sl@0
  1041
    int objc;			/* Number of objects to concatenate. */
sl@0
  1042
    Tcl_Obj *CONST objv[];	/* Array of objects to concatenate. */
sl@0
  1043
{
sl@0
  1044
    int allocSize, finalSize, length, elemLength, i;
sl@0
  1045
    char *p;
sl@0
  1046
    char *element;
sl@0
  1047
    char *concatStr;
sl@0
  1048
    Tcl_Obj *objPtr;
sl@0
  1049
sl@0
  1050
    /*
sl@0
  1051
     * Check first to see if all the items are of list type.  If so,
sl@0
  1052
     * we will concat them together as lists, and return a list object.
sl@0
  1053
     * This is only valid when the lists have no current string
sl@0
  1054
     * representation, since we don't know what the original type was.
sl@0
  1055
     * An original string rep may have lost some whitespace info when
sl@0
  1056
     * converted which could be important.
sl@0
  1057
     */
sl@0
  1058
    for (i = 0;  i < objc;  i++) {
sl@0
  1059
	objPtr = objv[i];
sl@0
  1060
	if ((objPtr->typePtr != &tclListType) || (objPtr->bytes != NULL)) {
sl@0
  1061
	    break;
sl@0
  1062
	}
sl@0
  1063
    }
sl@0
  1064
    if (i == objc) {
sl@0
  1065
	Tcl_Obj **listv;
sl@0
  1066
	int listc;
sl@0
  1067
sl@0
  1068
	objPtr = Tcl_NewListObj(0, NULL);
sl@0
  1069
	for (i = 0;  i < objc;  i++) {
sl@0
  1070
	    /*
sl@0
  1071
	     * Tcl_ListObjAppendList could be used here, but this saves
sl@0
  1072
	     * us a bit of type checking (since we've already done it)
sl@0
  1073
	     * Use of INT_MAX tells us to always put the new stuff on
sl@0
  1074
	     * the end.  It will be set right in Tcl_ListObjReplace.
sl@0
  1075
	     */
sl@0
  1076
	    Tcl_ListObjGetElements(NULL, objv[i], &listc, &listv);
sl@0
  1077
	    Tcl_ListObjReplace(NULL, objPtr, INT_MAX, 0, listc, listv);
sl@0
  1078
	}
sl@0
  1079
	return objPtr;
sl@0
  1080
    }
sl@0
  1081
sl@0
  1082
    allocSize = 0;
sl@0
  1083
    for (i = 0;  i < objc;  i++) {
sl@0
  1084
	objPtr = objv[i];
sl@0
  1085
	element = Tcl_GetStringFromObj(objPtr, &length);
sl@0
  1086
	if ((element != NULL) && (length > 0)) {
sl@0
  1087
	    allocSize += (length + 1);
sl@0
  1088
	}
sl@0
  1089
    }
sl@0
  1090
    if (allocSize == 0) {
sl@0
  1091
	allocSize = 1;		/* enough for the NULL byte at end */
sl@0
  1092
    }
sl@0
  1093
sl@0
  1094
    /*
sl@0
  1095
     * Allocate storage for the concatenated result. Note that allocSize
sl@0
  1096
     * is one more than the total number of characters, and so includes
sl@0
  1097
     * room for the terminating NULL byte.
sl@0
  1098
     */
sl@0
  1099
    
sl@0
  1100
    concatStr = (char *) ckalloc((unsigned) allocSize);
sl@0
  1101
sl@0
  1102
    /*
sl@0
  1103
     * Now concatenate the elements. Clip white space off the front and back
sl@0
  1104
     * to generate a neater result, and ignore any empty elements. Also put
sl@0
  1105
     * a null byte at the end.
sl@0
  1106
     */
sl@0
  1107
sl@0
  1108
    finalSize = 0;
sl@0
  1109
    if (objc == 0) {
sl@0
  1110
	*concatStr = '\0';
sl@0
  1111
    } else {
sl@0
  1112
	p = concatStr;
sl@0
  1113
        for (i = 0;  i < objc;  i++) {
sl@0
  1114
	    objPtr = objv[i];
sl@0
  1115
	    element = Tcl_GetStringFromObj(objPtr, &elemLength);
sl@0
  1116
	    while ((elemLength > 0) && (UCHAR(*element) < 127)
sl@0
  1117
		    && isspace(UCHAR(*element))) { /* INTL: ISO C space. */
sl@0
  1118
	         element++;
sl@0
  1119
		 elemLength--;
sl@0
  1120
	    }
sl@0
  1121
sl@0
  1122
	    /*
sl@0
  1123
	     * Trim trailing white space.  But, be careful not to trim
sl@0
  1124
	     * a space character if it is preceded by a backslash: in
sl@0
  1125
	     * this case it could be significant.
sl@0
  1126
	     */
sl@0
  1127
sl@0
  1128
	    while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127)
sl@0
  1129
		    && isspace(UCHAR(element[elemLength-1])) /* INTL: ISO C space. */
sl@0
  1130
		    && ((elemLength < 2) || (element[elemLength-2] != '\\'))) {
sl@0
  1131
		elemLength--;
sl@0
  1132
	    }
sl@0
  1133
	    if (elemLength == 0) {
sl@0
  1134
	         continue;	/* nothing left of this element */
sl@0
  1135
	    }
sl@0
  1136
	    memcpy((VOID *) p, (VOID *) element, (size_t) elemLength);
sl@0
  1137
	    p += elemLength;
sl@0
  1138
	    *p = ' ';
sl@0
  1139
	    p++;
sl@0
  1140
	    finalSize += (elemLength + 1);
sl@0
  1141
        }
sl@0
  1142
        if (p != concatStr) {
sl@0
  1143
	    p[-1] = 0;
sl@0
  1144
	    finalSize -= 1;	/* we overwrote the final ' ' */
sl@0
  1145
        } else {
sl@0
  1146
	    *p = 0;
sl@0
  1147
        }
sl@0
  1148
    }
sl@0
  1149
    
sl@0
  1150
    TclNewObj(objPtr);
sl@0
  1151
    objPtr->bytes  = concatStr;
sl@0
  1152
    objPtr->length = finalSize;
sl@0
  1153
    return objPtr;
sl@0
  1154
}
sl@0
  1155

sl@0
  1156
/*
sl@0
  1157
 *----------------------------------------------------------------------
sl@0
  1158
 *
sl@0
  1159
 * Tcl_StringMatch --
sl@0
  1160
 *
sl@0
  1161
 *	See if a particular string matches a particular pattern.
sl@0
  1162
 *
sl@0
  1163
 * Results:
sl@0
  1164
 *	The return value is 1 if string matches pattern, and
sl@0
  1165
 *	0 otherwise.  The matching operation permits the following
sl@0
  1166
 *	special characters in the pattern: *?\[] (see the manual
sl@0
  1167
 *	entry for details on what these mean).
sl@0
  1168
 *
sl@0
  1169
 * Side effects:
sl@0
  1170
 *	None.
sl@0
  1171
 *
sl@0
  1172
 *----------------------------------------------------------------------
sl@0
  1173
 */
sl@0
  1174
sl@0
  1175
EXPORT_C int
sl@0
  1176
Tcl_StringMatch(string, pattern)
sl@0
  1177
    CONST char *string;		/* String. */
sl@0
  1178
    CONST char *pattern;	/* Pattern, which may contain special
sl@0
  1179
				 * characters. */
sl@0
  1180
{
sl@0
  1181
    return Tcl_StringCaseMatch(string, pattern, 0);
sl@0
  1182
}
sl@0
  1183

sl@0
  1184
/*
sl@0
  1185
 *----------------------------------------------------------------------
sl@0
  1186
 *
sl@0
  1187
 * Tcl_StringCaseMatch --
sl@0
  1188
 *
sl@0
  1189
 *	See if a particular string matches a particular pattern.
sl@0
  1190
 *	Allows case insensitivity.
sl@0
  1191
 *
sl@0
  1192
 * Results:
sl@0
  1193
 *	The return value is 1 if string matches pattern, and
sl@0
  1194
 *	0 otherwise.  The matching operation permits the following
sl@0
  1195
 *	special characters in the pattern: *?\[] (see the manual
sl@0
  1196
 *	entry for details on what these mean).
sl@0
  1197
 *
sl@0
  1198
 * Side effects:
sl@0
  1199
 *	None.
sl@0
  1200
 *
sl@0
  1201
 *----------------------------------------------------------------------
sl@0
  1202
 */
sl@0
  1203
sl@0
  1204
EXPORT_C int
sl@0
  1205
Tcl_StringCaseMatch(string, pattern, nocase)
sl@0
  1206
    CONST char *string;		/* String. */
sl@0
  1207
    CONST char *pattern;	/* Pattern, which may contain special
sl@0
  1208
				 * characters. */
sl@0
  1209
    int nocase;			/* 0 for case sensitive, 1 for insensitive */
sl@0
  1210
{
sl@0
  1211
    int p, charLen;
sl@0
  1212
    CONST char *pstart = pattern;
sl@0
  1213
    Tcl_UniChar ch1, ch2;
sl@0
  1214
    
sl@0
  1215
    while (1) {
sl@0
  1216
	p = *pattern;
sl@0
  1217
	
sl@0
  1218
	/*
sl@0
  1219
	 * See if we're at the end of both the pattern and the string.  If
sl@0
  1220
	 * so, we succeeded.  If we're at the end of the pattern but not at
sl@0
  1221
	 * the end of the string, we failed.
sl@0
  1222
	 */
sl@0
  1223
	
sl@0
  1224
	if (p == '\0') {
sl@0
  1225
	    return (*string == '\0');
sl@0
  1226
	}
sl@0
  1227
	if ((*string == '\0') && (p != '*')) {
sl@0
  1228
	    return 0;
sl@0
  1229
	}
sl@0
  1230
sl@0
  1231
	/*
sl@0
  1232
	 * Check for a "*" as the next pattern character.  It matches
sl@0
  1233
	 * any substring.  We handle this by calling ourselves
sl@0
  1234
	 * recursively for each postfix of string, until either we
sl@0
  1235
	 * match or we reach the end of the string.
sl@0
  1236
	 */
sl@0
  1237
	
sl@0
  1238
	if (p == '*') {
sl@0
  1239
	    /*
sl@0
  1240
	     * Skip all successive *'s in the pattern
sl@0
  1241
	     */
sl@0
  1242
	    while (*(++pattern) == '*') {}
sl@0
  1243
	    p = *pattern;
sl@0
  1244
	    if (p == '\0') {
sl@0
  1245
		return 1;
sl@0
  1246
	    }
sl@0
  1247
	    /*
sl@0
  1248
	     * This is a special case optimization for single-byte utf.
sl@0
  1249
	     */
sl@0
  1250
	    if (UCHAR(*pattern) < 0x80) {
sl@0
  1251
		ch2 = (Tcl_UniChar)
sl@0
  1252
		    (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
sl@0
  1253
	    } else {
sl@0
  1254
		Tcl_UtfToUniChar(pattern, &ch2);
sl@0
  1255
		if (nocase) {
sl@0
  1256
		    ch2 = Tcl_UniCharToLower(ch2);
sl@0
  1257
		}
sl@0
  1258
	    }
sl@0
  1259
	    while (1) {
sl@0
  1260
		/*
sl@0
  1261
		 * Optimization for matching - cruise through the string
sl@0
  1262
		 * quickly if the next char in the pattern isn't a special
sl@0
  1263
		 * character
sl@0
  1264
		 */
sl@0
  1265
		if ((p != '[') && (p != '?') && (p != '\\')) {
sl@0
  1266
		    if (nocase) {
sl@0
  1267
			while (*string) {
sl@0
  1268
			    charLen = TclUtfToUniChar(string, &ch1);
sl@0
  1269
			    if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) {
sl@0
  1270
				break;
sl@0
  1271
			    }
sl@0
  1272
			    string += charLen;
sl@0
  1273
			}
sl@0
  1274
		    } else {
sl@0
  1275
			/*
sl@0
  1276
			 * There's no point in trying to make this code
sl@0
  1277
			 * shorter, as the number of bytes you want to
sl@0
  1278
			 * compare each time is non-constant.
sl@0
  1279
			 */
sl@0
  1280
			while (*string) {
sl@0
  1281
			    charLen = TclUtfToUniChar(string, &ch1);
sl@0
  1282
			    if (ch2 == ch1) {
sl@0
  1283
				break;
sl@0
  1284
			    }
sl@0
  1285
			    string += charLen;
sl@0
  1286
			}
sl@0
  1287
		    }
sl@0
  1288
		}
sl@0
  1289
		if (Tcl_StringCaseMatch(string, pattern, nocase)) {
sl@0
  1290
		    return 1;
sl@0
  1291
		}
sl@0
  1292
		if (*string == '\0') {
sl@0
  1293
		    return 0;
sl@0
  1294
		}
sl@0
  1295
		string += TclUtfToUniChar(string, &ch1);
sl@0
  1296
	    }
sl@0
  1297
	}
sl@0
  1298
sl@0
  1299
	/*
sl@0
  1300
	 * Check for a "?" as the next pattern character.  It matches
sl@0
  1301
	 * any single character.
sl@0
  1302
	 */
sl@0
  1303
sl@0
  1304
	if (p == '?') {
sl@0
  1305
	    pattern++;
sl@0
  1306
	    string += TclUtfToUniChar(string, &ch1);
sl@0
  1307
	    continue;
sl@0
  1308
	}
sl@0
  1309
sl@0
  1310
	/*
sl@0
  1311
	 * Check for a "[" as the next pattern character.  It is followed
sl@0
  1312
	 * by a list of characters that are acceptable, or by a range
sl@0
  1313
	 * (two characters separated by "-").
sl@0
  1314
	 */
sl@0
  1315
sl@0
  1316
	if (p == '[') {
sl@0
  1317
	    Tcl_UniChar startChar, endChar;
sl@0
  1318
sl@0
  1319
	    pattern++;
sl@0
  1320
	    if (UCHAR(*string) < 0x80) {
sl@0
  1321
		ch1 = (Tcl_UniChar)
sl@0
  1322
		    (nocase ? tolower(UCHAR(*string)) : UCHAR(*string));
sl@0
  1323
		string++;
sl@0
  1324
	    } else {
sl@0
  1325
		string += Tcl_UtfToUniChar(string, &ch1);
sl@0
  1326
		if (nocase) {
sl@0
  1327
		    ch1 = Tcl_UniCharToLower(ch1);
sl@0
  1328
		}
sl@0
  1329
	    }
sl@0
  1330
	    while (1) {
sl@0
  1331
		if ((*pattern == ']') || (*pattern == '\0')) {
sl@0
  1332
		    return 0;
sl@0
  1333
		}
sl@0
  1334
		if (UCHAR(*pattern) < 0x80) {
sl@0
  1335
		    startChar = (Tcl_UniChar)
sl@0
  1336
			(nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
sl@0
  1337
		    pattern++;
sl@0
  1338
		} else {
sl@0
  1339
		    pattern += Tcl_UtfToUniChar(pattern, &startChar);
sl@0
  1340
		    if (nocase) {
sl@0
  1341
			startChar = Tcl_UniCharToLower(startChar);
sl@0
  1342
		    }
sl@0
  1343
		}
sl@0
  1344
		if (*pattern == '-') {
sl@0
  1345
		    pattern++;
sl@0
  1346
		    if (*pattern == '\0') {
sl@0
  1347
			return 0;
sl@0
  1348
		    }
sl@0
  1349
		    if (UCHAR(*pattern) < 0x80) {
sl@0
  1350
			endChar = (Tcl_UniChar)
sl@0
  1351
			    (nocase ? tolower(UCHAR(*pattern))
sl@0
  1352
				    : UCHAR(*pattern));
sl@0
  1353
			pattern++;
sl@0
  1354
		    } else {
sl@0
  1355
			pattern += Tcl_UtfToUniChar(pattern, &endChar);
sl@0
  1356
			if (nocase) {
sl@0
  1357
			    endChar = Tcl_UniCharToLower(endChar);
sl@0
  1358
			}
sl@0
  1359
		    }
sl@0
  1360
		    if (((startChar <= ch1) && (ch1 <= endChar))
sl@0
  1361
			    || ((endChar <= ch1) && (ch1 <= startChar))) {
sl@0
  1362
			/*
sl@0
  1363
			 * Matches ranges of form [a-z] or [z-a].
sl@0
  1364
			 */
sl@0
  1365
sl@0
  1366
			break;
sl@0
  1367
		    }
sl@0
  1368
		} else if (startChar == ch1) {
sl@0
  1369
		    break;
sl@0
  1370
		}
sl@0
  1371
	    }
sl@0
  1372
	    while (*pattern != ']') {
sl@0
  1373
		if (*pattern == '\0') {
sl@0
  1374
		    pattern = Tcl_UtfPrev(pattern, pstart);
sl@0
  1375
		    break;
sl@0
  1376
		}
sl@0
  1377
		pattern++;
sl@0
  1378
	    }
sl@0
  1379
	    pattern++;
sl@0
  1380
	    continue;
sl@0
  1381
	}
sl@0
  1382
sl@0
  1383
	/*
sl@0
  1384
	 * If the next pattern character is '\', just strip off the '\'
sl@0
  1385
	 * so we do exact matching on the character that follows.
sl@0
  1386
	 */
sl@0
  1387
sl@0
  1388
	if (p == '\\') {
sl@0
  1389
	    pattern++;
sl@0
  1390
	    if (*pattern == '\0') {
sl@0
  1391
		return 0;
sl@0
  1392
	    }
sl@0
  1393
	}
sl@0
  1394
sl@0
  1395
	/*
sl@0
  1396
	 * There's no special character.  Just make sure that the next
sl@0
  1397
	 * bytes of each string match.
sl@0
  1398
	 */
sl@0
  1399
sl@0
  1400
	string  += TclUtfToUniChar(string, &ch1);
sl@0
  1401
	pattern += TclUtfToUniChar(pattern, &ch2);
sl@0
  1402
	if (nocase) {
sl@0
  1403
	    if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) {
sl@0
  1404
		return 0;
sl@0
  1405
	    }
sl@0
  1406
	} else if (ch1 != ch2) {
sl@0
  1407
	    return 0;
sl@0
  1408
	}
sl@0
  1409
    }
sl@0
  1410
}
sl@0
  1411

sl@0
  1412
/*
sl@0
  1413
 *----------------------------------------------------------------------
sl@0
  1414
 *
sl@0
  1415
 * TclMatchIsTrivial --
sl@0
  1416
 *
sl@0
  1417
 *	Test whether a particular glob pattern is a trivial pattern.
sl@0
  1418
 *	(i.e. where matching is the same as equality testing).
sl@0
  1419
 *
sl@0
  1420
 * Results:
sl@0
  1421
 *	A boolean indicating whether the pattern is free of all of the
sl@0
  1422
 *	glob special chars.
sl@0
  1423
 *
sl@0
  1424
 * Side effects:
sl@0
  1425
 *	None.
sl@0
  1426
 *
sl@0
  1427
 *----------------------------------------------------------------------
sl@0
  1428
 */
sl@0
  1429
sl@0
  1430
int
sl@0
  1431
TclMatchIsTrivial(pattern)
sl@0
  1432
    CONST char *pattern;
sl@0
  1433
{
sl@0
  1434
    CONST char *p = pattern;
sl@0
  1435
sl@0
  1436
    while (1) {
sl@0
  1437
	switch (*p++) {
sl@0
  1438
	case '\0':
sl@0
  1439
	    return 1;
sl@0
  1440
	case '*':
sl@0
  1441
	case '?':
sl@0
  1442
	case '[':
sl@0
  1443
	case '\\':
sl@0
  1444
	    return 0;
sl@0
  1445
	}
sl@0
  1446
    }
sl@0
  1447
}
sl@0
  1448

sl@0
  1449
/*
sl@0
  1450
 *----------------------------------------------------------------------
sl@0
  1451
 *
sl@0
  1452
 * Tcl_DStringInit --
sl@0
  1453
 *
sl@0
  1454
 *	Initializes a dynamic string, discarding any previous contents
sl@0
  1455
 *	of the string (Tcl_DStringFree should have been called already
sl@0
  1456
 *	if the dynamic string was previously in use).
sl@0
  1457
 *
sl@0
  1458
 * Results:
sl@0
  1459
 *	None.
sl@0
  1460
 *
sl@0
  1461
 * Side effects:
sl@0
  1462
 *	The dynamic string is initialized to be empty.
sl@0
  1463
 *
sl@0
  1464
 *----------------------------------------------------------------------
sl@0
  1465
 */
sl@0
  1466
sl@0
  1467
EXPORT_C void
sl@0
  1468
Tcl_DStringInit(dsPtr)
sl@0
  1469
    Tcl_DString *dsPtr;		/* Pointer to structure for dynamic string. */
sl@0
  1470
{
sl@0
  1471
    dsPtr->string = dsPtr->staticSpace;
sl@0
  1472
    dsPtr->length = 0;
sl@0
  1473
    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
sl@0
  1474
    dsPtr->staticSpace[0] = '\0';
sl@0
  1475
}
sl@0
  1476

sl@0
  1477
/*
sl@0
  1478
 *----------------------------------------------------------------------
sl@0
  1479
 *
sl@0
  1480
 * Tcl_DStringAppend --
sl@0
  1481
 *
sl@0
  1482
 *	Append more characters to the current value of a dynamic string.
sl@0
  1483
 *
sl@0
  1484
 * Results:
sl@0
  1485
 *	The return value is a pointer to the dynamic string's new value.
sl@0
  1486
 *
sl@0
  1487
 * Side effects:
sl@0
  1488
 *	Length bytes from string (or all of string if length is less
sl@0
  1489
 *	than zero) are added to the current value of the string. Memory
sl@0
  1490
 *	gets reallocated if needed to accomodate the string's new size.
sl@0
  1491
 *
sl@0
  1492
 *----------------------------------------------------------------------
sl@0
  1493
 */
sl@0
  1494
sl@0
  1495
EXPORT_C char *
sl@0
  1496
Tcl_DStringAppend(dsPtr, string, length)
sl@0
  1497
    Tcl_DString *dsPtr;		/* Structure describing dynamic string. */
sl@0
  1498
    CONST char *string;		/* String to append.  If length is -1 then
sl@0
  1499
				 * this must be null-terminated. */
sl@0
  1500
    int length;			/* Number of characters from string to
sl@0
  1501
				 * append.  If < 0, then append all of string,
sl@0
  1502
				 * up to null at end. */
sl@0
  1503
{
sl@0
  1504
    int newSize;
sl@0
  1505
    char *dst;
sl@0
  1506
    CONST char *end;
sl@0
  1507
sl@0
  1508
    if (length < 0) {
sl@0
  1509
	length = strlen(string);
sl@0
  1510
    }
sl@0
  1511
    newSize = length + dsPtr->length;
sl@0
  1512
sl@0
  1513
    /*
sl@0
  1514
     * Allocate a larger buffer for the string if the current one isn't
sl@0
  1515
     * large enough. Allocate extra space in the new buffer so that there
sl@0
  1516
     * will be room to grow before we have to allocate again.
sl@0
  1517
     */
sl@0
  1518
sl@0
  1519
    if (newSize >= dsPtr->spaceAvl) {
sl@0
  1520
	dsPtr->spaceAvl = newSize * 2;
sl@0
  1521
	if (dsPtr->string == dsPtr->staticSpace) {
sl@0
  1522
	    char *newString;
sl@0
  1523
sl@0
  1524
	    newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
sl@0
  1525
	    memcpy((VOID *) newString, (VOID *) dsPtr->string,
sl@0
  1526
		    (size_t) dsPtr->length);
sl@0
  1527
	    dsPtr->string = newString;
sl@0
  1528
	} else {
sl@0
  1529
	    dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
sl@0
  1530
		    (size_t) dsPtr->spaceAvl);
sl@0
  1531
	}
sl@0
  1532
    }
sl@0
  1533
sl@0
  1534
    /*
sl@0
  1535
     * Copy the new string into the buffer at the end of the old
sl@0
  1536
     * one.
sl@0
  1537
     */
sl@0
  1538
sl@0
  1539
    for (dst = dsPtr->string + dsPtr->length, end = string+length;
sl@0
  1540
	    string < end; string++, dst++) {
sl@0
  1541
	*dst = *string;
sl@0
  1542
    }
sl@0
  1543
    *dst = '\0';
sl@0
  1544
    dsPtr->length += length;
sl@0
  1545
    return dsPtr->string;
sl@0
  1546
}
sl@0
  1547

sl@0
  1548
/*
sl@0
  1549
 *----------------------------------------------------------------------
sl@0
  1550
 *
sl@0
  1551
 * Tcl_DStringAppendElement --
sl@0
  1552
 *
sl@0
  1553
 *	Append a list element to the current value of a dynamic string.
sl@0
  1554
 *
sl@0
  1555
 * Results:
sl@0
  1556
 *	The return value is a pointer to the dynamic string's new value.
sl@0
  1557
 *
sl@0
  1558
 * Side effects:
sl@0
  1559
 *	String is reformatted as a list element and added to the current
sl@0
  1560
 *	value of the string.  Memory gets reallocated if needed to
sl@0
  1561
 *	accomodate the string's new size.
sl@0
  1562
 *
sl@0
  1563
 *----------------------------------------------------------------------
sl@0
  1564
 */
sl@0
  1565
sl@0
  1566
EXPORT_C char *
sl@0
  1567
Tcl_DStringAppendElement(dsPtr, string)
sl@0
  1568
    Tcl_DString *dsPtr;		/* Structure describing dynamic string. */
sl@0
  1569
    CONST char *string;		/* String to append.  Must be
sl@0
  1570
				 * null-terminated. */
sl@0
  1571
{
sl@0
  1572
    int newSize, flags, strSize;
sl@0
  1573
    char *dst;
sl@0
  1574
sl@0
  1575
    strSize = ((string == NULL) ? 0 : strlen(string));
sl@0
  1576
    newSize = Tcl_ScanCountedElement(string, strSize, &flags)
sl@0
  1577
	+ dsPtr->length + 1;
sl@0
  1578
sl@0
  1579
    /*
sl@0
  1580
     * Allocate a larger buffer for the string if the current one isn't
sl@0
  1581
     * large enough.  Allocate extra space in the new buffer so that there
sl@0
  1582
     * will be room to grow before we have to allocate again.
sl@0
  1583
     * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
sl@0
  1584
     * to a larger buffer, since there may be embedded NULLs in the
sl@0
  1585
     * string in some cases.
sl@0
  1586
     */
sl@0
  1587
sl@0
  1588
    if (newSize >= dsPtr->spaceAvl) {
sl@0
  1589
	dsPtr->spaceAvl = newSize * 2;
sl@0
  1590
	if (dsPtr->string == dsPtr->staticSpace) {
sl@0
  1591
	    char *newString;
sl@0
  1592
sl@0
  1593
	    newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
sl@0
  1594
	    memcpy((VOID *) newString, (VOID *) dsPtr->string,
sl@0
  1595
		    (size_t) dsPtr->length);
sl@0
  1596
	    dsPtr->string = newString;
sl@0
  1597
	} else {
sl@0
  1598
	    dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
sl@0
  1599
		    (size_t) dsPtr->spaceAvl);
sl@0
  1600
	}
sl@0
  1601
    }
sl@0
  1602
sl@0
  1603
    /*
sl@0
  1604
     * Convert the new string to a list element and copy it into the
sl@0
  1605
     * buffer at the end, with a space, if needed.
sl@0
  1606
     */
sl@0
  1607
sl@0
  1608
    dst = dsPtr->string + dsPtr->length;
sl@0
  1609
    if (TclNeedSpace(dsPtr->string, dst)) {
sl@0
  1610
	*dst = ' ';
sl@0
  1611
	dst++;
sl@0
  1612
	dsPtr->length++;
sl@0
  1613
    }
sl@0
  1614
    dsPtr->length += Tcl_ConvertCountedElement(string, strSize, dst, flags);
sl@0
  1615
    return dsPtr->string;
sl@0
  1616
}
sl@0
  1617

sl@0
  1618
/*
sl@0
  1619
 *----------------------------------------------------------------------
sl@0
  1620
 *
sl@0
  1621
 * Tcl_DStringSetLength --
sl@0
  1622
 *
sl@0
  1623
 *	Change the length of a dynamic string.  This can cause the
sl@0
  1624
 *	string to either grow or shrink, depending on the value of
sl@0
  1625
 *	length.
sl@0
  1626
 *
sl@0
  1627
 * Results:
sl@0
  1628
 *	None.
sl@0
  1629
 *
sl@0
  1630
 * Side effects:
sl@0
  1631
 *	The length of dsPtr is changed to length and a null byte is
sl@0
  1632
 *	stored at that position in the string.  If length is larger
sl@0
  1633
 *	than the space allocated for dsPtr, then a panic occurs.
sl@0
  1634
 *
sl@0
  1635
 *----------------------------------------------------------------------
sl@0
  1636
 */
sl@0
  1637
sl@0
  1638
EXPORT_C void
sl@0
  1639
Tcl_DStringSetLength(dsPtr, length)
sl@0
  1640
    Tcl_DString *dsPtr;		/* Structure describing dynamic string. */
sl@0
  1641
    int length;			/* New length for dynamic string. */
sl@0
  1642
{
sl@0
  1643
    int newsize;
sl@0
  1644
sl@0
  1645
    if (length < 0) {
sl@0
  1646
	length = 0;
sl@0
  1647
    }
sl@0
  1648
    if (length >= dsPtr->spaceAvl) {
sl@0
  1649
	/*
sl@0
  1650
	 * There are two interesting cases here.  In the first case, the user
sl@0
  1651
	 * may be trying to allocate a large buffer of a specific size.  It
sl@0
  1652
	 * would be wasteful to overallocate that buffer, so we just allocate
sl@0
  1653
	 * enough for the requested size plus the trailing null byte.  In the
sl@0
  1654
	 * second case, we are growing the buffer incrementally, so we need
sl@0
  1655
	 * behavior similar to Tcl_DStringAppend.  The requested length will
sl@0
  1656
	 * usually be a small delta above the current spaceAvl, so we'll end up
sl@0
  1657
	 * doubling the old size.  This won't grow the buffer quite as quickly,
sl@0
  1658
	 * but it should be close enough.
sl@0
  1659
	 */
sl@0
  1660
sl@0
  1661
	newsize = dsPtr->spaceAvl * 2;
sl@0
  1662
	if (length < newsize) {
sl@0
  1663
	    dsPtr->spaceAvl = newsize;
sl@0
  1664
	} else {
sl@0
  1665
	    dsPtr->spaceAvl = length + 1;
sl@0
  1666
	}
sl@0
  1667
	if (dsPtr->string == dsPtr->staticSpace) {
sl@0
  1668
	    char *newString;
sl@0
  1669
sl@0
  1670
	    newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
sl@0
  1671
	    memcpy((VOID *) newString, (VOID *) dsPtr->string,
sl@0
  1672
		    (size_t) dsPtr->length);
sl@0
  1673
	    dsPtr->string = newString;
sl@0
  1674
	} else {
sl@0
  1675
	    dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
sl@0
  1676
		    (size_t) dsPtr->spaceAvl);
sl@0
  1677
	}
sl@0
  1678
    }
sl@0
  1679
    dsPtr->length = length;
sl@0
  1680
    dsPtr->string[length] = 0;
sl@0
  1681
}
sl@0
  1682

sl@0
  1683
/*
sl@0
  1684
 *----------------------------------------------------------------------
sl@0
  1685
 *
sl@0
  1686
 * Tcl_DStringFree --
sl@0
  1687
 *
sl@0
  1688
 *	Frees up any memory allocated for the dynamic string and
sl@0
  1689
 *	reinitializes the string to an empty state.
sl@0
  1690
 *
sl@0
  1691
 * Results:
sl@0
  1692
 *	None.
sl@0
  1693
 *
sl@0
  1694
 * Side effects:
sl@0
  1695
 *	The previous contents of the dynamic string are lost, and
sl@0
  1696
 *	the new value is an empty string.
sl@0
  1697
 *
sl@0
  1698
 *---------------------------------------------------------------------- */
sl@0
  1699
sl@0
  1700
EXPORT_C void
sl@0
  1701
Tcl_DStringFree(dsPtr)
sl@0
  1702
    Tcl_DString *dsPtr;		/* Structure describing dynamic string. */
sl@0
  1703
{
sl@0
  1704
    if (dsPtr->string != dsPtr->staticSpace) {
sl@0
  1705
	ckfree(dsPtr->string);
sl@0
  1706
    }
sl@0
  1707
    dsPtr->string = dsPtr->staticSpace;
sl@0
  1708
    dsPtr->length = 0;
sl@0
  1709
    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
sl@0
  1710
    dsPtr->staticSpace[0] = '\0';
sl@0
  1711
}
sl@0
  1712

sl@0
  1713
/*
sl@0
  1714
 *----------------------------------------------------------------------
sl@0
  1715
 *
sl@0
  1716
 * Tcl_DStringResult --
sl@0
  1717
 *
sl@0
  1718
 *	This procedure moves the value of a dynamic string into an
sl@0
  1719
 *	interpreter as its string result. Afterwards, the dynamic string
sl@0
  1720
 *	is reset to an empty string.
sl@0
  1721
 *
sl@0
  1722
 * Results:
sl@0
  1723
 *	None.
sl@0
  1724
 *
sl@0
  1725
 * Side effects:
sl@0
  1726
 *	The string is "moved" to interp's result, and any existing
sl@0
  1727
 *	string result for interp is freed. dsPtr is reinitialized to
sl@0
  1728
 *	an empty string.
sl@0
  1729
 *
sl@0
  1730
 *----------------------------------------------------------------------
sl@0
  1731
 */
sl@0
  1732
sl@0
  1733
EXPORT_C void
sl@0
  1734
Tcl_DStringResult(interp, dsPtr)
sl@0
  1735
    Tcl_Interp *interp;		/* Interpreter whose result is to be reset. */
sl@0
  1736
    Tcl_DString *dsPtr;		/* Dynamic string that is to become the
sl@0
  1737
				 * result of interp. */
sl@0
  1738
{
sl@0
  1739
    Tcl_ResetResult(interp);
sl@0
  1740
    
sl@0
  1741
    if (dsPtr->string != dsPtr->staticSpace) {
sl@0
  1742
	interp->result = dsPtr->string;
sl@0
  1743
	interp->freeProc = TCL_DYNAMIC;
sl@0
  1744
    } else if (dsPtr->length < TCL_RESULT_SIZE) {
sl@0
  1745
	interp->result = ((Interp *) interp)->resultSpace;
sl@0
  1746
	strcpy(interp->result, dsPtr->string);
sl@0
  1747
    } else {
sl@0
  1748
	Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
sl@0
  1749
    }
sl@0
  1750
    
sl@0
  1751
    dsPtr->string = dsPtr->staticSpace;
sl@0
  1752
    dsPtr->length = 0;
sl@0
  1753
    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
sl@0
  1754
    dsPtr->staticSpace[0] = '\0';
sl@0
  1755
}
sl@0
  1756

sl@0
  1757
/*
sl@0
  1758
 *----------------------------------------------------------------------
sl@0
  1759
 *
sl@0
  1760
 * Tcl_DStringGetResult --
sl@0
  1761
 *
sl@0
  1762
 *	This procedure moves an interpreter's result into a dynamic string.
sl@0
  1763
 *
sl@0
  1764
 * Results:
sl@0
  1765
 *	None.
sl@0
  1766
 *
sl@0
  1767
 * Side effects:
sl@0
  1768
 *	The interpreter's string result is cleared, and the previous
sl@0
  1769
 *	contents of dsPtr are freed.
sl@0
  1770
 *
sl@0
  1771
 *	If the string result is empty, the object result is moved to the
sl@0
  1772
 *	string result, then the object result is reset.
sl@0
  1773
 *
sl@0
  1774
 *----------------------------------------------------------------------
sl@0
  1775
 */
sl@0
  1776
sl@0
  1777
EXPORT_C void
sl@0
  1778
Tcl_DStringGetResult(interp, dsPtr)
sl@0
  1779
    Tcl_Interp *interp;		/* Interpreter whose result is to be reset. */
sl@0
  1780
    Tcl_DString *dsPtr;		/* Dynamic string that is to become the
sl@0
  1781
				 * result of interp. */
sl@0
  1782
{
sl@0
  1783
    Interp *iPtr = (Interp *) interp;
sl@0
  1784
    
sl@0
  1785
    if (dsPtr->string != dsPtr->staticSpace) {
sl@0
  1786
	ckfree(dsPtr->string);
sl@0
  1787
    }
sl@0
  1788
sl@0
  1789
    /*
sl@0
  1790
     * If the string result is empty, move the object result to the
sl@0
  1791
     * string result, then reset the object result.
sl@0
  1792
     */
sl@0
  1793
sl@0
  1794
    if (*(iPtr->result) == 0) {
sl@0
  1795
	Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
sl@0
  1796
	        TCL_VOLATILE);
sl@0
  1797
    }
sl@0
  1798
sl@0
  1799
    dsPtr->length = strlen(iPtr->result);
sl@0
  1800
    if (iPtr->freeProc != NULL) {
sl@0
  1801
	if (iPtr->freeProc == TCL_DYNAMIC) {
sl@0
  1802
	    dsPtr->string = iPtr->result;
sl@0
  1803
	    dsPtr->spaceAvl = dsPtr->length+1;
sl@0
  1804
	} else {
sl@0
  1805
	    dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
sl@0
  1806
	    strcpy(dsPtr->string, iPtr->result);
sl@0
  1807
	    (*iPtr->freeProc)(iPtr->result);
sl@0
  1808
	}
sl@0
  1809
	dsPtr->spaceAvl = dsPtr->length+1;
sl@0
  1810
	iPtr->freeProc = NULL;
sl@0
  1811
    } else {
sl@0
  1812
	if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
sl@0
  1813
	    dsPtr->string = dsPtr->staticSpace;
sl@0
  1814
	    dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
sl@0
  1815
	} else {
sl@0
  1816
	    dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
sl@0
  1817
	    dsPtr->spaceAvl = dsPtr->length + 1;
sl@0
  1818
	}
sl@0
  1819
	strcpy(dsPtr->string, iPtr->result);
sl@0
  1820
    }
sl@0
  1821
    
sl@0
  1822
    iPtr->result = iPtr->resultSpace;
sl@0
  1823
    iPtr->resultSpace[0] = 0;
sl@0
  1824
}
sl@0
  1825

sl@0
  1826
/*
sl@0
  1827
 *----------------------------------------------------------------------
sl@0
  1828
 *
sl@0
  1829
 * Tcl_DStringStartSublist --
sl@0
  1830
 *
sl@0
  1831
 *	This procedure adds the necessary information to a dynamic
sl@0
  1832
 *	string (e.g. " {" to start a sublist.  Future element
sl@0
  1833
 *	appends will be in the sublist rather than the main list.
sl@0
  1834
 *
sl@0
  1835
 * Results:
sl@0
  1836
 *	None.
sl@0
  1837
 *
sl@0
  1838
 * Side effects:
sl@0
  1839
 *	Characters get added to the dynamic string.
sl@0
  1840
 *
sl@0
  1841
 *----------------------------------------------------------------------
sl@0
  1842
 */
sl@0
  1843
sl@0
  1844
EXPORT_C void
sl@0
  1845
Tcl_DStringStartSublist(dsPtr)
sl@0
  1846
    Tcl_DString *dsPtr;			/* Dynamic string. */
sl@0
  1847
{
sl@0
  1848
    if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
sl@0
  1849
	Tcl_DStringAppend(dsPtr, " {", -1);
sl@0
  1850
    } else {
sl@0
  1851
	Tcl_DStringAppend(dsPtr, "{", -1);
sl@0
  1852
    }
sl@0
  1853
}
sl@0
  1854

sl@0
  1855
/*
sl@0
  1856
 *----------------------------------------------------------------------
sl@0
  1857
 *
sl@0
  1858
 * Tcl_DStringEndSublist --
sl@0
  1859
 *
sl@0
  1860
 *	This procedure adds the necessary characters to a dynamic
sl@0
  1861
 *	string to end a sublist (e.g. "}").  Future element appends
sl@0
  1862
 *	will be in the enclosing (sub)list rather than the current
sl@0
  1863
 *	sublist.
sl@0
  1864
 *
sl@0
  1865
 * Results:
sl@0
  1866
 *	None.
sl@0
  1867
 *
sl@0
  1868
 * Side effects:
sl@0
  1869
 *	None.
sl@0
  1870
 *
sl@0
  1871
 *----------------------------------------------------------------------
sl@0
  1872
 */
sl@0
  1873
sl@0
  1874
EXPORT_C void
sl@0
  1875
Tcl_DStringEndSublist(dsPtr)
sl@0
  1876
    Tcl_DString *dsPtr;			/* Dynamic string. */
sl@0
  1877
{
sl@0
  1878
    Tcl_DStringAppend(dsPtr, "}", -1);
sl@0
  1879
}
sl@0
  1880

sl@0
  1881
/*
sl@0
  1882
 *----------------------------------------------------------------------
sl@0
  1883
 *
sl@0
  1884
 * Tcl_PrintDouble --
sl@0
  1885
 *
sl@0
  1886
 *	Given a floating-point value, this procedure converts it to
sl@0
  1887
 *	an ASCII string using.
sl@0
  1888
 *
sl@0
  1889
 * Results:
sl@0
  1890
 *	The ASCII equivalent of "value" is written at "dst".  It is
sl@0
  1891
 *	written using the current precision, and it is guaranteed to
sl@0
  1892
 *	contain a decimal point or exponent, so that it looks like
sl@0
  1893
 *	a floating-point value and not an integer.
sl@0
  1894
 *
sl@0
  1895
 * Side effects:
sl@0
  1896
 *	None.
sl@0
  1897
 *
sl@0
  1898
 *----------------------------------------------------------------------
sl@0
  1899
 */
sl@0
  1900
sl@0
  1901
EXPORT_C void
sl@0
  1902
Tcl_PrintDouble(interp, value, dst)
sl@0
  1903
    Tcl_Interp *interp;			/* Interpreter whose tcl_precision
sl@0
  1904
					 * variable used to be used to control
sl@0
  1905
					 * printing.  It's ignored now. */
sl@0
  1906
    double value;			/* Value to print as string. */
sl@0
  1907
    char *dst;				/* Where to store converted value;
sl@0
  1908
					 * must have at least TCL_DOUBLE_SPACE
sl@0
  1909
					 * characters. */
sl@0
  1910
{
sl@0
  1911
    char *p, c;
sl@0
  1912
    Tcl_UniChar ch;
sl@0
  1913
sl@0
  1914
    Tcl_MutexLock(&precisionMutex);
sl@0
  1915
    sprintf(dst, precisionFormat, value);
sl@0
  1916
    Tcl_MutexUnlock(&precisionMutex);
sl@0
  1917
sl@0
  1918
    /*
sl@0
  1919
     * If the ASCII result looks like an integer, add ".0" so that it
sl@0
  1920
     * doesn't look like an integer anymore.  This prevents floating-point
sl@0
  1921
     * values from being converted to integers unintentionally.
sl@0
  1922
     * Check for ASCII specifically to speed up the function.
sl@0
  1923
     */
sl@0
  1924
sl@0
  1925
    for (p = dst; *p != 0; ) {
sl@0
  1926
	if (UCHAR(*p) < 0x80) {
sl@0
  1927
	    c = *p++;
sl@0
  1928
	} else {
sl@0
  1929
	    p += Tcl_UtfToUniChar(p, &ch);
sl@0
  1930
	    c = UCHAR(ch);
sl@0
  1931
	}
sl@0
  1932
	if ((c == '.') || isalpha(UCHAR(c))) {	/* INTL: ISO only. */
sl@0
  1933
	    return;
sl@0
  1934
	}
sl@0
  1935
    }
sl@0
  1936
    p[0] = '.';
sl@0
  1937
    p[1] = '0';
sl@0
  1938
    p[2] = 0;
sl@0
  1939
}
sl@0
  1940

sl@0
  1941
/*
sl@0
  1942
 *----------------------------------------------------------------------
sl@0
  1943
 *
sl@0
  1944
 * TclPrecTraceProc --
sl@0
  1945
 *
sl@0
  1946
 *	This procedure is invoked whenever the variable "tcl_precision"
sl@0
  1947
 *	is written.
sl@0
  1948
 *
sl@0
  1949
 * Results:
sl@0
  1950
 *	Returns NULL if all went well, or an error message if the
sl@0
  1951
 *	new value for the variable doesn't make sense.
sl@0
  1952
 *
sl@0
  1953
 * Side effects:
sl@0
  1954
 *	If the new value doesn't make sense then this procedure
sl@0
  1955
 *	undoes the effect of the variable modification.  Otherwise
sl@0
  1956
 *	it modifies the format string that's used by Tcl_PrintDouble.
sl@0
  1957
 *
sl@0
  1958
 *----------------------------------------------------------------------
sl@0
  1959
 */
sl@0
  1960
sl@0
  1961
	/* ARGSUSED */
sl@0
  1962
char *
sl@0
  1963
TclPrecTraceProc(clientData, interp, name1, name2, flags)
sl@0
  1964
    ClientData clientData;	/* Not used. */
sl@0
  1965
    Tcl_Interp *interp;		/* Interpreter containing variable. */
sl@0
  1966
    CONST char *name1;		/* Name of variable. */
sl@0
  1967
    CONST char *name2;		/* Second part of variable name. */
sl@0
  1968
    int flags;			/* Information about what happened. */
sl@0
  1969
{
sl@0
  1970
    CONST char *value;
sl@0
  1971
    char *end;
sl@0
  1972
    int prec;
sl@0
  1973
sl@0
  1974
    /*
sl@0
  1975
     * If the variable is unset, then recreate the trace.
sl@0
  1976
     */
sl@0
  1977
sl@0
  1978
    if (flags & TCL_TRACE_UNSETS) {
sl@0
  1979
	if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) {
sl@0
  1980
	    Tcl_TraceVar2(interp, name1, name2,
sl@0
  1981
		    TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
sl@0
  1982
		    |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData);
sl@0
  1983
	}
sl@0
  1984
	return (char *) NULL;
sl@0
  1985
    }
sl@0
  1986
sl@0
  1987
    /*
sl@0
  1988
     * When the variable is read, reset its value from our shared
sl@0
  1989
     * value.  This is needed in case the variable was modified in
sl@0
  1990
     * some other interpreter so that this interpreter's value is
sl@0
  1991
     * out of date.
sl@0
  1992
     */
sl@0
  1993
sl@0
  1994
    Tcl_MutexLock(&precisionMutex);
sl@0
  1995
sl@0
  1996
    if (flags & TCL_TRACE_READS) {
sl@0
  1997
	Tcl_SetVar2(interp, name1, name2, precisionString,
sl@0
  1998
		flags & TCL_GLOBAL_ONLY);
sl@0
  1999
	Tcl_MutexUnlock(&precisionMutex);
sl@0
  2000
	return (char *) NULL;
sl@0
  2001
    }
sl@0
  2002
sl@0
  2003
    /*
sl@0
  2004
     * The variable is being written.  Check the new value and disallow
sl@0
  2005
     * it if it isn't reasonable or if this is a safe interpreter (we
sl@0
  2006
     * don't want safe interpreters messing up the precision of other
sl@0
  2007
     * interpreters).
sl@0
  2008
     */
sl@0
  2009
sl@0
  2010
    if (Tcl_IsSafe(interp)) {
sl@0
  2011
	Tcl_SetVar2(interp, name1, name2, precisionString,
sl@0
  2012
		flags & TCL_GLOBAL_ONLY);
sl@0
  2013
	Tcl_MutexUnlock(&precisionMutex);
sl@0
  2014
	return "can't modify precision from a safe interpreter";
sl@0
  2015
    }
sl@0
  2016
    value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
sl@0
  2017
    if (value == NULL) {
sl@0
  2018
	value = "";
sl@0
  2019
    }
sl@0
  2020
    prec = strtoul(value, &end, 10);
sl@0
  2021
    if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
sl@0
  2022
	    (end == value) || (*end != 0)) {
sl@0
  2023
	Tcl_SetVar2(interp, name1, name2, precisionString,
sl@0
  2024
		flags & TCL_GLOBAL_ONLY);
sl@0
  2025
	Tcl_MutexUnlock(&precisionMutex);
sl@0
  2026
	return "improper value for precision";
sl@0
  2027
    }
sl@0
  2028
    TclFormatInt(precisionString, prec);
sl@0
  2029
    sprintf(precisionFormat, "%%.%dg", prec);
sl@0
  2030
    Tcl_MutexUnlock(&precisionMutex);
sl@0
  2031
    return (char *) NULL;
sl@0
  2032
}
sl@0
  2033

sl@0
  2034
/*
sl@0
  2035
 *----------------------------------------------------------------------
sl@0
  2036
 *
sl@0
  2037
 * TclNeedSpace --
sl@0
  2038
 *
sl@0
  2039
 *	This procedure checks to see whether it is appropriate to
sl@0
  2040
 *	add a space before appending a new list element to an
sl@0
  2041
 *	existing string.
sl@0
  2042
 *
sl@0
  2043
 * Results:
sl@0
  2044
 *	The return value is 1 if a space is appropriate, 0 otherwise.
sl@0
  2045
 *
sl@0
  2046
 * Side effects:
sl@0
  2047
 *	None.
sl@0
  2048
 *
sl@0
  2049
 *----------------------------------------------------------------------
sl@0
  2050
 */
sl@0
  2051
sl@0
  2052
int
sl@0
  2053
TclNeedSpace(start, end)
sl@0
  2054
    CONST char *start;		/* First character in string. */
sl@0
  2055
    CONST char *end;		/* End of string (place where space will
sl@0
  2056
				 * be added, if appropriate). */
sl@0
  2057
{
sl@0
  2058
    /*
sl@0
  2059
     * A space is needed unless either
sl@0
  2060
     * (a) we're at the start of the string, or
sl@0
  2061
     */
sl@0
  2062
    if (end == start) {
sl@0
  2063
	return 0;
sl@0
  2064
    }
sl@0
  2065
sl@0
  2066
    /*
sl@0
  2067
     * (b) we're at the start of a nested list-element, quoted with an
sl@0
  2068
     *     open curly brace; we can be nested arbitrarily deep, so long
sl@0
  2069
     *     as the first curly brace starts an element, so backtrack over
sl@0
  2070
     *     open curly braces that are trailing characters of the string; and
sl@0
  2071
     */
sl@0
  2072
sl@0
  2073
    end = Tcl_UtfPrev(end, start);
sl@0
  2074
    while (*end == '{') {
sl@0
  2075
	if (end == start) {
sl@0
  2076
	    return 0;
sl@0
  2077
	}
sl@0
  2078
	end = Tcl_UtfPrev(end, start);
sl@0
  2079
    }
sl@0
  2080
sl@0
  2081
    /*
sl@0
  2082
     * (c) the trailing character of the string is already a list-element
sl@0
  2083
     *     separator (according to TclFindElement); that is, one of these
sl@0
  2084
     *     characters:
sl@0
  2085
     *     	\u0009	\t	TAB
sl@0
  2086
     *     	\u000A	\n	NEWLINE
sl@0
  2087
     *     	\u000B	\v	VERTICAL TAB
sl@0
  2088
     *     	\u000C	\f	FORM FEED
sl@0
  2089
     *     	\u000D	\r	CARRIAGE RETURN
sl@0
  2090
     *     	\u0020		SPACE
sl@0
  2091
     *     with the condition that the penultimate character is not a
sl@0
  2092
     *     backslash.
sl@0
  2093
     */
sl@0
  2094
sl@0
  2095
    if (*end > 0x20) {
sl@0
  2096
	/*
sl@0
  2097
	 * Performance tweak.  All ASCII spaces are <= 0x20. So get
sl@0
  2098
	 * a quick answer for most characters before comparing against
sl@0
  2099
	 * all spaces in the switch below.
sl@0
  2100
	 *
sl@0
  2101
	 * NOTE: Remove this if other Unicode spaces ever get accepted
sl@0
  2102
	 * as list-element separators.
sl@0
  2103
	 */
sl@0
  2104
	return 1;
sl@0
  2105
    }
sl@0
  2106
    switch (*end) {
sl@0
  2107
	case ' ':
sl@0
  2108
        case '\t':
sl@0
  2109
        case '\n':
sl@0
  2110
        case '\r':
sl@0
  2111
        case '\v':
sl@0
  2112
        case '\f':
sl@0
  2113
	    if ((end == start) || (end[-1] != '\\')) {
sl@0
  2114
		return 0;
sl@0
  2115
	    }
sl@0
  2116
    }
sl@0
  2117
    return 1;
sl@0
  2118
}
sl@0
  2119

sl@0
  2120
/*
sl@0
  2121
 *----------------------------------------------------------------------
sl@0
  2122
 *
sl@0
  2123
 * TclFormatInt --
sl@0
  2124
 *
sl@0
  2125
 *	This procedure formats an integer into a sequence of decimal digit
sl@0
  2126
 *	characters in a buffer. If the integer is negative, a minus sign is
sl@0
  2127
 *	inserted at the start of the buffer. A null character is inserted at
sl@0
  2128
 *	the end of the formatted characters. It is the caller's
sl@0
  2129
 *	responsibility to ensure that enough storage is available. This
sl@0
  2130
 *	procedure has the effect of sprintf(buffer, "%d", n) but is faster.
sl@0
  2131
 *
sl@0
  2132
 * Results:
sl@0
  2133
 *	An integer representing the number of characters formatted, not
sl@0
  2134
 *	including the terminating \0.
sl@0
  2135
 *
sl@0
  2136
 * Side effects:
sl@0
  2137
 *	The formatted characters are written into the storage pointer to
sl@0
  2138
 *	by the "buffer" argument.
sl@0
  2139
 *
sl@0
  2140
 *----------------------------------------------------------------------
sl@0
  2141
 */
sl@0
  2142
sl@0
  2143
int
sl@0
  2144
TclFormatInt(buffer, n)
sl@0
  2145
    char *buffer;		/* Points to the storage into which the
sl@0
  2146
				 * formatted characters are written. */
sl@0
  2147
    long n;			/* The integer to format. */
sl@0
  2148
{
sl@0
  2149
    long intVal;
sl@0
  2150
    int i;
sl@0
  2151
    int numFormatted, j;
sl@0
  2152
    char *digits = "0123456789";
sl@0
  2153
sl@0
  2154
    /*
sl@0
  2155
     * Check first whether "n" is zero.
sl@0
  2156
     */
sl@0
  2157
sl@0
  2158
    if (n == 0) {
sl@0
  2159
	buffer[0] = '0';
sl@0
  2160
	buffer[1] = 0;
sl@0
  2161
	return 1;
sl@0
  2162
    }
sl@0
  2163
sl@0
  2164
    /*
sl@0
  2165
     * Check whether "n" is the maximum negative value. This is
sl@0
  2166
     * -2^(m-1) for an m-bit word, and has no positive equivalent;
sl@0
  2167
     * negating it produces the same value.
sl@0
  2168
     */
sl@0
  2169
sl@0
  2170
    if (n == -n) {
sl@0
  2171
	sprintf(buffer, "%ld", n);
sl@0
  2172
	return strlen(buffer);
sl@0
  2173
    }
sl@0
  2174
sl@0
  2175
    /*
sl@0
  2176
     * Generate the characters of the result backwards in the buffer.
sl@0
  2177
     */
sl@0
  2178
sl@0
  2179
    intVal = (n < 0? -n : n);
sl@0
  2180
    i = 0;
sl@0
  2181
    buffer[0] = '\0';
sl@0
  2182
    do {
sl@0
  2183
	i++;
sl@0
  2184
	buffer[i] = digits[intVal % 10];
sl@0
  2185
	intVal = intVal/10;
sl@0
  2186
    } while (intVal > 0);
sl@0
  2187
    if (n < 0) {
sl@0
  2188
	i++;
sl@0
  2189
	buffer[i] = '-';
sl@0
  2190
    }
sl@0
  2191
    numFormatted = i;
sl@0
  2192
sl@0
  2193
    /*
sl@0
  2194
     * Now reverse the characters.
sl@0
  2195
     */
sl@0
  2196
sl@0
  2197
    for (j = 0;  j < i;  j++, i--) {
sl@0
  2198
	char tmp = buffer[i];
sl@0
  2199
	buffer[i] = buffer[j];
sl@0
  2200
	buffer[j] = tmp;
sl@0
  2201
    }
sl@0
  2202
    return numFormatted;
sl@0
  2203
}
sl@0
  2204

sl@0
  2205
/*
sl@0
  2206
 *----------------------------------------------------------------------
sl@0
  2207
 *
sl@0
  2208
 * TclLooksLikeInt --
sl@0
  2209
 *
sl@0
  2210
 *	This procedure decides whether the leading characters of a
sl@0
  2211
 *	string look like an integer or something else (such as a
sl@0
  2212
 *	floating-point number or string).
sl@0
  2213
 *
sl@0
  2214
 * Results:
sl@0
  2215
 *	The return value is 1 if the leading characters of p look
sl@0
  2216
 *	like a valid Tcl integer.  If they look like a floating-point
sl@0
  2217
 *	number (e.g. "e01" or "2.4"), or if they don't look like a
sl@0
  2218
 *	number at all, then 0 is returned.
sl@0
  2219
 *
sl@0
  2220
 * Side effects:
sl@0
  2221
 *	None.
sl@0
  2222
 *
sl@0
  2223
 *----------------------------------------------------------------------
sl@0
  2224
 */
sl@0
  2225
sl@0
  2226
int
sl@0
  2227
TclLooksLikeInt(bytes, length)
sl@0
  2228
    register CONST char *bytes;	/* Points to first byte of the string. */
sl@0
  2229
    int length;			/* Number of bytes in the string. If < 0
sl@0
  2230
				 * bytes up to the first null byte are
sl@0
  2231
				 * considered (if they may appear in an 
sl@0
  2232
				 * integer). */
sl@0
  2233
{
sl@0
  2234
    register CONST char *p;
sl@0
  2235
sl@0
  2236
    if ((bytes == NULL) && (length > 0)) {
sl@0
  2237
	Tcl_Panic("TclLooksLikeInt: cannot scan %d bytes from NULL", length);
sl@0
  2238
    }
sl@0
  2239
sl@0
  2240
    if (length < 0) {
sl@0
  2241
        length = (bytes? strlen(bytes) : 0);
sl@0
  2242
    }
sl@0
  2243
sl@0
  2244
    p = bytes;
sl@0
  2245
    while (length && isspace(UCHAR(*p))) { /* INTL: ISO space. */
sl@0
  2246
	length--; p++;
sl@0
  2247
    }
sl@0
  2248
    if (length == 0) {
sl@0
  2249
        return 0;
sl@0
  2250
    }
sl@0
  2251
    if ((*p == '+') || (*p == '-')) {
sl@0
  2252
        p++; length--;
sl@0
  2253
    }
sl@0
  2254
sl@0
  2255
    return (0 != TclParseInteger(p, length));
sl@0
  2256
}
sl@0
  2257

sl@0
  2258
/*
sl@0
  2259
 *----------------------------------------------------------------------
sl@0
  2260
 *
sl@0
  2261
 * TclGetIntForIndex --
sl@0
  2262
 *
sl@0
  2263
 *	This procedure returns an integer corresponding to the list index
sl@0
  2264
 *	held in a Tcl object. The Tcl object's value is expected to be
sl@0
  2265
 *	either an integer or a string of the form "end([+-]integer)?". 
sl@0
  2266
 *
sl@0
  2267
 * Results:
sl@0
  2268
 *	The return value is normally TCL_OK, which means that the index was
sl@0
  2269
 *	successfully stored into the location referenced by "indexPtr".  If
sl@0
  2270
 *	the Tcl object referenced by "objPtr" has the value "end", the
sl@0
  2271
 *	value stored is "endValue". If "objPtr"s values is not of the form
sl@0
  2272
 *	"end([+-]integer)?" and
sl@0
  2273
 *	can not be converted to an integer, TCL_ERROR is returned and, if
sl@0
  2274
 *	"interp" is non-NULL, an error message is left in the interpreter's
sl@0
  2275
 *	result object.
sl@0
  2276
 *
sl@0
  2277
 * Side effects:
sl@0
  2278
 *	The object referenced by "objPtr" might be converted to an
sl@0
  2279
 *	integer, wide integer, or end-based-index object.
sl@0
  2280
 *
sl@0
  2281
 *----------------------------------------------------------------------
sl@0
  2282
 */
sl@0
  2283
sl@0
  2284
int
sl@0
  2285
TclGetIntForIndex(interp, objPtr, endValue, indexPtr)
sl@0
  2286
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. 
sl@0
  2287
				 * If NULL, then no error message is left
sl@0
  2288
				 * after errors. */
sl@0
  2289
    Tcl_Obj *objPtr;		/* Points to an object containing either
sl@0
  2290
				 * "end" or an integer. */
sl@0
  2291
    int endValue;		/* The value to be stored at "indexPtr" if
sl@0
  2292
				 * "objPtr" holds "end". */
sl@0
  2293
    int *indexPtr;		/* Location filled in with an integer
sl@0
  2294
				 * representing an index. */
sl@0
  2295
{
sl@0
  2296
    if (Tcl_GetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
sl@0
  2297
	return TCL_OK;
sl@0
  2298
    }
sl@0
  2299
sl@0
  2300
    if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
sl@0
  2301
	/*
sl@0
  2302
	 * If the object is already an offset from the end of the
sl@0
  2303
	 * list, or can be converted to one, use it.
sl@0
  2304
	 */
sl@0
  2305
sl@0
  2306
	*indexPtr = endValue + objPtr->internalRep.longValue;
sl@0
  2307
sl@0
  2308
    } else {
sl@0
  2309
	/*
sl@0
  2310
	 * Report a parse error.
sl@0
  2311
	 */
sl@0
  2312
sl@0
  2313
	if (interp != NULL) {
sl@0
  2314
	    char *bytes = Tcl_GetString(objPtr);
sl@0
  2315
	    /*
sl@0
  2316
	     * The result might not be empty; this resets it which
sl@0
  2317
	     * should be both a cheap operation, and of little problem
sl@0
  2318
	     * because this is an error-generation path anyway.
sl@0
  2319
	     */
sl@0
  2320
	    Tcl_ResetResult(interp);
sl@0
  2321
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
  2322
				   "bad index \"", bytes,
sl@0
  2323
				   "\": must be integer or end?-integer?",
sl@0
  2324
				   (char *) NULL);
sl@0
  2325
	    if (!strncmp(bytes, "end-", 3)) {
sl@0
  2326
		bytes += 3;
sl@0
  2327
	    }
sl@0
  2328
	    TclCheckBadOctal(interp, bytes);
sl@0
  2329
	}
sl@0
  2330
sl@0
  2331
	return TCL_ERROR;
sl@0
  2332
    }
sl@0
  2333
	    
sl@0
  2334
    return TCL_OK;
sl@0
  2335
}
sl@0
  2336

sl@0
  2337
/*
sl@0
  2338
 *----------------------------------------------------------------------
sl@0
  2339
 *
sl@0
  2340
 * UpdateStringOfEndOffset --
sl@0
  2341
 *
sl@0
  2342
 *	Update the string rep of a Tcl object holding an "end-offset"
sl@0
  2343
 *	expression.
sl@0
  2344
 *
sl@0
  2345
 * Results:
sl@0
  2346
 *	None.
sl@0
  2347
 *
sl@0
  2348
 * Side effects:
sl@0
  2349
 *	Stores a valid string in the object's string rep.
sl@0
  2350
 *
sl@0
  2351
 * This procedure does NOT free any earlier string rep.  If it is
sl@0
  2352
 * called on an object that already has a valid string rep, it will
sl@0
  2353
 * leak memory.
sl@0
  2354
 *
sl@0
  2355
 *----------------------------------------------------------------------
sl@0
  2356
 */
sl@0
  2357
sl@0
  2358
static void
sl@0
  2359
UpdateStringOfEndOffset(objPtr)
sl@0
  2360
    register Tcl_Obj* objPtr;
sl@0
  2361
{
sl@0
  2362
    char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1];
sl@0
  2363
    register int len;
sl@0
  2364
sl@0
  2365
    strcpy(buffer, "end");
sl@0
  2366
    len = sizeof("end") - 1;
sl@0
  2367
    if (objPtr->internalRep.longValue != 0) {
sl@0
  2368
	buffer[len++] = '-';
sl@0
  2369
	len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
sl@0
  2370
    }
sl@0
  2371
    objPtr->bytes = ckalloc((unsigned) (len+1));
sl@0
  2372
    strcpy(objPtr->bytes, buffer);
sl@0
  2373
    objPtr->length = len;
sl@0
  2374
}
sl@0
  2375

sl@0
  2376
/*
sl@0
  2377
 *----------------------------------------------------------------------
sl@0
  2378
 *
sl@0
  2379
 * SetEndOffsetFromAny --
sl@0
  2380
 *
sl@0
  2381
 *	Look for a string of the form "end-offset" and convert it
sl@0
  2382
 *	to an internal representation holding the offset.
sl@0
  2383
 *
sl@0
  2384
 * Results:
sl@0
  2385
 *	Returns TCL_OK if ok, TCL_ERROR if the string was badly formed.
sl@0
  2386
 *
sl@0
  2387
 * Side effects:
sl@0
  2388
 *	If interp is not NULL, stores an error message in the
sl@0
  2389
 *	interpreter result.
sl@0
  2390
 *
sl@0
  2391
 *----------------------------------------------------------------------
sl@0
  2392
 */
sl@0
  2393
sl@0
  2394
static int
sl@0
  2395
SetEndOffsetFromAny(interp, objPtr)
sl@0
  2396
     Tcl_Interp* interp;	/* Tcl interpreter or NULL */
sl@0
  2397
     Tcl_Obj* objPtr;		/* Pointer to the object to parse */
sl@0
  2398
{
sl@0
  2399
    int offset;			/* Offset in the "end-offset" expression */
sl@0
  2400
    Tcl_ObjType* oldTypePtr = objPtr->typePtr;
sl@0
  2401
				/* Old internal rep type of the object */
sl@0
  2402
    register char* bytes;	/* String rep of the object */
sl@0
  2403
    int length;			/* Length of the object's string rep */
sl@0
  2404
sl@0
  2405
    /* If it's already the right type, we're fine. */
sl@0
  2406
sl@0
  2407
    if (objPtr->typePtr == &tclEndOffsetType) {
sl@0
  2408
	return TCL_OK;
sl@0
  2409
    }
sl@0
  2410
sl@0
  2411
    /* Check for a string rep of the right form. */
sl@0
  2412
sl@0
  2413
    bytes = Tcl_GetStringFromObj(objPtr, &length);
sl@0
  2414
    if ((*bytes != 'e') || (strncmp(bytes, "end",
sl@0
  2415
	    (size_t)((length > 3) ? 3 : length)) != 0)) {
sl@0
  2416
	if (interp != NULL) {
sl@0
  2417
	    Tcl_ResetResult(interp);
sl@0
  2418
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
  2419
				   "bad index \"", bytes,
sl@0
  2420
				   "\": must be end?-integer?",
sl@0
  2421
				   (char*) NULL);
sl@0
  2422
	}
sl@0
  2423
	return TCL_ERROR;
sl@0
  2424
    }
sl@0
  2425
sl@0
  2426
    /* Convert the string rep */
sl@0
  2427
sl@0
  2428
    if (length <= 3) {
sl@0
  2429
	offset = 0;
sl@0
  2430
    } else if ((length > 4) && (bytes[3] == '-')) {
sl@0
  2431
	/*
sl@0
  2432
	 * This is our limited string expression evaluator.  Pass everything
sl@0
  2433
	 * after "end-" to Tcl_GetInt, then reverse for offset.
sl@0
  2434
	 */
sl@0
  2435
	if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
sl@0
  2436
	    return TCL_ERROR;
sl@0
  2437
	}
sl@0
  2438
	offset = -offset;
sl@0
  2439
    } else {
sl@0
  2440
	/*
sl@0
  2441
	 * Conversion failed.  Report the error.
sl@0
  2442
	 */
sl@0
  2443
	if (interp != NULL) {
sl@0
  2444
	    Tcl_ResetResult(interp);
sl@0
  2445
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
sl@0
  2446
				   "bad index \"", bytes,
sl@0
  2447
				   "\": must be integer or end?-integer?",
sl@0
  2448
				   (char *) NULL);
sl@0
  2449
	}
sl@0
  2450
	return TCL_ERROR;
sl@0
  2451
    }
sl@0
  2452
sl@0
  2453
    /*
sl@0
  2454
     * The conversion succeeded. Free the old internal rep and set
sl@0
  2455
     * the new one.
sl@0
  2456
     */
sl@0
  2457
sl@0
  2458
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
sl@0
  2459
	oldTypePtr->freeIntRepProc(objPtr);
sl@0
  2460
    }
sl@0
  2461
    
sl@0
  2462
    objPtr->internalRep.longValue = offset;
sl@0
  2463
    objPtr->typePtr = &tclEndOffsetType;
sl@0
  2464
sl@0
  2465
    return TCL_OK;
sl@0
  2466
}    
sl@0
  2467

sl@0
  2468
/*
sl@0
  2469
 *----------------------------------------------------------------------
sl@0
  2470
 *
sl@0
  2471
 * TclCheckBadOctal --
sl@0
  2472
 *
sl@0
  2473
 *	This procedure checks for a bad octal value and appends a
sl@0
  2474
 *	meaningful error to the interp's result.
sl@0
  2475
 *
sl@0
  2476
 * Results:
sl@0
  2477
 *	1 if the argument was a bad octal, else 0.
sl@0
  2478
 *
sl@0
  2479
 * Side effects:
sl@0
  2480
 *	The interpreter's result is modified.
sl@0
  2481
 *
sl@0
  2482
 *----------------------------------------------------------------------
sl@0
  2483
 */
sl@0
  2484
sl@0
  2485
int
sl@0
  2486
TclCheckBadOctal(interp, value)
sl@0
  2487
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. 
sl@0
  2488
				 * If NULL, then no error message is left
sl@0
  2489
				 * after errors. */
sl@0
  2490
    CONST char *value;		/* String to check. */
sl@0
  2491
{
sl@0
  2492
    register CONST char *p = value;
sl@0
  2493
sl@0
  2494
    /*
sl@0
  2495
     * A frequent mistake is invalid octal values due to an unwanted
sl@0
  2496
     * leading zero. Try to generate a meaningful error message.
sl@0
  2497
     */
sl@0
  2498
sl@0
  2499
    while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
sl@0
  2500
	p++;
sl@0
  2501
    }
sl@0
  2502
    if (*p == '+' || *p == '-') {
sl@0
  2503
	p++;
sl@0
  2504
    }
sl@0
  2505
    if (*p == '0') {
sl@0
  2506
	while (isdigit(UCHAR(*p))) {	/* INTL: digit. */
sl@0
  2507
	    p++;
sl@0
  2508
	}
sl@0
  2509
	while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
sl@0
  2510
	    p++;
sl@0
  2511
	}
sl@0
  2512
	if (*p == '\0') {
sl@0
  2513
	    /* Reached end of string */
sl@0
  2514
	    if (interp != NULL) {
sl@0
  2515
		/*
sl@0
  2516
		 * Don't reset the result here because we want this result
sl@0
  2517
		 * to be added to an existing error message as extra info.
sl@0
  2518
		 */
sl@0
  2519
		Tcl_AppendResult(interp, " (looks like invalid octal number)",
sl@0
  2520
			(char *) NULL);
sl@0
  2521
	    }
sl@0
  2522
	    return 1;
sl@0
  2523
	}
sl@0
  2524
    }
sl@0
  2525
    return 0;
sl@0
  2526
}
sl@0
  2527

sl@0
  2528
/*
sl@0
  2529
 *----------------------------------------------------------------------
sl@0
  2530
 *
sl@0
  2531
 * Tcl_GetNameOfExecutable --
sl@0
  2532
 *
sl@0
  2533
 *	This procedure simply returns a pointer to the internal full
sl@0
  2534
 *	path name of the executable file as computed by
sl@0
  2535
 *	Tcl_FindExecutable.  This procedure call is the C API
sl@0
  2536
 *	equivalent to the "info nameofexecutable" command.
sl@0
  2537
 *
sl@0
  2538
 * Results:
sl@0
  2539
 *	A pointer to the internal string or NULL if the internal full
sl@0
  2540
 *	path name has not been computed or unknown.
sl@0
  2541
 *
sl@0
  2542
 * Side effects:
sl@0
  2543
 *	The object referenced by "objPtr" might be converted to an
sl@0
  2544
 *	integer object.
sl@0
  2545
 *
sl@0
  2546
 *----------------------------------------------------------------------
sl@0
  2547
 */
sl@0
  2548
sl@0
  2549
EXPORT_C CONST char *
sl@0
  2550
Tcl_GetNameOfExecutable()
sl@0
  2551
{
sl@0
  2552
    return tclExecutableName;
sl@0
  2553
}
sl@0
  2554

sl@0
  2555
/*
sl@0
  2556
 *----------------------------------------------------------------------
sl@0
  2557
 *
sl@0
  2558
 * TclpGetTime --
sl@0
  2559
 *
sl@0
  2560
 *	Deprecated synonym for Tcl_GetTime.
sl@0
  2561
 *
sl@0
  2562
 * Results:
sl@0
  2563
 *	None.
sl@0
  2564
 *
sl@0
  2565
 * Side effects:
sl@0
  2566
 *	Stores current time in the buffer designated by "timePtr"
sl@0
  2567
 *
sl@0
  2568
 * This procedure is provided for the benefit of extensions written
sl@0
  2569
 * before Tcl_GetTime was exported from the library.
sl@0
  2570
 *
sl@0
  2571
 *----------------------------------------------------------------------
sl@0
  2572
 */
sl@0
  2573
sl@0
  2574
void
sl@0
  2575
TclpGetTime(timePtr)
sl@0
  2576
    Tcl_Time* timePtr;
sl@0
  2577
{
sl@0
  2578
    Tcl_GetTime(timePtr);
sl@0
  2579
}