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 |
}
|