tclUtil.cGo to the documentation of this file.00001 /* 00002 * tclUtil.c -- 00003 * 00004 * This file contains utility functions that are used by many Tcl 00005 * commands. 00006 * 00007 * Copyright (c) 1987-1993 The Regents of the University of California. 00008 * Copyright (c) 1994-1998 Sun Microsystems, Inc. 00009 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. 00010 * 00011 * See the file "license.terms" for information on usage and redistribution of 00012 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00013 * 00014 * RCS: @(#) $Id: tclUtil.c,v 1.96 2007/12/13 15:23:20 dgp Exp $ 00015 */ 00016 00017 #include "tclInt.h" 00018 #include <float.h> 00019 #include <math.h> 00020 00021 /* 00022 * The absolute pathname of the executable in which this Tcl library is 00023 * running. 00024 */ 00025 00026 static ProcessGlobalValue executableName = { 00027 0, 0, NULL, NULL, NULL, NULL, NULL 00028 }; 00029 00030 /* 00031 * The following values are used in the flags returned by Tcl_ScanElement and 00032 * used by Tcl_ConvertElement. The values TCL_DONT_USE_BRACES and 00033 * TCL_DONT_QUOTE_HASH are defined in tcl.h; make sure neither value overlaps 00034 * with any of the values below. 00035 * 00036 * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in 00037 * braces (e.g. it contains unmatched braces, or 00038 * ends in a backslash character, or user just 00039 * doesn't want braces); handle all special 00040 * characters by adding backslashes. 00041 * USE_BRACES - 1 means the string contains a special 00042 * character that can be handled simply by 00043 * enclosing the entire argument in braces. 00044 * BRACES_UNMATCHED - 1 means that braces aren't properly matched in 00045 * the argument. 00046 * TCL_DONT_QUOTE_HASH - 1 means the caller insists that a leading hash 00047 * character ('#') should *not* be quoted. This 00048 * is appropriate when the caller can guarantee 00049 * the element is not the first element of a 00050 * list, so [eval] cannot mis-parse the element 00051 * as a comment. 00052 */ 00053 00054 #define USE_BRACES 2 00055 #define BRACES_UNMATCHED 4 00056 00057 /* 00058 * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to 00059 * access the precision to be used for double formatting. 00060 */ 00061 00062 static Tcl_ThreadDataKey precisionKey; 00063 00064 /* 00065 * Prototypes for functions defined later in this file. 00066 */ 00067 00068 static void ClearHash(Tcl_HashTable *tablePtr); 00069 static void FreeProcessGlobalValue(ClientData clientData); 00070 static void FreeThreadHash(ClientData clientData); 00071 static Tcl_HashTable * GetThreadHash(Tcl_ThreadDataKey *keyPtr); 00072 static int SetEndOffsetFromAny(Tcl_Interp* interp, 00073 Tcl_Obj* objPtr); 00074 static void UpdateStringOfEndOffset(Tcl_Obj* objPtr); 00075 00076 /* 00077 * The following is the Tcl object type definition for an object that 00078 * represents a list index in the form, "end-offset". It is used as a 00079 * performance optimization in TclGetIntForIndex. The internal rep is an 00080 * integer, so no memory management is required for it. 00081 */ 00082 00083 Tcl_ObjType tclEndOffsetType = { 00084 "end-offset", /* name */ 00085 NULL, /* freeIntRepProc */ 00086 NULL, /* dupIntRepProc */ 00087 UpdateStringOfEndOffset, /* updateStringProc */ 00088 SetEndOffsetFromAny 00089 }; 00090 00091 /* 00092 *---------------------------------------------------------------------- 00093 * 00094 * TclFindElement -- 00095 * 00096 * Given a pointer into a Tcl list, locate the first (or next) element in 00097 * the list. 00098 * 00099 * Results: 00100 * The return value is normally TCL_OK, which means that the element was 00101 * successfully located. If TCL_ERROR is returned it means that list 00102 * didn't have proper list structure; the interp's result contains a more 00103 * detailed error message. 00104 * 00105 * If TCL_OK is returned, then *elementPtr will be set to point to the 00106 * first element of list, and *nextPtr will be set to point to the 00107 * character just after any white space following the last character 00108 * that's part of the element. If this is the last argument in the list, 00109 * then *nextPtr will point just after the last character in the list 00110 * (i.e., at the character at list+listLength). If sizePtr is non-NULL, 00111 * *sizePtr is filled in with the number of characters in the element. If 00112 * the element is in braces, then *elementPtr will point to the character 00113 * after the opening brace and *sizePtr will not include either of the 00114 * braces. If there isn't an element in the list, *sizePtr will be zero, 00115 * and both *elementPtr and *termPtr will point just after the last 00116 * character in the list. Note: this function does NOT collapse backslash 00117 * sequences. 00118 * 00119 * Side effects: 00120 * None. 00121 * 00122 *---------------------------------------------------------------------- 00123 */ 00124 00125 int 00126 TclFindElement( 00127 Tcl_Interp *interp, /* Interpreter to use for error reporting. If 00128 * NULL, then no error message is left after 00129 * errors. */ 00130 CONST char *list, /* Points to the first byte of a string 00131 * containing a Tcl list with zero or more 00132 * elements (possibly in braces). */ 00133 int listLength, /* Number of bytes in the list's string. */ 00134 CONST char **elementPtr, /* Where to put address of first significant 00135 * character in first element of list. */ 00136 CONST char **nextPtr, /* Fill in with location of character just 00137 * after all white space following end of 00138 * argument (next arg or end of list). */ 00139 int *sizePtr, /* If non-zero, fill in with size of 00140 * element. */ 00141 int *bracePtr) /* If non-zero, fill in with non-zero/zero to 00142 * indicate that arg was/wasn't in braces. */ 00143 { 00144 CONST char *p = list; 00145 CONST char *elemStart; /* Points to first byte of first element. */ 00146 CONST char *limit; /* Points just after list's last byte. */ 00147 int openBraces = 0; /* Brace nesting level during parse. */ 00148 int inQuotes = 0; 00149 int size = 0; /* lint. */ 00150 int numChars; 00151 CONST char *p2; 00152 00153 /* 00154 * Skim off leading white space and check for an opening brace or quote. 00155 * We treat embedded NULLs in the list as bytes belonging to a list 00156 * element. 00157 */ 00158 00159 limit = (list + listLength); 00160 while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ 00161 p++; 00162 } 00163 if (p == limit) { /* no element found */ 00164 elemStart = limit; 00165 goto done; 00166 } 00167 00168 if (*p == '{') { 00169 openBraces = 1; 00170 p++; 00171 } else if (*p == '"') { 00172 inQuotes = 1; 00173 p++; 00174 } 00175 elemStart = p; 00176 if (bracePtr != 0) { 00177 *bracePtr = openBraces; 00178 } 00179 00180 /* 00181 * Find element's end (a space, close brace, or the end of the string). 00182 */ 00183 00184 while (p < limit) { 00185 switch (*p) { 00186 /* 00187 * Open brace: don't treat specially unless the element is in 00188 * braces. In this case, keep a nesting count. 00189 */ 00190 00191 case '{': 00192 if (openBraces != 0) { 00193 openBraces++; 00194 } 00195 break; 00196 00197 /* 00198 * Close brace: if element is in braces, keep nesting count and 00199 * quit when the last close brace is seen. 00200 */ 00201 00202 case '}': 00203 if (openBraces > 1) { 00204 openBraces--; 00205 } else if (openBraces == 1) { 00206 size = (p - elemStart); 00207 p++; 00208 if ((p >= limit) 00209 || isspace(UCHAR(*p))) { /* INTL: ISO space. */ 00210 goto done; 00211 } 00212 00213 /* 00214 * Garbage after the closing brace; return an error. 00215 */ 00216 00217 if (interp != NULL) { 00218 p2 = p; 00219 while ((p2 < limit) 00220 && (!isspace(UCHAR(*p2))) /* INTL: ISO space. */ 00221 && (p2 < p+20)) { 00222 p2++; 00223 } 00224 Tcl_SetObjResult(interp, Tcl_ObjPrintf( 00225 "list element in braces followed by \"%.*s\" " 00226 "instead of space", (int) (p2-p), p)); 00227 } 00228 return TCL_ERROR; 00229 } 00230 break; 00231 00232 /* 00233 * Backslash: skip over everything up to the end of the backslash 00234 * sequence. 00235 */ 00236 00237 case '\\': 00238 Tcl_UtfBackslash(p, &numChars, NULL); 00239 p += (numChars - 1); 00240 break; 00241 00242 /* 00243 * Space: ignore if element is in braces or quotes; otherwise 00244 * terminate element. 00245 */ 00246 00247 case ' ': 00248 case '\f': 00249 case '\n': 00250 case '\r': 00251 case '\t': 00252 case '\v': 00253 if ((openBraces == 0) && !inQuotes) { 00254 size = (p - elemStart); 00255 goto done; 00256 } 00257 break; 00258 00259 /* 00260 * Double-quote: if element is in quotes then terminate it. 00261 */ 00262 00263 case '"': 00264 if (inQuotes) { 00265 size = (p - elemStart); 00266 p++; 00267 if ((p >= limit) 00268 || isspace(UCHAR(*p))) { /* INTL: ISO space */ 00269 goto done; 00270 } 00271 00272 /* 00273 * Garbage after the closing quote; return an error. 00274 */ 00275 00276 if (interp != NULL) { 00277 p2 = p; 00278 while ((p2 < limit) 00279 && (!isspace(UCHAR(*p2))) /* INTL: ISO space */ 00280 && (p2 < p+20)) { 00281 p2++; 00282 } 00283 Tcl_SetObjResult(interp, Tcl_ObjPrintf( 00284 "list element in quotes followed by \"%.*s\" " 00285 "instead of space", (int) (p2-p), p)); 00286 } 00287 return TCL_ERROR; 00288 } 00289 break; 00290 } 00291 p++; 00292 } 00293 00294 /* 00295 * End of list: terminate element. 00296 */ 00297 00298 if (p == limit) { 00299 if (openBraces != 0) { 00300 if (interp != NULL) { 00301 Tcl_SetResult(interp, "unmatched open brace in list", 00302 TCL_STATIC); 00303 } 00304 return TCL_ERROR; 00305 } else if (inQuotes) { 00306 if (interp != NULL) { 00307 Tcl_SetResult(interp, "unmatched open quote in list", 00308 TCL_STATIC); 00309 } 00310 return TCL_ERROR; 00311 } 00312 size = (p - elemStart); 00313 } 00314 00315 done: 00316 while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */ 00317 p++; 00318 } 00319 *elementPtr = elemStart; 00320 *nextPtr = p; 00321 if (sizePtr != 0) { 00322 *sizePtr = size; 00323 } 00324 return TCL_OK; 00325 } 00326 00327 /* 00328 *---------------------------------------------------------------------- 00329 * 00330 * TclCopyAndCollapse -- 00331 * 00332 * Copy a string and eliminate any backslashes that aren't in braces. 00333 * 00334 * Results: 00335 * Count characters get copied from src to dst. Along the way, if 00336 * backslash sequences are found outside braces, the backslashes are 00337 * eliminated in the copy. After scanning count chars from source, a null 00338 * character is placed at the end of dst. Returns the number of 00339 * characters that got copied. 00340 * 00341 * Side effects: 00342 * None. 00343 * 00344 *---------------------------------------------------------------------- 00345 */ 00346 00347 int 00348 TclCopyAndCollapse( 00349 int count, /* Number of characters to copy from src. */ 00350 CONST char *src, /* Copy from here... */ 00351 char *dst) /* ... to here. */ 00352 { 00353 register char c; 00354 int numRead; 00355 int newCount = 0; 00356 int backslashCount; 00357 00358 for (c = *src; count > 0; src++, c = *src, count--) { 00359 if (c == '\\') { 00360 backslashCount = Tcl_UtfBackslash(src, &numRead, dst); 00361 dst += backslashCount; 00362 newCount += backslashCount; 00363 src += numRead-1; 00364 count -= numRead-1; 00365 } else { 00366 *dst = c; 00367 dst++; 00368 newCount++; 00369 } 00370 } 00371 *dst = 0; 00372 return newCount; 00373 } 00374 00375 /* 00376 *---------------------------------------------------------------------- 00377 * 00378 * Tcl_SplitList -- 00379 * 00380 * Splits a list up into its constituent fields. 00381 * 00382 * Results 00383 * The return value is normally TCL_OK, which means that the list was 00384 * successfully split up. If TCL_ERROR is returned, it means that "list" 00385 * didn't have proper list structure; the interp's result will contain a 00386 * more detailed error message. 00387 * 00388 * *argvPtr will be filled in with the address of an array whose elements 00389 * point to the elements of list, in order. *argcPtr will get filled in 00390 * with the number of valid elements in the array. A single block of 00391 * memory is dynamically allocated to hold both the argv array and a copy 00392 * of the list (with backslashes and braces removed in the standard way). 00393 * The caller must eventually free this memory by calling free() on 00394 * *argvPtr. Note: *argvPtr and *argcPtr are only modified if the 00395 * function returns normally. 00396 * 00397 * Side effects: 00398 * Memory is allocated. 00399 * 00400 *---------------------------------------------------------------------- 00401 */ 00402 00403 int 00404 Tcl_SplitList( 00405 Tcl_Interp *interp, /* Interpreter to use for error reporting. If 00406 * NULL, no error message is left. */ 00407 CONST char *list, /* Pointer to string with list structure. */ 00408 int *argcPtr, /* Pointer to location to fill in with the 00409 * number of elements in the list. */ 00410 CONST char ***argvPtr) /* Pointer to place to store pointer to array 00411 * of pointers to list elements. */ 00412 { 00413 CONST char **argv, *l, *element; 00414 char *p; 00415 int length, size, i, result, elSize, brace; 00416 00417 /* 00418 * Figure out how much space to allocate. There must be enough space for 00419 * both the array of pointers and also for a copy of the list. To estimate 00420 * the number of pointers needed, count the number of space characters in 00421 * the list. 00422 */ 00423 00424 for (size = 2, l = list; *l != 0; l++) { 00425 if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ 00426 size++; 00427 00428 /* 00429 * Consecutive space can only count as a single list delimiter. 00430 */ 00431 00432 while (1) { 00433 char next = *(l + 1); 00434 00435 if (next == '\0') { 00436 break; 00437 } 00438 ++l; 00439 if (isspace(UCHAR(next))) { /* INTL: ISO space. */ 00440 continue; 00441 } 00442 break; 00443 } 00444 } 00445 } 00446 length = l - list; 00447 argv = (CONST char **) ckalloc((unsigned) 00448 ((size * sizeof(char *)) + length + 1)); 00449 for (i = 0, p = ((char *) argv) + size*sizeof(char *); 00450 *list != 0; i++) { 00451 CONST char *prevList = list; 00452 00453 result = TclFindElement(interp, list, length, &element, &list, 00454 &elSize, &brace); 00455 length -= (list - prevList); 00456 if (result != TCL_OK) { 00457 ckfree((char *) argv); 00458 return result; 00459 } 00460 if (*element == 0) { 00461 break; 00462 } 00463 if (i >= size) { 00464 ckfree((char *) argv); 00465 if (interp != NULL) { 00466 Tcl_SetResult(interp, "internal error in Tcl_SplitList", 00467 TCL_STATIC); 00468 } 00469 return TCL_ERROR; 00470 } 00471 argv[i] = p; 00472 if (brace) { 00473 memcpy(p, element, (size_t) elSize); 00474 p += elSize; 00475 *p = 0; 00476 p++; 00477 } else { 00478 TclCopyAndCollapse(elSize, element, p); 00479 p += elSize+1; 00480 } 00481 } 00482 00483 argv[i] = NULL; 00484 *argvPtr = argv; 00485 *argcPtr = i; 00486 return TCL_OK; 00487 } 00488 00489 /* 00490 *---------------------------------------------------------------------- 00491 * 00492 * TclMarkList -- 00493 * 00494 * Marks the locations within a string where list elements start and 00495 * computes where they end. 00496 * 00497 * Results 00498 * The return value is normally TCL_OK, which means that the list was 00499 * successfully split up. If TCL_ERROR is returned, it means that "list" 00500 * didn't have proper list structure; the interp's result will contain a 00501 * more detailed error message. 00502 * 00503 * *argvPtr will be filled in with the address of an array whose elements 00504 * point to the places where the elements of list start, in order. 00505 * *argcPtr will get filled in with the number of valid elements in the 00506 * array. *argszPtr will get filled in with the address of an array whose 00507 * elements are the lengths of the elements of the list, in order. 00508 * Note: *argvPtr, *argcPtr and *argszPtr are only modified if the 00509 * function returns normally. 00510 * 00511 * Side effects: 00512 * Memory is allocated. 00513 * 00514 *---------------------------------------------------------------------- 00515 */ 00516 00517 int 00518 TclMarkList( 00519 Tcl_Interp *interp, /* Interpreter to use for error reporting. If 00520 * NULL, no error message is left. */ 00521 CONST char *list, /* Pointer to string with list structure. */ 00522 CONST char *end, /* Pointer to first char after the list. */ 00523 int *argcPtr, /* Pointer to location to fill in with the 00524 * number of elements in the list. */ 00525 CONST int **argszPtr, /* Pointer to place to store length of list 00526 * elements. */ 00527 CONST char ***argvPtr) /* Pointer to place to store pointer to array 00528 * of pointers to list elements. */ 00529 { 00530 CONST char **argv, *l, *element; 00531 int *argn, length, size, i, result, elSize, brace; 00532 00533 /* 00534 * Figure out how much space to allocate. There must be enough space for 00535 * the array of pointers and lengths. To estimate the number of pointers 00536 * needed, count the number of whitespace characters in the list. 00537 */ 00538 00539 for (size=2, l=list ; l!=end ; l++) { 00540 if (isspace(UCHAR(*l))) { /* INTL: ISO space. */ 00541 size++; 00542 00543 /* 00544 * Consecutive space can only count as a single list delimiter. 00545 */ 00546 00547 while (1) { 00548 char next = *(l + 1); 00549 00550 if ((l+1) == end) { 00551 break; 00552 } 00553 ++l; 00554 if (isspace(UCHAR(next))) { /* INTL: ISO space. */ 00555 continue; 00556 } 00557 break; 00558 } 00559 } 00560 } 00561 length = l - list; 00562 argv = (CONST char **) ckalloc((unsigned) size * sizeof(char *)); 00563 argn = (int *) ckalloc((unsigned) size * sizeof(int *)); 00564 00565 for (i = 0; list != end; i++) { 00566 CONST char *prevList = list; 00567 00568 result = TclFindElement(interp, list, length, &element, &list, 00569 &elSize, &brace); 00570 length -= (list - prevList); 00571 if (result != TCL_OK) { 00572 ckfree((char *) argv); 00573 ckfree((char *) argn); 00574 return result; 00575 } 00576 if (*element == 0) { 00577 break; 00578 } 00579 if (i >= size) { 00580 ckfree((char *) argv); 00581 ckfree((char *) argn); 00582 if (interp != NULL) { 00583 Tcl_SetResult(interp, "internal error in TclMarkList", 00584 TCL_STATIC); 00585 } 00586 return TCL_ERROR; 00587 } 00588 argv[i] = element; 00589 argn[i] = elSize; 00590 } 00591 00592 argv[i] = NULL; 00593 argn[i] = 0; 00594 *argvPtr = argv; 00595 *argszPtr = argn; 00596 *argcPtr = i; 00597 return TCL_OK; 00598 } 00599 00600 /* 00601 *---------------------------------------------------------------------- 00602 * 00603 * Tcl_ScanElement -- 00604 * 00605 * This function is a companion function to Tcl_ConvertElement. It scans 00606 * a string to see what needs to be done to it (e.g. add backslashes or 00607 * enclosing braces) to make the string into a valid Tcl list element. 00608 * 00609 * Results: 00610 * The return value is an overestimate of the number of characters that 00611 * will be needed by Tcl_ConvertElement to produce a valid list element 00612 * from string. The word at *flagPtr is filled in with a value needed by 00613 * Tcl_ConvertElement when doing the actual conversion. 00614 * 00615 * Side effects: 00616 * None. 00617 * 00618 *---------------------------------------------------------------------- 00619 */ 00620 00621 int 00622 Tcl_ScanElement( 00623 register CONST char *string,/* String to convert to list element. */ 00624 register int *flagPtr) /* Where to store information to guide 00625 * Tcl_ConvertCountedElement. */ 00626 { 00627 return Tcl_ScanCountedElement(string, -1, flagPtr); 00628 } 00629 00630 /* 00631 *---------------------------------------------------------------------- 00632 * 00633 * Tcl_ScanCountedElement -- 00634 * 00635 * This function is a companion function to Tcl_ConvertCountedElement. It 00636 * scans a string to see what needs to be done to it (e.g. add 00637 * backslashes or enclosing braces) to make the string into a valid Tcl 00638 * list element. If length is -1, then the string is scanned up to the 00639 * first null byte. 00640 * 00641 * Results: 00642 * The return value is an overestimate of the number of characters that 00643 * will be needed by Tcl_ConvertCountedElement to produce a valid list 00644 * element from string. The word at *flagPtr is filled in with a value 00645 * needed by Tcl_ConvertCountedElement when doing the actual conversion. 00646 * 00647 * Side effects: 00648 * None. 00649 * 00650 *---------------------------------------------------------------------- 00651 */ 00652 00653 int 00654 Tcl_ScanCountedElement( 00655 CONST char *string, /* String to convert to Tcl list element. */ 00656 int length, /* Number of bytes in string, or -1. */ 00657 int *flagPtr) /* Where to store information to guide 00658 * Tcl_ConvertElement. */ 00659 { 00660 int flags, nestingLevel; 00661 register CONST char *p, *lastChar; 00662 00663 /* 00664 * This function and Tcl_ConvertElement together do two things: 00665 * 00666 * 1. They produce a proper list, one that will yield back the argument 00667 * strings when evaluated or when disassembled with Tcl_SplitList. This 00668 * is the most important thing. 00669 * 00670 * 2. They try to produce legible output, which means minimizing the use 00671 * of backslashes (using braces instead). However, there are some 00672 * situations where backslashes must be used (e.g. an element like 00673 * "{abc": the leading brace will have to be backslashed. For each 00674 * element, one of three things must be done: 00675 * 00676 * (a) Use the element as-is (it doesn't contain any special 00677 * characters). This is the most desirable option. 00678 * 00679 * (b) Enclose the element in braces, but leave the contents alone. 00680 * This happens if the element contains embedded space, or if it 00681 * contains characters with special interpretation ($, [, ;, or \), 00682 * or if it starts with a brace or double-quote, or if there are no 00683 * characters in the element. 00684 * 00685 * (c) Don't enclose the element in braces, but add backslashes to 00686 * prevent special interpretation of special characters. This is a 00687 * last resort used when the argument would normally fall under 00688 * case (b) but contains unmatched braces. It also occurs if the 00689 * last character of the argument is a backslash or if the element 00690 * contains a backslash followed by newline. 00691 * 00692 * The function figures out how many bytes will be needed to store the 00693 * result (actually, it overestimates). It also collects information about 00694 * the element in the form of a flags word. 00695 * 00696 * Note: list elements produced by this function and 00697 * Tcl_ConvertCountedElement must have the property that they can be 00698 * enclosing in curly braces to make sub-lists. This means, for example, 00699 * that we must not leave unmatched curly braces in the resulting list 00700 * element. This property is necessary in order for functions like 00701 * Tcl_DStringStartSublist to work. 00702 */ 00703 00704 nestingLevel = 0; 00705 flags = 0; 00706 if (string == NULL) { 00707 string = ""; 00708 } 00709 if (length == -1) { 00710 length = strlen(string); 00711 } 00712 lastChar = string + length; 00713 p = string; 00714 if ((p == lastChar) || (*p == '{') || (*p == '"')) { 00715 flags |= USE_BRACES; 00716 } 00717 for (; p < lastChar; p++) { 00718 switch (*p) { 00719 case '{': 00720 nestingLevel++; 00721 break; 00722 case '}': 00723 nestingLevel--; 00724 if (nestingLevel < 0) { 00725 flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED; 00726 } 00727 break; 00728 case '[': 00729 case '$': 00730 case ';': 00731 case ' ': 00732 case '\f': 00733 case '\n': 00734 case '\r': 00735 case '\t': 00736 case '\v': 00737 flags |= USE_BRACES; 00738 break; 00739 case '\\': 00740 if ((p+1 == lastChar) || (p[1] == '\n')) { 00741 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; 00742 } else { 00743 int size; 00744 00745 Tcl_UtfBackslash(p, &size, NULL); 00746 p += size-1; 00747 flags |= USE_BRACES; 00748 } 00749 break; 00750 } 00751 } 00752 if (nestingLevel != 0) { 00753 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED; 00754 } 00755 *flagPtr = flags; 00756 00757 /* 00758 * Allow enough space to backslash every character plus leave two spaces 00759 * for braces. 00760 */ 00761 00762 return 2*(p-string) + 2; 00763 } 00764 00765 /* 00766 *---------------------------------------------------------------------- 00767 * 00768 * Tcl_ConvertElement -- 00769 * 00770 * This is a companion function to Tcl_ScanElement. Given the information 00771 * produced by Tcl_ScanElement, this function converts a string to a list 00772 * element equal to that string. 00773 * 00774 * Results: 00775 * Information is copied to *dst in the form of a list element identical 00776 * to src (i.e. if Tcl_SplitList is applied to dst it will produce a 00777 * string identical to src). The return value is a count of the number of 00778 * characters copied (not including the terminating NULL character). 00779 * 00780 * Side effects: 00781 * None. 00782 * 00783 *---------------------------------------------------------------------- 00784 */ 00785 00786 int 00787 Tcl_ConvertElement( 00788 register CONST char *src, /* Source information for list element. */ 00789 register char *dst, /* Place to put list-ified element. */ 00790 register int flags) /* Flags produced by Tcl_ScanElement. */ 00791 { 00792 return Tcl_ConvertCountedElement(src, -1, dst, flags); 00793 } 00794 00795 /* 00796 *---------------------------------------------------------------------- 00797 * 00798 * Tcl_ConvertCountedElement -- 00799 * 00800 * This is a companion function to Tcl_ScanCountedElement. Given the 00801 * information produced by Tcl_ScanCountedElement, this function converts 00802 * a string to a list element equal to that string. 00803 * 00804 * Results: 00805 * Information is copied to *dst in the form of a list element identical 00806 * to src (i.e. if Tcl_SplitList is applied to dst it will produce a 00807 * string identical to src). The return value is a count of the number of 00808 * characters copied (not including the terminating NULL character). 00809 * 00810 * Side effects: 00811 * None. 00812 * 00813 *---------------------------------------------------------------------- 00814 */ 00815 00816 int 00817 Tcl_ConvertCountedElement( 00818 register CONST char *src, /* Source information for list element. */ 00819 int length, /* Number of bytes in src, or -1. */ 00820 char *dst, /* Place to put list-ified element. */ 00821 int flags) /* Flags produced by Tcl_ScanElement. */ 00822 { 00823 register char *p = dst; 00824 register CONST char *lastChar; 00825 00826 /* 00827 * See the comment block at the beginning of the Tcl_ScanElement code for 00828 * details of how this works. 00829 */ 00830 00831 if (src && length == -1) { 00832 length = strlen(src); 00833 } 00834 if ((src == NULL) || (length == 0)) { 00835 p[0] = '{'; 00836 p[1] = '}'; 00837 p[2] = 0; 00838 return 2; 00839 } 00840 lastChar = src + length; 00841 if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { 00842 flags |= USE_BRACES; 00843 } 00844 if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) { 00845 *p = '{'; 00846 p++; 00847 for (; src != lastChar; src++, p++) { 00848 *p = *src; 00849 } 00850 *p = '}'; 00851 p++; 00852 } else { 00853 if (*src == '{') { 00854 /* 00855 * Can't have a leading brace unless the whole element is enclosed 00856 * in braces. Add a backslash before the brace. Furthermore, this 00857 * may destroy the balance between open and close braces, so set 00858 * BRACES_UNMATCHED. 00859 */ 00860 00861 p[0] = '\\'; 00862 p[1] = '{'; 00863 p += 2; 00864 src++; 00865 flags |= BRACES_UNMATCHED; 00866 } else if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { 00867 /* 00868 * Leading '#' could be seen by [eval] as the start of a comment, 00869 * if on the first element of a list, so quote it. 00870 */ 00871 00872 p[0] = '\\'; 00873 p[1] = '#'; 00874 p += 2; 00875 src++; 00876 } 00877 for (; src != lastChar; src++) { 00878 switch (*src) { 00879 case ']': 00880 case '[': 00881 case '$': 00882 case ';': 00883 case ' ': 00884 case '\\': 00885 case '"': 00886 *p = '\\'; 00887 p++; 00888 break; 00889 case '{': 00890 case '}': 00891 /* 00892 * It may not seem necessary to backslash braces, but it is. 00893 * The reason for this is that the resulting list element may 00894 * actually be an element of a sub-list enclosed in braces 00895 * (e.g. if Tcl_DStringStartSublist has been invoked), so 00896 * there may be a brace mismatch if the braces aren't 00897 * backslashed. 00898 */ 00899 00900 if (flags & BRACES_UNMATCHED) { 00901 *p = '\\'; 00902 p++; 00903 } 00904 break; 00905 case '\f': 00906 *p = '\\'; 00907 p++; 00908 *p = 'f'; 00909 p++; 00910 continue; 00911 case '\n': 00912 *p = '\\'; 00913 p++; 00914 *p = 'n'; 00915 p++; 00916 continue; 00917 case '\r': 00918 *p = '\\'; 00919 p++; 00920 *p = 'r'; 00921 p++; 00922 continue; 00923 case '\t': 00924 *p = '\\'; 00925 p++; 00926 *p = 't'; 00927 p++; 00928 continue; 00929 case '\v': 00930 *p = '\\'; 00931 p++; 00932 *p = 'v'; 00933 p++; 00934 continue; 00935 } 00936 *p = *src; 00937 p++; 00938 } 00939 } 00940 *p = '\0'; 00941 return p-dst; 00942 } 00943 00944 /* 00945 *---------------------------------------------------------------------- 00946 * 00947 * Tcl_Merge -- 00948 * 00949 * Given a collection of strings, merge them together into a single 00950 * string that has proper Tcl list structured (i.e. Tcl_SplitList may be 00951 * used to retrieve strings equal to the original elements, and Tcl_Eval 00952 * will parse the string back into its original elements). 00953 * 00954 * Results: 00955 * The return value is the address of a dynamically-allocated string 00956 * containing the merged list. 00957 * 00958 * Side effects: 00959 * None. 00960 * 00961 *---------------------------------------------------------------------- 00962 */ 00963 00964 char * 00965 Tcl_Merge( 00966 int argc, /* How many strings to merge. */ 00967 CONST char * CONST *argv) /* Array of string values. */ 00968 { 00969 # define LOCAL_SIZE 20 00970 int localFlags[LOCAL_SIZE], *flagPtr; 00971 int numChars; 00972 char *result; 00973 char *dst; 00974 int i; 00975 00976 /* 00977 * Pass 1: estimate space, gather flags. 00978 */ 00979 00980 if (argc <= LOCAL_SIZE) { 00981 flagPtr = localFlags; 00982 } else { 00983 flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int)); 00984 } 00985 numChars = 1; 00986 for (i = 0; i < argc; i++) { 00987 numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1; 00988 } 00989 00990 /* 00991 * Pass two: copy into the result area. 00992 */ 00993 00994 result = (char *) ckalloc((unsigned) numChars); 00995 dst = result; 00996 for (i = 0; i < argc; i++) { 00997 numChars = Tcl_ConvertElement(argv[i], dst, 00998 flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH)); 00999 dst += numChars; 01000 *dst = ' '; 01001 dst++; 01002 } 01003 if (dst == result) { 01004 *dst = 0; 01005 } else { 01006 dst[-1] = 0; 01007 } 01008 01009 if (flagPtr != localFlags) { 01010 ckfree((char *) flagPtr); 01011 } 01012 return result; 01013 } 01014 01015 /* 01016 *---------------------------------------------------------------------- 01017 * 01018 * Tcl_Backslash -- 01019 * 01020 * Figure out how to handle a backslash sequence. 01021 * 01022 * Results: 01023 * The return value is the character that should be substituted in place 01024 * of the backslash sequence that starts at src. If readPtr isn't NULL 01025 * then it is filled in with a count of the number of characters in the 01026 * backslash sequence. 01027 * 01028 * Side effects: 01029 * None. 01030 * 01031 *---------------------------------------------------------------------- 01032 */ 01033 01034 char 01035 Tcl_Backslash( 01036 CONST char *src, /* Points to the backslash character of a 01037 * backslash sequence. */ 01038 int *readPtr) /* Fill in with number of characters read from 01039 * src, unless NULL. */ 01040 { 01041 char buf[TCL_UTF_MAX]; 01042 Tcl_UniChar ch; 01043 01044 Tcl_UtfBackslash(src, readPtr, buf); 01045 TclUtfToUniChar(buf, &ch); 01046 return (char) ch; 01047 } 01048 01049 /* 01050 *---------------------------------------------------------------------- 01051 * 01052 * Tcl_Concat -- 01053 * 01054 * Concatenate a set of strings into a single large string. 01055 * 01056 * Results: 01057 * The return value is dynamically-allocated string containing a 01058 * concatenation of all the strings in argv, with spaces between the 01059 * original argv elements. 01060 * 01061 * Side effects: 01062 * Memory is allocated for the result; the caller is responsible for 01063 * freeing the memory. 01064 * 01065 *---------------------------------------------------------------------- 01066 */ 01067 01068 char * 01069 Tcl_Concat( 01070 int argc, /* Number of strings to concatenate. */ 01071 CONST char * CONST *argv) /* Array of strings to concatenate. */ 01072 { 01073 int totalSize, i; 01074 char *p; 01075 char *result; 01076 01077 for (totalSize = 1, i = 0; i < argc; i++) { 01078 totalSize += strlen(argv[i]) + 1; 01079 } 01080 result = (char *) ckalloc((unsigned) totalSize); 01081 if (argc == 0) { 01082 *result = '\0'; 01083 return result; 01084 } 01085 for (p = result, i = 0; i < argc; i++) { 01086 CONST char *element; 01087 int length; 01088 01089 /* 01090 * Clip white space off the front and back of the string to generate a 01091 * neater result, and ignore any empty elements. 01092 */ 01093 01094 element = argv[i]; 01095 while (isspace(UCHAR(*element))) { /* INTL: ISO space. */ 01096 element++; 01097 } 01098 for (length = strlen(element); 01099 (length > 0) 01100 && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */ 01101 && ((length < 2) || (element[length-2] != '\\')); 01102 length--) { 01103 /* Null loop body. */ 01104 } 01105 if (length == 0) { 01106 continue; 01107 } 01108 memcpy(p, element, (size_t) length); 01109 p += length; 01110 *p = ' '; 01111 p++; 01112 } 01113 if (p != result) { 01114 p[-1] = 0; 01115 } else { 01116 *p = 0; 01117 } 01118 return result; 01119 } 01120 01121 /* 01122 *---------------------------------------------------------------------- 01123 * 01124 * Tcl_ConcatObj -- 01125 * 01126 * Concatenate the strings from a set of objects into a single string 01127 * object with spaces between the original strings. 01128 * 01129 * Results: 01130 * The return value is a new string object containing a concatenation of 01131 * the strings in objv. Its ref count is zero. 01132 * 01133 * Side effects: 01134 * A new object is created. 01135 * 01136 *---------------------------------------------------------------------- 01137 */ 01138 01139 Tcl_Obj * 01140 Tcl_ConcatObj( 01141 int objc, /* Number of objects to concatenate. */ 01142 Tcl_Obj *CONST objv[]) /* Array of objects to concatenate. */ 01143 { 01144 int allocSize, finalSize, length, elemLength, i; 01145 char *p; 01146 char *element; 01147 char *concatStr; 01148 Tcl_Obj *objPtr, *resPtr; 01149 01150 /* 01151 * Check first to see if all the items are of list type or empty. If so, 01152 * we will concat them together as lists, and return a list object. This 01153 * is only valid when the lists have no current string representation, 01154 * since we don't know what the original type was. An original string rep 01155 * may have lost some whitespace info when converted which could be 01156 * important. 01157 */ 01158 01159 for (i = 0; i < objc; i++) { 01160 List *listRepPtr; 01161 01162 objPtr = objv[i]; 01163 if (objPtr->typePtr != &tclListType) { 01164 TclGetString(objPtr); 01165 if (objPtr->length) { 01166 break; 01167 } else { 01168 continue; 01169 } 01170 } 01171 listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1; 01172 if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) { 01173 break; 01174 } 01175 } 01176 if (i == objc) { 01177 Tcl_Obj **listv; 01178 int listc; 01179 01180 resPtr = NULL; 01181 for (i = 0; i < objc; i++) { 01182 /* 01183 * Tcl_ListObjAppendList could be used here, but this saves us a 01184 * bit of type checking (since we've already done it). Use of 01185 * INT_MAX tells us to always put the new stuff on the end. It 01186 * will be set right in Tcl_ListObjReplace. 01187 * Note that all objs at this point are either lists or have an 01188 * empty string rep. 01189 */ 01190 01191 objPtr = objv[i]; 01192 if (objPtr->bytes && !objPtr->length) { 01193 continue; 01194 } 01195 TclListObjGetElements(NULL, objPtr, &listc, &listv); 01196 if (listc) { 01197 if (resPtr) { 01198 Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv); 01199 } else { 01200 if (Tcl_IsShared(objPtr)) { 01201 resPtr = TclListObjCopy(NULL, objPtr); 01202 } else { 01203 resPtr = objPtr; 01204 } 01205 } 01206 } 01207 } 01208 if (!resPtr) { 01209 resPtr = Tcl_NewObj(); 01210 } 01211 return resPtr; 01212 } 01213 01214 /* 01215 * Something cannot be determined to be safe, so build the concatenation 01216 * the slow way, using the string representations. 01217 */ 01218 01219 allocSize = 0; 01220 for (i = 0; i < objc; i++) { 01221 objPtr = objv[i]; 01222 element = TclGetStringFromObj(objPtr, &length); 01223 if ((element != NULL) && (length > 0)) { 01224 allocSize += (length + 1); 01225 } 01226 } 01227 if (allocSize == 0) { 01228 allocSize = 1; /* enough for the NULL byte at end */ 01229 } 01230 01231 /* 01232 * Allocate storage for the concatenated result. Note that allocSize is 01233 * one more than the total number of characters, and so includes room for 01234 * the terminating NULL byte. 01235 */ 01236 01237 concatStr = ckalloc((unsigned) allocSize); 01238 01239 /* 01240 * Now concatenate the elements. Clip white space off the front and back 01241 * to generate a neater result, and ignore any empty elements. Also put a 01242 * null byte at the end. 01243 */ 01244 01245 finalSize = 0; 01246 if (objc == 0) { 01247 *concatStr = '\0'; 01248 } else { 01249 p = concatStr; 01250 for (i = 0; i < objc; i++) { 01251 objPtr = objv[i]; 01252 element = TclGetStringFromObj(objPtr, &elemLength); 01253 while ((elemLength > 0) && (UCHAR(*element) < 127) 01254 && isspace(UCHAR(*element))) { /* INTL: ISO C space. */ 01255 element++; 01256 elemLength--; 01257 } 01258 01259 /* 01260 * Trim trailing white space. But, be careful not to trim a space 01261 * character if it is preceded by a backslash: in this case it 01262 * could be significant. 01263 */ 01264 01265 while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127) 01266 && isspace(UCHAR(element[elemLength-1])) 01267 /* INTL: ISO C space. */ 01268 && ((elemLength < 2) || (element[elemLength-2] != '\\'))) { 01269 elemLength--; 01270 } 01271 if (elemLength == 0) { 01272 continue; /* nothing left of this element */ 01273 } 01274 memcpy(p, element, (size_t) elemLength); 01275 p += elemLength; 01276 *p = ' '; 01277 p++; 01278 finalSize += (elemLength + 1); 01279 } 01280 if (p != concatStr) { 01281 p[-1] = 0; 01282 finalSize -= 1; /* we overwrote the final ' ' */ 01283 } else { 01284 *p = 0; 01285 } 01286 } 01287 01288 TclNewObj(objPtr); 01289 objPtr->bytes = concatStr; 01290 objPtr->length = finalSize; 01291 return objPtr; 01292 } 01293 01294 /* 01295 *---------------------------------------------------------------------- 01296 * 01297 * Tcl_StringMatch -- 01298 * 01299 * See if a particular string matches a particular pattern. 01300 * 01301 * Results: 01302 * The return value is 1 if string matches pattern, and 0 otherwise. The 01303 * matching operation permits the following special characters in the 01304 * pattern: *?\[] (see the manual entry for details on what these mean). 01305 * 01306 * Side effects: 01307 * None. 01308 * 01309 *---------------------------------------------------------------------- 01310 */ 01311 01312 int 01313 Tcl_StringMatch( 01314 CONST char *str, /* String. */ 01315 CONST char *pattern) /* Pattern, which may contain special 01316 * characters. */ 01317 { 01318 return Tcl_StringCaseMatch(str, pattern, 0); 01319 } 01320 01321 /* 01322 *---------------------------------------------------------------------- 01323 * 01324 * Tcl_StringCaseMatch -- 01325 * 01326 * See if a particular string matches a particular pattern. Allows case 01327 * insensitivity. 01328 * 01329 * Results: 01330 * The return value is 1 if string matches pattern, and 0 otherwise. The 01331 * matching operation permits the following special characters in the 01332 * pattern: *?\[] (see the manual entry for details on what these mean). 01333 * 01334 * Side effects: 01335 * None. 01336 * 01337 *---------------------------------------------------------------------- 01338 */ 01339 01340 int 01341 Tcl_StringCaseMatch( 01342 CONST char *str, /* String. */ 01343 CONST char *pattern, /* Pattern, which may contain special 01344 * characters. */ 01345 int nocase) /* 0 for case sensitive, 1 for insensitive */ 01346 { 01347 int p, charLen; 01348 CONST char *pstart = pattern; 01349 Tcl_UniChar ch1, ch2; 01350 01351 while (1) { 01352 p = *pattern; 01353 01354 /* 01355 * See if we're at the end of both the pattern and the string. If so, 01356 * we succeeded. If we're at the end of the pattern but not at the end 01357 * of the string, we failed. 01358 */ 01359 01360 if (p == '\0') { 01361 return (*str == '\0'); 01362 } 01363 if ((*str == '\0') && (p != '*')) { 01364 return 0; 01365 } 01366 01367 /* 01368 * Check for a "*" as the next pattern character. It matches any 01369 * substring. We handle this by calling ourselves recursively for each 01370 * postfix of string, until either we match or we reach the end of the 01371 * string. 01372 */ 01373 01374 if (p == '*') { 01375 /* 01376 * Skip all successive *'s in the pattern 01377 */ 01378 01379 while (*(++pattern) == '*') {} 01380 p = *pattern; 01381 if (p == '\0') { 01382 return 1; 01383 } 01384 01385 /* 01386 * This is a special case optimization for single-byte utf. 01387 */ 01388 01389 if (UCHAR(*pattern) < 0x80) { 01390 ch2 = (Tcl_UniChar) 01391 (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); 01392 } else { 01393 Tcl_UtfToUniChar(pattern, &ch2); 01394 if (nocase) { 01395 ch2 = Tcl_UniCharToLower(ch2); 01396 } 01397 } 01398 01399 while (1) { 01400 /* 01401 * Optimization for matching - cruise through the string 01402 * quickly if the next char in the pattern isn't a special 01403 * character 01404 */ 01405 01406 if ((p != '[') && (p != '?') && (p != '\\')) { 01407 if (nocase) { 01408 while (*str) { 01409 charLen = TclUtfToUniChar(str, &ch1); 01410 if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) { 01411 break; 01412 } 01413 str += charLen; 01414 } 01415 } else { 01416 /* 01417 * There's no point in trying to make this code 01418 * shorter, as the number of bytes you want to compare 01419 * each time is non-constant. 01420 */ 01421 01422 while (*str) { 01423 charLen = TclUtfToUniChar(str, &ch1); 01424 if (ch2 == ch1) { 01425 break; 01426 } 01427 str += charLen; 01428 } 01429 } 01430 } 01431 if (Tcl_StringCaseMatch(str, pattern, nocase)) { 01432 return 1; 01433 } 01434 if (*str == '\0') { 01435 return 0; 01436 } 01437 str += TclUtfToUniChar(str, &ch1); 01438 } 01439 } 01440 01441 /* 01442 * Check for a "?" as the next pattern character. It matches any 01443 * single character. 01444 */ 01445 01446 if (p == '?') { 01447 pattern++; 01448 str += TclUtfToUniChar(str, &ch1); 01449 continue; 01450 } 01451 01452 /* 01453 * Check for a "[" as the next pattern character. It is followed by a 01454 * list of characters that are acceptable, or by a range (two 01455 * characters separated by "-"). 01456 */ 01457 01458 if (p == '[') { 01459 Tcl_UniChar startChar, endChar; 01460 01461 pattern++; 01462 if (UCHAR(*str) < 0x80) { 01463 ch1 = (Tcl_UniChar) 01464 (nocase ? tolower(UCHAR(*str)) : UCHAR(*str)); 01465 str++; 01466 } else { 01467 str += Tcl_UtfToUniChar(str, &ch1); 01468 if (nocase) { 01469 ch1 = Tcl_UniCharToLower(ch1); 01470 } 01471 } 01472 while (1) { 01473 if ((*pattern == ']') || (*pattern == '\0')) { 01474 return 0; 01475 } 01476 if (UCHAR(*pattern) < 0x80) { 01477 startChar = (Tcl_UniChar) (nocase 01478 ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); 01479 pattern++; 01480 } else { 01481 pattern += Tcl_UtfToUniChar(pattern, &startChar); 01482 if (nocase) { 01483 startChar = Tcl_UniCharToLower(startChar); 01484 } 01485 } 01486 if (*pattern == '-') { 01487 pattern++; 01488 if (*pattern == '\0') { 01489 return 0; 01490 } 01491 if (UCHAR(*pattern) < 0x80) { 01492 endChar = (Tcl_UniChar) (nocase 01493 ? tolower(UCHAR(*pattern)) : UCHAR(*pattern)); 01494 pattern++; 01495 } else { 01496 pattern += Tcl_UtfToUniChar(pattern, &endChar); 01497 if (nocase) { 01498 endChar = Tcl_UniCharToLower(endChar); 01499 } 01500 } 01501 if (((startChar <= ch1) && (ch1 <= endChar)) 01502 || ((endChar <= ch1) && (ch1 <= startChar))) { 01503 /* 01504 * Matches ranges of form [a-z] or [z-a]. 01505 */ 01506 01507 break; 01508 } 01509 } else if (startChar == ch1) { 01510 break; 01511 } 01512 } 01513 while (*pattern != ']') { 01514 if (*pattern == '\0') { 01515 pattern = Tcl_UtfPrev(pattern, pstart); 01516 break; 01517 } 01518 pattern++; 01519 } 01520 pattern++; 01521 continue; 01522 } 01523 01524 /* 01525 * If the next pattern character is '\', just strip off the '\' so we 01526 * do exact matching on the character that follows. 01527 */ 01528 01529 if (p == '\\') { 01530 pattern++; 01531 if (*pattern == '\0') { 01532 return 0; 01533 } 01534 } 01535 01536 /* 01537 * There's no special character. Just make sure that the next bytes of 01538 * each string match. 01539 */ 01540 01541 str += TclUtfToUniChar(str, &ch1); 01542 pattern += TclUtfToUniChar(pattern, &ch2); 01543 if (nocase) { 01544 if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) { 01545 return 0; 01546 } 01547 } else if (ch1 != ch2) { 01548 return 0; 01549 } 01550 } 01551 } 01552 01553 /* 01554 *---------------------------------------------------------------------- 01555 * 01556 * TclByteArrayMatch -- 01557 * 01558 * See if a particular string matches a particular pattern. Does not 01559 * allow for case insensitivity. 01560 * Parallels tclUtf.c:TclUniCharMatch, adjusted for char* and sans nocase. 01561 * 01562 * Results: 01563 * The return value is 1 if string matches pattern, and 0 otherwise. The 01564 * matching operation permits the following special characters in the 01565 * pattern: *?\[] (see the manual entry for details on what these mean). 01566 * 01567 * Side effects: 01568 * None. 01569 * 01570 *---------------------------------------------------------------------- 01571 */ 01572 01573 int 01574 TclByteArrayMatch( 01575 const unsigned char *string, /* String. */ 01576 int strLen, /* Length of String */ 01577 const unsigned char *pattern, /* Pattern, which may contain special 01578 * characters. */ 01579 int ptnLen, /* Length of Pattern */ 01580 int flags) 01581 { 01582 const unsigned char *stringEnd, *patternEnd; 01583 unsigned char p; 01584 01585 stringEnd = string + strLen; 01586 patternEnd = pattern + ptnLen; 01587 01588 while (1) { 01589 /* 01590 * See if we're at the end of both the pattern and the string. If so, 01591 * we succeeded. If we're at the end of the pattern but not at the end 01592 * of the string, we failed. 01593 */ 01594 01595 if (pattern == patternEnd) { 01596 return (string == stringEnd); 01597 } 01598 p = *pattern; 01599 if ((string == stringEnd) && (p != '*')) { 01600 return 0; 01601 } 01602 01603 /* 01604 * Check for a "*" as the next pattern character. It matches any 01605 * substring. We handle this by skipping all the characters up to the 01606 * next matching one in the pattern, and then calling ourselves 01607 * recursively for each postfix of string, until either we match or we 01608 * reach the end of the string. 01609 */ 01610 01611 if (p == '*') { 01612 /* 01613 * Skip all successive *'s in the pattern. 01614 */ 01615 01616 while (*(++pattern) == '*') { 01617 /* empty body */ 01618 } 01619 if (pattern == patternEnd) { 01620 return 1; 01621 } 01622 p = *pattern; 01623 while (1) { 01624 /* 01625 * Optimization for matching - cruise through the string 01626 * quickly if the next char in the pattern isn't a special 01627 * character. 01628 */ 01629 01630 if ((p != '[') && (p != '?') && (p != '\\')) { 01631 while ((string < stringEnd) && (p != *string)) { 01632 string++; 01633 } 01634 } 01635 if (TclByteArrayMatch(string, stringEnd - string, 01636 pattern, patternEnd - pattern, 0)) { 01637 return 1; 01638 } 01639 if (string == stringEnd) { 01640 return 0; 01641 } 01642 string++; 01643 } 01644 } 01645 01646 /* 01647 * Check for a "?" as the next pattern character. It matches any 01648 * single character. 01649 */ 01650 01651 if (p == '?') { 01652 pattern++; 01653 string++; 01654 continue; 01655 } 01656 01657 /* 01658 * Check for a "[" as the next pattern character. It is followed by a 01659 * list of characters that are acceptable, or by a range (two 01660 * characters separated by "-"). 01661 */ 01662 01663 if (p == '[') { 01664 unsigned char ch1, startChar, endChar; 01665 01666 pattern++; 01667 ch1 = *string; 01668 string++; 01669 while (1) { 01670 if ((*pattern == ']') || (pattern == patternEnd)) { 01671 return 0; 01672 } 01673 startChar = *pattern; 01674 pattern++; 01675 if (*pattern == '-') { 01676 pattern++; 01677 if (pattern == patternEnd) { 01678 return 0; 01679 } 01680 endChar = *pattern; 01681 pattern++; 01682 if (((startChar <= ch1) && (ch1 <= endChar)) 01683 || ((endChar <= ch1) && (ch1 <= startChar))) { 01684 /* 01685 * Matches ranges of form [a-z] or [z-a]. 01686 */ 01687 break; 01688 } 01689 } else if (startChar == ch1) { 01690 break; 01691 } 01692 } 01693 while (*pattern != ']') { 01694 if (pattern == patternEnd) { 01695 pattern--; 01696 break; 01697 } 01698 pattern++; 01699 } 01700 pattern++; 01701 continue; 01702 } 01703 01704 /* 01705 * If the next pattern character is '\', just strip off the '\' so we 01706 * do exact matching on the character that follows. 01707 */ 01708 01709 if (p == '\\') { 01710 if (++pattern == patternEnd) { 01711 return 0; 01712 } 01713 } 01714 01715 /* 01716 * There's no special character. Just make sure that the next bytes of 01717 * each string match. 01718 */ 01719 01720 if (*string != *pattern) { 01721 return 0; 01722 } 01723 string++; 01724 pattern++; 01725 } 01726 } 01727 01728 /* 01729 *---------------------------------------------------------------------- 01730 * 01731 * TclStringMatchObj -- 01732 * 01733 * See if a particular string matches a particular pattern. 01734 * Allows case insensitivity. This is the generic multi-type handler 01735 * for the various matching algorithms. 01736 * 01737 * Results: 01738 * The return value is 1 if string matches pattern, and 0 otherwise. The 01739 * matching operation permits the following special characters in the 01740 * pattern: *?\[] (see the manual entry for details on what these mean). 01741 * 01742 * Side effects: 01743 * None. 01744 * 01745 *---------------------------------------------------------------------- 01746 */ 01747 01748 int 01749 TclStringMatchObj( 01750 Tcl_Obj *strObj, /* string object. */ 01751 Tcl_Obj *ptnObj, /* pattern object. */ 01752 int flags) /* Only TCL_MATCH_NOCASE should be passed or 0. */ 01753 { 01754 int match, length, plen; 01755 01756 /* 01757 * Promote based on the type of incoming object. 01758 * XXX: Currently doesn't take advantage of exact-ness that 01759 * XXX: TclReToGlob tells us about 01760 trivial = nocase ? 0 : TclMatchIsTrivial(TclGetString(ptnObj)); 01761 */ 01762 01763 if ((strObj->typePtr == &tclStringType)) { 01764 Tcl_UniChar *udata, *uptn; 01765 01766 udata = Tcl_GetUnicodeFromObj(strObj, &length); 01767 uptn = Tcl_GetUnicodeFromObj(ptnObj, &plen); 01768 match = TclUniCharMatch(udata, length, uptn, plen, flags); 01769 } else if ((strObj->typePtr == &tclByteArrayType) && !flags) { 01770 unsigned char *data, *ptn; 01771 01772 data = Tcl_GetByteArrayFromObj(strObj, &length); 01773 ptn = Tcl_GetByteArrayFromObj(ptnObj, &plen); 01774 match = TclByteArrayMatch(data, length, ptn, plen, 0); 01775 } else { 01776 match = Tcl_StringCaseMatch(TclGetString(strObj), 01777 TclGetString(ptnObj), flags); 01778 } 01779 return match; 01780 } 01781 01782 /* 01783 *---------------------------------------------------------------------- 01784 * 01785 * Tcl_DStringInit -- 01786 * 01787 * Initializes a dynamic string, discarding any previous contents of the 01788 * string (Tcl_DStringFree should have been called already if the dynamic 01789 * string was previously in use). 01790 * 01791 * Results: 01792 * None. 01793 * 01794 * Side effects: 01795 * The dynamic string is initialized to be empty. 01796 * 01797 *---------------------------------------------------------------------- 01798 */ 01799 01800 void 01801 Tcl_DStringInit( 01802 Tcl_DString *dsPtr) /* Pointer to structure for dynamic string. */ 01803 { 01804 dsPtr->string = dsPtr->staticSpace; 01805 dsPtr->length = 0; 01806 dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; 01807 dsPtr->staticSpace[0] = '\0'; 01808 } 01809 01810 /* 01811 *---------------------------------------------------------------------- 01812 * 01813 * Tcl_DStringAppend -- 01814 * 01815 * Append more bytes to the current value of a dynamic string. 01816 * 01817 * Results: 01818 * The return value is a pointer to the dynamic string's new value. 01819 * 01820 * Side effects: 01821 * Length bytes from "bytes" (or all of "bytes" if length is less than 01822 * zero) are added to the current value of the string. Memory gets 01823 * reallocated if needed to accomodate the string's new size. 01824 * 01825 *---------------------------------------------------------------------- 01826 */ 01827 01828 char * 01829 Tcl_DStringAppend( 01830 Tcl_DString *dsPtr, /* Structure describing dynamic string. */ 01831 CONST char *bytes, /* String to append. If length is -1 then this 01832 * must be null-terminated. */ 01833 int length) /* Number of bytes from "bytes" to append. If 01834 * < 0, then append all of bytes, up to null 01835 * at end. */ 01836 { 01837 int newSize; 01838 char *dst; 01839 CONST char *end; 01840 01841 if (length < 0) { 01842 length = strlen(bytes); 01843 } 01844 newSize = length + dsPtr->length; 01845 01846 /* 01847 * Allocate a larger buffer for the string if the current one isn't large 01848 * enough. Allocate extra space in the new buffer so that there will be 01849 * room to grow before we have to allocate again. 01850 */ 01851 01852 if (newSize >= dsPtr->spaceAvl) { 01853 dsPtr->spaceAvl = newSize * 2; 01854 if (dsPtr->string == dsPtr->staticSpace) { 01855 char *newString = ckalloc((unsigned) dsPtr->spaceAvl); 01856 01857 memcpy(newString, dsPtr->string, (size_t) dsPtr->length); 01858 dsPtr->string = newString; 01859 } else { 01860 dsPtr->string = ckrealloc((void *) dsPtr->string, 01861 (size_t) dsPtr->spaceAvl); 01862 } 01863 } 01864 01865 /* 01866 * Copy the new string into the buffer at the end of the old one. 01867 */ 01868 01869 for (dst = dsPtr->string + dsPtr->length, end = bytes+length; 01870 bytes < end; bytes++, dst++) { 01871 *dst = *bytes; 01872 } 01873 *dst = '\0'; 01874 dsPtr->length += length; 01875 return dsPtr->string; 01876 } 01877 01878 /* 01879 *---------------------------------------------------------------------- 01880 * 01881 * Tcl_DStringAppendElement -- 01882 * 01883 * Append a list element to the current value of a dynamic string. 01884 * 01885 * Results: 01886 * The return value is a pointer to the dynamic string's new value. 01887 * 01888 * Side effects: 01889 * String is reformatted as a list element and added to the current value 01890 * of the string. Memory gets reallocated if needed to accomodate the 01891 * string's new size. 01892 * 01893 *---------------------------------------------------------------------- 01894 */ 01895 01896 char * 01897 Tcl_DStringAppendElement( 01898 Tcl_DString *dsPtr, /* Structure describing dynamic string. */ 01899 CONST char *element) /* String to append. Must be 01900 * null-terminated. */ 01901 { 01902 int newSize, flags, strSize; 01903 char *dst; 01904 01905 strSize = ((element== NULL) ? 0 : strlen(element)); 01906 newSize = Tcl_ScanCountedElement(element, strSize, &flags) 01907 + dsPtr->length + 1; 01908 01909 /* 01910 * Allocate a larger buffer for the string if the current one isn't large 01911 * enough. Allocate extra space in the new buffer so that there will be 01912 * room to grow before we have to allocate again. SPECIAL NOTE: must use 01913 * memcpy, not strcpy, to copy the string to a larger buffer, since there 01914 * may be embedded NULLs in the string in some cases. 01915 */ 01916 01917 if (newSize >= dsPtr->spaceAvl) { 01918 dsPtr->spaceAvl = newSize * 2; 01919 if (dsPtr->string == dsPtr->staticSpace) { 01920 char *newString = ckalloc((unsigned) dsPtr->spaceAvl); 01921 01922 memcpy(newString, dsPtr->string, (size_t) dsPtr->length); 01923 dsPtr->string = newString; 01924 } else { 01925 dsPtr->string = (char *) ckrealloc((void *) dsPtr->string, 01926 (size_t) dsPtr->spaceAvl); 01927 } 01928 } 01929 01930 /* 01931 * Convert the new string to a list element and copy it into the buffer at 01932 * the end, with a space, if needed. 01933 */ 01934 01935 dst = dsPtr->string + dsPtr->length; 01936 if (TclNeedSpace(dsPtr->string, dst)) { 01937 *dst = ' '; 01938 dst++; 01939 dsPtr->length++; 01940 01941 /* 01942 * If we need a space to separate this element from preceding stuff, 01943 * then this element will not lead a list, and need not have it's 01944 * leading '#' quoted. 01945 */ 01946 01947 flags |= TCL_DONT_QUOTE_HASH; 01948 } 01949 dsPtr->length += Tcl_ConvertCountedElement(element, strSize, dst, flags); 01950 return dsPtr->string; 01951 } 01952 01953 /* 01954 *---------------------------------------------------------------------- 01955 * 01956 * Tcl_DStringSetLength -- 01957 * 01958 * Change the length of a dynamic string. This can cause the string to 01959 * either grow or shrink, depending on the value of length. 01960 * 01961 * Results: 01962 * None. 01963 * 01964 * Side effects: 01965 * The length of dsPtr is changed to length and a null byte is stored at 01966 * that position in the string. If length is larger than the space 01967 * allocated for dsPtr, then a panic occurs. 01968 * 01969 *---------------------------------------------------------------------- 01970 */ 01971 01972 void 01973 Tcl_DStringSetLength( 01974 Tcl_DString *dsPtr, /* Structure describing dynamic string. */ 01975 int length) /* New length for dynamic string. */ 01976 { 01977 int newsize; 01978 01979 if (length < 0) { 01980 length = 0; 01981 } 01982 if (length >= dsPtr->spaceAvl) { 01983 /* 01984 * There are two interesting cases here. In the first case, the user 01985 * may be trying to allocate a large buffer of a specific size. It 01986 * would be wasteful to overallocate that buffer, so we just allocate 01987 * enough for the requested size plus the trailing null byte. In the 01988 * second case, we are growing the buffer incrementally, so we need 01989 * behavior similar to Tcl_DStringAppend. The requested length will 01990 * usually be a small delta above the current spaceAvl, so we'll end 01991 * up doubling the old size. This won't grow the buffer quite as 01992 * quickly, but it should be close enough. 01993 */ 01994 01995 newsize = dsPtr->spaceAvl * 2; 01996 if (length < newsize) { 01997 dsPtr->spaceAvl = newsize; 01998 } else { 01999 dsPtr->spaceAvl = length + 1; 02000 } 02001 if (dsPtr->string == dsPtr->staticSpace) { 02002 char *newString = ckalloc((unsigned) dsPtr->spaceAvl); 02003 02004 memcpy(newString, dsPtr->string, (size_t) dsPtr->length); 02005 dsPtr->string = newString; 02006 } else { 02007 dsPtr->string = (char *) ckrealloc((void *) dsPtr->string, 02008 (size_t) dsPtr->spaceAvl); 02009 } 02010 } 02011 dsPtr->length = length; 02012 dsPtr->string[length] = 0; 02013 } 02014 02015 /* 02016 *---------------------------------------------------------------------- 02017 * 02018 * Tcl_DStringFree -- 02019 * 02020 * Frees up any memory allocated for the dynamic string and reinitializes 02021 * the string to an empty state. 02022 * 02023 * Results: 02024 * None. 02025 * 02026 * Side effects: 02027 * The previous contents of the dynamic string are lost, and the new 02028 * value is an empty string. 02029 * 02030 *---------------------------------------------------------------------- 02031 */ 02032 02033 void 02034 Tcl_DStringFree( 02035 Tcl_DString *dsPtr) /* Structure describing dynamic string. */ 02036 { 02037 if (dsPtr->string != dsPtr->staticSpace) { 02038 ckfree(dsPtr->string); 02039 } 02040 dsPtr->string = dsPtr->staticSpace; 02041 dsPtr->length = 0; 02042 dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; 02043 dsPtr->staticSpace[0] = '\0'; 02044 } 02045 02046 /* 02047 *---------------------------------------------------------------------- 02048 * 02049 * Tcl_DStringResult -- 02050 * 02051 * This function moves the value of a dynamic string into an interpreter 02052 * as its string result. Afterwards, the dynamic string is reset to an 02053 * empty string. 02054 * 02055 * Results: 02056 * None. 02057 * 02058 * Side effects: 02059 * The string is "moved" to interp's result, and any existing string 02060 * result for interp is freed. dsPtr is reinitialized to an empty string. 02061 * 02062 *---------------------------------------------------------------------- 02063 */ 02064 02065 void 02066 Tcl_DStringResult( 02067 Tcl_Interp *interp, /* Interpreter whose result is to be reset. */ 02068 Tcl_DString *dsPtr) /* Dynamic string that is to become the 02069 * result of interp. */ 02070 { 02071 Tcl_ResetResult(interp); 02072 02073 if (dsPtr->string != dsPtr->staticSpace) { 02074 interp->result = dsPtr->string; 02075 interp->freeProc = TCL_DYNAMIC; 02076 } else if (dsPtr->length < TCL_RESULT_SIZE) { 02077 interp->result = ((Interp *) interp)->resultSpace; 02078 strcpy(interp->result, dsPtr->string); 02079 } else { 02080 Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE); 02081 } 02082 02083 dsPtr->string = dsPtr->staticSpace; 02084 dsPtr->length = 0; 02085 dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; 02086 dsPtr->staticSpace[0] = '\0'; 02087 } 02088 02089 /* 02090 *---------------------------------------------------------------------- 02091 * 02092 * Tcl_DStringGetResult -- 02093 * 02094 * This function moves an interpreter's result into a dynamic string. 02095 * 02096 * Results: 02097 * None. 02098 * 02099 * Side effects: 02100 * The interpreter's string result is cleared, and the previous contents 02101 * of dsPtr are freed. 02102 * 02103 * If the string result is empty, the object result is moved to the 02104 * string result, then the object result is reset. 02105 * 02106 *---------------------------------------------------------------------- 02107 */ 02108 02109 void 02110 Tcl_DStringGetResult( 02111 Tcl_Interp *interp, /* Interpreter whose result is to be reset. */ 02112 Tcl_DString *dsPtr) /* Dynamic string that is to become the result 02113 * of interp. */ 02114 { 02115 Interp *iPtr = (Interp *) interp; 02116 02117 if (dsPtr->string != dsPtr->staticSpace) { 02118 ckfree(dsPtr->string); 02119 } 02120 02121 /* 02122 * If the string result is empty, move the object result to the string 02123 * result, then reset the object result. 02124 */ 02125 02126 (void) Tcl_GetStringResult(interp); 02127 02128 dsPtr->length = strlen(iPtr->result); 02129 if (iPtr->freeProc != NULL) { 02130 if (iPtr->freeProc == TCL_DYNAMIC) { 02131 dsPtr->string = iPtr->result; 02132 dsPtr->spaceAvl = dsPtr->length+1; 02133 } else { 02134 dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1)); 02135 memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1); 02136 (*iPtr->freeProc)(iPtr->result); 02137 } 02138 dsPtr->spaceAvl = dsPtr->length+1; 02139 iPtr->freeProc = NULL; 02140 } else { 02141 if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) { 02142 dsPtr->string = dsPtr->staticSpace; 02143 dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE; 02144 } else { 02145 dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1)); 02146 dsPtr->spaceAvl = dsPtr->length + 1; 02147 } 02148 memcpy(dsPtr->string, iPtr->result, (unsigned) dsPtr->length+1); 02149 } 02150 02151 iPtr->result = iPtr->resultSpace; 02152 iPtr->resultSpace[0] = 0; 02153 } 02154 02155 /* 02156 *---------------------------------------------------------------------- 02157 * 02158 * Tcl_DStringStartSublist -- 02159 * 02160 * This function adds the necessary information to a dynamic string 02161 * (e.g. " {") to start a sublist. Future element appends will be in the 02162 * sublist rather than the main list. 02163 * 02164 * Results: 02165 * None. 02166 * 02167 * Side effects: 02168 * Characters get added to the dynamic string. 02169 * 02170 *---------------------------------------------------------------------- 02171 */ 02172 02173 void 02174 Tcl_DStringStartSublist( 02175 Tcl_DString *dsPtr) /* Dynamic string. */ 02176 { 02177 if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) { 02178 Tcl_DStringAppend(dsPtr, " {", -1); 02179 } else { 02180 Tcl_DStringAppend(dsPtr, "{", -1); 02181 } 02182 } 02183 02184 /* 02185 *---------------------------------------------------------------------- 02186 * 02187 * Tcl_DStringEndSublist -- 02188 * 02189 * This function adds the necessary characters to a dynamic string to end 02190 * a sublist (e.g. "}"). Future element appends will be in the enclosing 02191 * (sub)list rather than the current sublist. 02192 * 02193 * Results: 02194 * None. 02195 * 02196 * Side effects: 02197 * None. 02198 * 02199 *---------------------------------------------------------------------- 02200 */ 02201 02202 void 02203 Tcl_DStringEndSublist( 02204 Tcl_DString *dsPtr) /* Dynamic string. */ 02205 { 02206 Tcl_DStringAppend(dsPtr, "}", -1); 02207 } 02208 02209 /* 02210 *---------------------------------------------------------------------- 02211 * 02212 * Tcl_PrintDouble -- 02213 * 02214 * Given a floating-point value, this function converts it to an ASCII 02215 * string using. 02216 * 02217 * Results: 02218 * The ASCII equivalent of "value" is written at "dst". It is written 02219 * using the current precision, and it is guaranteed to contain a decimal 02220 * point or exponent, so that it looks like a floating-point value and 02221 * not an integer. 02222 * 02223 * Side effects: 02224 * None. 02225 * 02226 *---------------------------------------------------------------------- 02227 */ 02228 02229 void 02230 Tcl_PrintDouble( 02231 Tcl_Interp *interp, /* Interpreter whose tcl_precision variable 02232 * used to be used to control printing. It's 02233 * ignored now. */ 02234 double value, /* Value to print as string. */ 02235 char *dst) /* Where to store converted value; must have 02236 * at least TCL_DOUBLE_SPACE characters. */ 02237 { 02238 char *p, c; 02239 int exp; 02240 int signum; 02241 char buffer[TCL_DOUBLE_SPACE]; 02242 Tcl_UniChar ch; 02243 02244 int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int)sizeof(int)); 02245 02246 /* 02247 * If *precisionPtr == 0, then use TclDoubleDigits to develop a decimal 02248 * significand and exponent, then format it in E or F format as 02249 * appropriate. If *precisionPtr != 0, use the native sprintf and then add 02250 * a trailing ".0" if there is no decimal point in the rep. 02251 */ 02252 02253 if (*precisionPtr == 0) { 02254 /* 02255 * Handle NaN. 02256 */ 02257 02258 if (TclIsNaN(value)) { 02259 TclFormatNaN(value, dst); 02260 return; 02261 } 02262 02263 /* 02264 * Handle infinities. 02265 */ 02266 02267 if (TclIsInfinite(value)) { 02268 if (value < 0) { 02269 strcpy(dst, "-Inf"); 02270 } else { 02271 strcpy(dst, "Inf"); 02272 } 02273 return; 02274 } 02275 02276 /* 02277 * Ordinary (normal and denormal) values. 02278 */ 02279 02280 exp = TclDoubleDigits(buffer, value, &signum); 02281 if (signum) { 02282 *dst++ = '-'; 02283 } 02284 p = buffer; 02285 if (exp < -3 || exp > 17) { 02286 /* 02287 * E format for numbers < 1e-3 or >= 1e17. 02288 */ 02289 02290 *dst++ = *p++; 02291 c = *p; 02292 if (c != '\0') { 02293 *dst++ = '.'; 02294 while (c != '\0') { 02295 *dst++ = c; 02296 c = *++p; 02297 } 02298 } 02299 sprintf(dst, "e%+d", exp-1); 02300 } else { 02301 /* 02302 * F format for others. 02303 */ 02304 02305 if (exp <= 0) { 02306 *dst++ = '0'; 02307 } 02308 c = *p; 02309 while (exp-- > 0) { 02310 if (c != '\0') { 02311 *dst++ = c; 02312 c = *++p; 02313 } else { 02314 *dst++ = '0'; 02315 } 02316 } 02317 *dst++ = '.'; 02318 if (c == '\0') { 02319 *dst++ = '0'; 02320 } else { 02321 while (++exp < 0) { 02322 *dst++ = '0'; 02323 } 02324 while (c != '\0') { 02325 *dst++ = c; 02326 c = *++p; 02327 } 02328 } 02329 *dst++ = '\0'; 02330 } 02331 } else { 02332 /* 02333 * tcl_precision is supplied, pass it to the native sprintf. 02334 */ 02335 02336 sprintf(dst, "%.*g", *precisionPtr, value); 02337 02338 /* 02339 * If the ASCII result looks like an integer, add ".0" so that it 02340 * doesn't look like an integer anymore. This prevents floating-point 02341 * values from being converted to integers unintentionally. Check for 02342 * ASCII specifically to speed up the function. 02343 */ 02344 02345 for (p = dst; *p != 0;) { 02346 if (UCHAR(*p) < 0x80) { 02347 c = *p++; 02348 } else { 02349 p += Tcl_UtfToUniChar(p, &ch); 02350 c = UCHAR(ch); 02351 } 02352 if ((c == '.') || isalpha(UCHAR(c))) { /* INTL: ISO only. */ 02353 return; 02354 } 02355 } 02356 p[0] = '.'; 02357 p[1] = '0'; 02358 p[2] = 0; 02359 } 02360 } 02361 02362 /* 02363 *---------------------------------------------------------------------- 02364 * 02365 * TclPrecTraceProc -- 02366 * 02367 * This function is invoked whenever the variable "tcl_precision" is 02368 * written. 02369 * 02370 * Results: 02371 * Returns NULL if all went well, or an error message if the new value 02372 * for the variable doesn't make sense. 02373 * 02374 * Side effects: 02375 * If the new value doesn't make sense then this function undoes the 02376 * effect of the variable modification. Otherwise it modifies the format 02377 * string that's used by Tcl_PrintDouble. 02378 * 02379 *---------------------------------------------------------------------- 02380 */ 02381 02382 /* ARGSUSED */ 02383 char * 02384 TclPrecTraceProc( 02385 ClientData clientData, /* Not used. */ 02386 Tcl_Interp *interp, /* Interpreter containing variable. */ 02387 CONST char *name1, /* Name of variable. */ 02388 CONST char *name2, /* Second part of variable name. */ 02389 int flags) /* Information about what happened. */ 02390 { 02391 Tcl_Obj* value; 02392 int prec; 02393 int *precisionPtr = Tcl_GetThreadData(&precisionKey, (int) sizeof(int)); 02394 02395 /* 02396 * If the variable is unset, then recreate the trace. 02397 */ 02398 02399 if (flags & TCL_TRACE_UNSETS) { 02400 if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) { 02401 Tcl_TraceVar2(interp, name1, name2, 02402 TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES 02403 |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData); 02404 } 02405 return NULL; 02406 } 02407 02408 /* 02409 * When the variable is read, reset its value from our shared value. This 02410 * is needed in case the variable was modified in some other interpreter 02411 * so that this interpreter's value is out of date. 02412 */ 02413 02414 02415 if (flags & TCL_TRACE_READS) { 02416 Tcl_SetVar2Ex(interp, name1, name2, Tcl_NewIntObj(*precisionPtr), 02417 flags & TCL_GLOBAL_ONLY); 02418 return NULL; 02419 } 02420 02421 /* 02422 * The variable is being written. Check the new value and disallow it if 02423 * it isn't reasonable or if this is a safe interpreter (we don't want 02424 * safe interpreters messing up the precision of other interpreters). 02425 */ 02426 02427 if (Tcl_IsSafe(interp)) { 02428 return "can't modify precision from a safe interpreter"; 02429 } 02430 value = Tcl_GetVar2Ex(interp, name1, name2, flags & TCL_GLOBAL_ONLY); 02431 if (value == NULL 02432 || Tcl_GetIntFromObj((Tcl_Interp*) NULL, value, &prec) != TCL_OK 02433 || prec < 0 || prec > TCL_MAX_PREC) { 02434 return "improper value for precision"; 02435 } 02436 *precisionPtr = prec; 02437 return NULL; 02438 } 02439 02440 /* 02441 *---------------------------------------------------------------------- 02442 * 02443 * TclNeedSpace -- 02444 * 02445 * This function checks to see whether it is appropriate to add a space 02446 * before appending a new list element to an existing string. 02447 * 02448 * Results: 02449 * The return value is 1 if a space is appropriate, 0 otherwise. 02450 * 02451 * Side effects: 02452 * None. 02453 * 02454 *---------------------------------------------------------------------- 02455 */ 02456 02457 int 02458 TclNeedSpace( 02459 CONST char *start, /* First character in string. */ 02460 CONST char *end) /* End of string (place where space will be 02461 * added, if appropriate). */ 02462 { 02463 /* 02464 * A space is needed unless either: 02465 * (a) we're at the start of the string, or 02466 */ 02467 02468 if (end == start) { 02469 return 0; 02470 } 02471 02472 /* 02473 * (b) we're at the start of a nested list-element, quoted with an open 02474 * curly brace; we can be nested arbitrarily deep, so long as the 02475 * first curly brace starts an element, so backtrack over open curly 02476 * braces that are trailing characters of the string; and 02477 */ 02478 02479 end = Tcl_UtfPrev(end, start); 02480 while (*end == '{') { 02481 if (end == start) { 02482 return 0; 02483 } 02484 end = Tcl_UtfPrev(end, start); 02485 } 02486 02487 /* 02488 * (c) the trailing character of the string is already a list-element 02489 * separator (according to TclFindElement); that is, one of these 02490 * characters: 02491 * \u0009 \t TAB 02492 * \u000A \n NEWLINE 02493 * \u000B \v VERTICAL TAB 02494 * \u000C \f FORM FEED 02495 * \u000D \r CARRIAGE RETURN 02496 * \u0020 SPACE 02497 * with the condition that the penultimate character is not a 02498 * backslash. 02499 */ 02500 02501 if (*end > 0x20) { 02502 /* 02503 * Performance tweak. All ASCII spaces are <= 0x20. So get a quick 02504 * answer for most characters before comparing against all spaces in 02505 * the switch below. 02506 * 02507 * NOTE: Remove this if other Unicode spaces ever get accepted as 02508 * list-element separators. 02509 */ 02510 return 1; 02511 } 02512 switch (*end) { 02513 case ' ': 02514 case '\t': 02515 case '\n': 02516 case '\r': 02517 case '\v': 02518 case '\f': 02519 if ((end == start) || (end[-1] != '\\')) { 02520 return 0; 02521 } 02522 } 02523 return 1; 02524 } 02525 02526 /* 02527 *---------------------------------------------------------------------- 02528 * 02529 * TclGetIntForIndex -- 02530 * 02531 * This function returns an integer corresponding to the list index held 02532 * in a Tcl object. The Tcl object's value is expected to be in the 02533 * format integer([+-]integer)? or the format end([+-]integer)?. 02534 * 02535 * Results: 02536 * The return value is normally TCL_OK, which means that the index was 02537 * successfully stored into the location referenced by "indexPtr". If the 02538 * Tcl object referenced by "objPtr" has the value "end", the value 02539 * stored is "endValue". If "objPtr"s values is not of one of the 02540 * expected formats, TCL_ERROR is returned and, if "interp" is non-NULL, 02541 * an error message is left in the interpreter's result object. 02542 * 02543 * Side effects: 02544 * The object referenced by "objPtr" might be converted to an integer, 02545 * wide integer, or end-based-index object. 02546 * 02547 *---------------------------------------------------------------------- 02548 */ 02549 02550 int 02551 TclGetIntForIndex( 02552 Tcl_Interp *interp, /* Interpreter to use for error reporting. If 02553 * NULL, then no error message is left after 02554 * errors. */ 02555 Tcl_Obj *objPtr, /* Points to an object containing either "end" 02556 * or an integer. */ 02557 int endValue, /* The value to be stored at "indexPtr" if 02558 * "objPtr" holds "end". */ 02559 int *indexPtr) /* Location filled in with an integer 02560 * representing an index. */ 02561 { 02562 int length; 02563 char *opPtr, *bytes; 02564 02565 if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) { 02566 return TCL_OK; 02567 } 02568 02569 if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) { 02570 /* 02571 * If the object is already an offset from the end of the list, or can 02572 * be converted to one, use it. 02573 */ 02574 02575 *indexPtr = endValue + objPtr->internalRep.longValue; 02576 return TCL_OK; 02577 } 02578 02579 bytes = TclGetStringFromObj(objPtr, &length); 02580 02581 /* 02582 * Leading whitespace is acceptable in an index. 02583 */ 02584 02585 while (length && isspace(UCHAR(*bytes))) { /* INTL: ISO space. */ 02586 bytes++; 02587 length--; 02588 } 02589 02590 if (TclParseNumber(NULL, NULL, NULL, bytes, length, (const char **)&opPtr, 02591 TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) == TCL_OK) { 02592 int code, first, second; 02593 char savedOp = *opPtr; 02594 02595 if ((savedOp != '+') && (savedOp != '-')) { 02596 goto parseError; 02597 } 02598 if (isspace(UCHAR(opPtr[1]))) { 02599 goto parseError; 02600 } 02601 *opPtr = '\0'; 02602 code = Tcl_GetInt(interp, bytes, &first); 02603 *opPtr = savedOp; 02604 if (code == TCL_ERROR) { 02605 goto parseError; 02606 } 02607 if (TCL_ERROR == Tcl_GetInt(interp, opPtr+1, &second)) { 02608 goto parseError; 02609 } 02610 if (savedOp == '+') { 02611 *indexPtr = first + second; 02612 } else { 02613 *indexPtr = first - second; 02614 } 02615 return TCL_OK; 02616 } 02617 02618 /* 02619 * Report a parse error. 02620 */ 02621 02622 parseError: 02623 if (interp != NULL) { 02624 char *bytes = Tcl_GetString(objPtr); 02625 02626 /* 02627 * The result might not be empty; this resets it which should be both 02628 * a cheap operation, and of little problem because this is an 02629 * error-generation path anyway. 02630 */ 02631 02632 Tcl_ResetResult(interp); 02633 Tcl_AppendResult(interp, "bad index \"", bytes, 02634 "\": must be integer?[+-]integer? or end?[+-]integer?", NULL); 02635 if (!strncmp(bytes, "end-", 4)) { 02636 bytes += 4; 02637 } 02638 TclCheckBadOctal(interp, bytes); 02639 } 02640 02641 return TCL_ERROR; 02642 } 02643 02644 /* 02645 *---------------------------------------------------------------------- 02646 * 02647 * UpdateStringOfEndOffset -- 02648 * 02649 * Update the string rep of a Tcl object holding an "end-offset" 02650 * expression. 02651 * 02652 * Results: 02653 * None. 02654 * 02655 * Side effects: 02656 * Stores a valid string in the object's string rep. 02657 * 02658 * This function does NOT free any earlier string rep. If it is called on an 02659 * object that already has a valid string rep, it will leak memory. 02660 * 02661 *---------------------------------------------------------------------- 02662 */ 02663 02664 static void 02665 UpdateStringOfEndOffset( 02666 register Tcl_Obj* objPtr) 02667 { 02668 char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1]; 02669 register int len; 02670 02671 strcpy(buffer, "end"); 02672 len = sizeof("end") - 1; 02673 if (objPtr->internalRep.longValue != 0) { 02674 buffer[len++] = '-'; 02675 len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue)); 02676 } 02677 objPtr->bytes = ckalloc((unsigned) len+1); 02678 memcpy(objPtr->bytes, buffer, (unsigned) len+1); 02679 objPtr->length = len; 02680 } 02681 02682 /* 02683 *---------------------------------------------------------------------- 02684 * 02685 * SetEndOffsetFromAny -- 02686 * 02687 * Look for a string of the form "end[+-]offset" and convert it to an 02688 * internal representation holding the offset. 02689 * 02690 * Results: 02691 * Returns TCL_OK if ok, TCL_ERROR if the string was badly formed. 02692 * 02693 * Side effects: 02694 * If interp is not NULL, stores an error message in the interpreter 02695 * result. 02696 * 02697 *---------------------------------------------------------------------- 02698 */ 02699 02700 static int 02701 SetEndOffsetFromAny( 02702 Tcl_Interp *interp, /* Tcl interpreter or NULL */ 02703 Tcl_Obj *objPtr) /* Pointer to the object to parse */ 02704 { 02705 int offset; /* Offset in the "end-offset" expression */ 02706 register char* bytes; /* String rep of the object */ 02707 int length; /* Length of the object's string rep */ 02708 02709 /* 02710 * If it's already the right type, we're fine. 02711 */ 02712 02713 if (objPtr->typePtr == &tclEndOffsetType) { 02714 return TCL_OK; 02715 } 02716 02717 /* 02718 * Check for a string rep of the right form. 02719 */ 02720 02721 bytes = TclGetStringFromObj(objPtr, &length); 02722 if ((*bytes != 'e') || (strncmp(bytes, "end", 02723 (size_t)((length > 3) ? 3 : length)) != 0)) { 02724 if (interp != NULL) { 02725 Tcl_ResetResult(interp); 02726 Tcl_AppendResult(interp, "bad index \"", bytes, 02727 "\": must be end?[+-]integer?", NULL); 02728 } 02729 return TCL_ERROR; 02730 } 02731 02732 /* 02733 * Convert the string rep. 02734 */ 02735 02736 if (length <= 3) { 02737 offset = 0; 02738 } else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) { 02739 /* 02740 * This is our limited string expression evaluator. Pass everything 02741 * after "end-" to Tcl_GetInt, then reverse for offset. 02742 */ 02743 02744 if (isspace(UCHAR(bytes[4]))) { 02745 return TCL_ERROR; 02746 } 02747 if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) { 02748 return TCL_ERROR; 02749 } 02750 if (bytes[3] == '-') { 02751 offset = -offset; 02752 } 02753 } else { 02754 /* 02755 * Conversion failed. Report the error. 02756 */ 02757 02758 if (interp != NULL) { 02759 Tcl_ResetResult(interp); 02760 Tcl_AppendResult(interp, "bad index \"", bytes, 02761 "\": must be end?[+-]integer?", NULL); 02762 } 02763 return TCL_ERROR; 02764 } 02765 02766 /* 02767 * The conversion succeeded. Free the old internal rep and set the new 02768 * one. 02769 */ 02770 02771 TclFreeIntRep(objPtr); 02772 objPtr->internalRep.longValue = offset; 02773 objPtr->typePtr = &tclEndOffsetType; 02774 02775 return TCL_OK; 02776 } 02777 02778 /* 02779 *---------------------------------------------------------------------- 02780 * 02781 * TclCheckBadOctal -- 02782 * 02783 * This function checks for a bad octal value and appends a meaningful 02784 * error to the interp's result. 02785 * 02786 * Results: 02787 * 1 if the argument was a bad octal, else 0. 02788 * 02789 * Side effects: 02790 * The interpreter's result is modified. 02791 * 02792 *---------------------------------------------------------------------- 02793 */ 02794 02795 int 02796 TclCheckBadOctal( 02797 Tcl_Interp *interp, /* Interpreter to use for error reporting. If 02798 * NULL, then no error message is left after 02799 * errors. */ 02800 CONST char *value) /* String to check. */ 02801 { 02802 register CONST char *p = value; 02803 02804 /* 02805 * A frequent mistake is invalid octal values due to an unwanted leading 02806 * zero. Try to generate a meaningful error message. 02807 */ 02808 02809 while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ 02810 p++; 02811 } 02812 if (*p == '+' || *p == '-') { 02813 p++; 02814 } 02815 if (*p == '0') { 02816 if ((p[1] == 'o') || p[1] == 'O') { 02817 p+=2; 02818 } 02819 while (isdigit(UCHAR(*p))) { /* INTL: digit. */ 02820 p++; 02821 } 02822 while (isspace(UCHAR(*p))) { /* INTL: ISO space. */ 02823 p++; 02824 } 02825 if (*p == '\0') { 02826 /* 02827 * Reached end of string. 02828 */ 02829 02830 if (interp != NULL) { 02831 /* 02832 * Don't reset the result here because we want this result to 02833 * be added to an existing error message as extra info. 02834 */ 02835 02836 Tcl_AppendResult(interp, " (looks like invalid octal number)", 02837 NULL); 02838 } 02839 return 1; 02840 } 02841 } 02842 return 0; 02843 } 02844 02845 /* 02846 *---------------------------------------------------------------------- 02847 * 02848 * ClearHash -- 02849 * 02850 * Remove all the entries in the hash table *tablePtr. 02851 * 02852 *---------------------------------------------------------------------- 02853 */ 02854 02855 static void 02856 ClearHash( 02857 Tcl_HashTable *tablePtr) 02858 { 02859 Tcl_HashSearch search; 02860 Tcl_HashEntry *hPtr; 02861 02862 for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; 02863 hPtr = Tcl_NextHashEntry(&search)) { 02864 Tcl_Obj *objPtr = (Tcl_Obj *) Tcl_GetHashValue(hPtr); 02865 Tcl_DecrRefCount(objPtr); 02866 Tcl_DeleteHashEntry(hPtr); 02867 } 02868 } 02869 02870 /* 02871 *---------------------------------------------------------------------- 02872 * 02873 * GetThreadHash -- 02874 * 02875 * Get a thread-specific (Tcl_HashTable *) associated with a thread data 02876 * key. 02877 * 02878 * Results: 02879 * The Tcl_HashTable * corresponding to *keyPtr. 02880 * 02881 * Side effects: 02882 * The first call on a keyPtr in each thread creates a new Tcl_HashTable, 02883 * and registers a thread exit handler to dispose of it. 02884 * 02885 *---------------------------------------------------------------------- 02886 */ 02887 02888 static Tcl_HashTable * 02889 GetThreadHash( 02890 Tcl_ThreadDataKey *keyPtr) 02891 { 02892 Tcl_HashTable **tablePtrPtr = (Tcl_HashTable **) 02893 Tcl_GetThreadData(keyPtr, (int) sizeof(Tcl_HashTable *)); 02894 02895 if (NULL == *tablePtrPtr) { 02896 *tablePtrPtr = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable)); 02897 Tcl_CreateThreadExitHandler(FreeThreadHash, (ClientData)*tablePtrPtr); 02898 Tcl_InitHashTable(*tablePtrPtr, TCL_ONE_WORD_KEYS); 02899 } 02900 return *tablePtrPtr; 02901 } 02902 02903 /* 02904 *---------------------------------------------------------------------- 02905 * 02906 * FreeThreadHash -- 02907 * 02908 * Thread exit handler used by GetThreadHash to dispose of a thread hash 02909 * table. 02910 * 02911 * Side effects: 02912 * Frees a Tcl_HashTable. 02913 * 02914 *---------------------------------------------------------------------- 02915 */ 02916 02917 static void 02918 FreeThreadHash( 02919 ClientData clientData) 02920 { 02921 Tcl_HashTable *tablePtr = (Tcl_HashTable *) clientData; 02922 02923 ClearHash(tablePtr); 02924 Tcl_DeleteHashTable(tablePtr); 02925 ckfree((char *) tablePtr); 02926 } 02927 02928 /* 02929 *---------------------------------------------------------------------- 02930 * 02931 * FreeProcessGlobalValue -- 02932 * 02933 * Exit handler used by Tcl(Set|Get)ProcessGlobalValue to cleanup a 02934 * ProcessGlobalValue at exit. 02935 * 02936 *---------------------------------------------------------------------- 02937 */ 02938 02939 static void 02940 FreeProcessGlobalValue( 02941 ClientData clientData) 02942 { 02943 ProcessGlobalValue *pgvPtr = (ProcessGlobalValue *) clientData; 02944 02945 pgvPtr->epoch++; 02946 pgvPtr->numBytes = 0; 02947 ckfree(pgvPtr->value); 02948 pgvPtr->value = NULL; 02949 if (pgvPtr->encoding) { 02950 Tcl_FreeEncoding(pgvPtr->encoding); 02951 pgvPtr->encoding = NULL; 02952 } 02953 Tcl_MutexFinalize(&pgvPtr->mutex); 02954 } 02955 02956 /* 02957 *---------------------------------------------------------------------- 02958 * 02959 * TclSetProcessGlobalValue -- 02960 * 02961 * Utility routine to set a global value shared by all threads in the 02962 * process while keeping a thread-local copy as well. 02963 * 02964 *---------------------------------------------------------------------- 02965 */ 02966 02967 void 02968 TclSetProcessGlobalValue( 02969 ProcessGlobalValue *pgvPtr, 02970 Tcl_Obj *newValue, 02971 Tcl_Encoding encoding) 02972 { 02973 CONST char *bytes; 02974 Tcl_HashTable *cacheMap; 02975 Tcl_HashEntry *hPtr; 02976 int dummy; 02977 02978 Tcl_MutexLock(&pgvPtr->mutex); 02979 02980 /* 02981 * Fill the global string value. 02982 */ 02983 02984 pgvPtr->epoch++; 02985 if (NULL != pgvPtr->value) { 02986 ckfree(pgvPtr->value); 02987 } else { 02988 Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData) pgvPtr); 02989 } 02990 bytes = Tcl_GetStringFromObj(newValue, &pgvPtr->numBytes); 02991 pgvPtr->value = ckalloc((unsigned) pgvPtr->numBytes + 1); 02992 memcpy(pgvPtr->value, bytes, (unsigned) pgvPtr->numBytes + 1); 02993 if (pgvPtr->encoding) { 02994 Tcl_FreeEncoding(pgvPtr->encoding); 02995 } 02996 pgvPtr->encoding = encoding; 02997 02998 /* 02999 * Fill the local thread copy directly with the Tcl_Obj value to avoid 03000 * loss of the intrep. Increment newValue refCount early to handle case 03001 * where we set a PGV to itself. 03002 */ 03003 03004 Tcl_IncrRefCount(newValue); 03005 cacheMap = GetThreadHash(&pgvPtr->key); 03006 ClearHash(cacheMap); 03007 hPtr = Tcl_CreateHashEntry(cacheMap, 03008 (char *) INT2PTR(pgvPtr->epoch), &dummy); 03009 Tcl_SetHashValue(hPtr, (ClientData) newValue); 03010 Tcl_MutexUnlock(&pgvPtr->mutex); 03011 } 03012 03013 /* 03014 *---------------------------------------------------------------------- 03015 * 03016 * TclGetProcessGlobalValue -- 03017 * 03018 * Retrieve a global value shared among all threads of the process, 03019 * preferring a thread-local copy as long as it remains valid. 03020 * 03021 * Results: 03022 * Returns a (Tcl_Obj *) that holds a copy of the global value. 03023 * 03024 *---------------------------------------------------------------------- 03025 */ 03026 03027 Tcl_Obj * 03028 TclGetProcessGlobalValue( 03029 ProcessGlobalValue *pgvPtr) 03030 { 03031 Tcl_Obj *value = NULL; 03032 Tcl_HashTable *cacheMap; 03033 Tcl_HashEntry *hPtr; 03034 int epoch = pgvPtr->epoch; 03035 03036 if (pgvPtr->encoding) { 03037 Tcl_Encoding current = Tcl_GetEncoding(NULL, NULL); 03038 03039 if (pgvPtr->encoding != current) { 03040 /* 03041 * The system encoding has changed since the master string value 03042 * was saved. Convert the master value to be based on the new 03043 * system encoding. 03044 */ 03045 03046 Tcl_DString native, newValue; 03047 03048 Tcl_MutexLock(&pgvPtr->mutex); 03049 pgvPtr->epoch++; 03050 epoch = pgvPtr->epoch; 03051 Tcl_UtfToExternalDString(pgvPtr->encoding, pgvPtr->value, 03052 pgvPtr->numBytes, &native); 03053 Tcl_ExternalToUtfDString(current, Tcl_DStringValue(&native), 03054 Tcl_DStringLength(&native), &newValue); 03055 Tcl_DStringFree(&native); 03056 ckfree(pgvPtr->value); 03057 pgvPtr->value = ckalloc((unsigned int) 03058 Tcl_DStringLength(&newValue) + 1); 03059 memcpy(pgvPtr->value, Tcl_DStringValue(&newValue), 03060 (size_t) Tcl_DStringLength(&newValue) + 1); 03061 Tcl_DStringFree(&newValue); 03062 Tcl_FreeEncoding(pgvPtr->encoding); 03063 pgvPtr->encoding = current; 03064 Tcl_MutexUnlock(&pgvPtr->mutex); 03065 } else { 03066 Tcl_FreeEncoding(current); 03067 } 03068 } 03069 cacheMap = GetThreadHash(&pgvPtr->key); 03070 hPtr = Tcl_FindHashEntry(cacheMap, (char *) INT2PTR(epoch)); 03071 if (NULL == hPtr) { 03072 int dummy; 03073 03074 /* 03075 * No cache for the current epoch - must be a new one. 03076 * 03077 * First, clear the cacheMap, as anything in it must refer to some 03078 * expired epoch. 03079 */ 03080 03081 ClearHash(cacheMap); 03082 03083 /* 03084 * If no thread has set the shared value, call the initializer. 03085 */ 03086 03087 Tcl_MutexLock(&pgvPtr->mutex); 03088 if ((NULL == pgvPtr->value) && (pgvPtr->proc)) { 03089 pgvPtr->epoch++; 03090 (*(pgvPtr->proc))(&pgvPtr->value, &pgvPtr->numBytes, 03091 &pgvPtr->encoding); 03092 if (pgvPtr->value == NULL) { 03093 Tcl_Panic("PGV Initializer did not initialize"); 03094 } 03095 Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData)pgvPtr); 03096 } 03097 03098 /* 03099 * Store a copy of the shared value in our epoch-indexed cache. 03100 */ 03101 03102 value = Tcl_NewStringObj(pgvPtr->value, pgvPtr->numBytes); 03103 hPtr = Tcl_CreateHashEntry(cacheMap, 03104 (char *) INT2PTR(pgvPtr->epoch), &dummy); 03105 Tcl_MutexUnlock(&pgvPtr->mutex); 03106 Tcl_SetHashValue(hPtr, (ClientData) value); 03107 Tcl_IncrRefCount(value); 03108 } 03109 return (Tcl_Obj *) Tcl_GetHashValue(hPtr); 03110 } 03111 03112 /* 03113 *---------------------------------------------------------------------- 03114 * 03115 * TclSetObjNameOfExecutable -- 03116 * 03117 * This function stores the absolute pathname of the executable file 03118 * (normally as computed by TclpFindExecutable). 03119 * 03120 * Results: 03121 * None. 03122 * 03123 * Side effects: 03124 * Stores the executable name. 03125 * 03126 *---------------------------------------------------------------------- 03127 */ 03128 03129 void 03130 TclSetObjNameOfExecutable( 03131 Tcl_Obj *name, 03132 Tcl_Encoding encoding) 03133 { 03134 TclSetProcessGlobalValue(&executableName, name, encoding); 03135 } 03136 03137 /* 03138 *---------------------------------------------------------------------- 03139 * 03140 * TclGetObjNameOfExecutable -- 03141 * 03142 * This function retrieves the absolute pathname of the application in 03143 * which the Tcl library is running, usually as previously stored by 03144 * TclpFindExecutable(). This function call is the C API equivalent to 03145 * the "info nameofexecutable" command. 03146 * 03147 * Results: 03148 * A pointer to an "fsPath" Tcl_Obj, or to an empty Tcl_Obj if the 03149 * pathname of the application is unknown. 03150 * 03151 * Side effects: 03152 * None. 03153 * 03154 *---------------------------------------------------------------------- 03155 */ 03156 03157 Tcl_Obj * 03158 TclGetObjNameOfExecutable(void) 03159 { 03160 return TclGetProcessGlobalValue(&executableName); 03161 } 03162 03163 /* 03164 *---------------------------------------------------------------------- 03165 * 03166 * Tcl_GetNameOfExecutable -- 03167 * 03168 * This function retrieves the absolute pathname of the application in 03169 * which the Tcl library is running, and returns it in string form. 03170 * 03171 * The returned string belongs to Tcl and should be copied if the caller 03172 * plans to keep it, to guard against it becoming invalid. 03173 * 03174 * Results: 03175 * A pointer to the internal string or NULL if the internal full path 03176 * name has not been computed or unknown. 03177 * 03178 * Side effects: 03179 * None. 03180 * 03181 *---------------------------------------------------------------------- 03182 */ 03183 03184 CONST char * 03185 Tcl_GetNameOfExecutable(void) 03186 { 03187 int numBytes; 03188 const char *bytes = 03189 Tcl_GetStringFromObj(TclGetObjNameOfExecutable(), &numBytes); 03190 03191 if (numBytes == 0) { 03192 return NULL; 03193 } 03194 return bytes; 03195 } 03196 03197 /* 03198 *---------------------------------------------------------------------- 03199 * 03200 * TclpGetTime -- 03201 * 03202 * Deprecated synonym for Tcl_GetTime. This function is provided for the 03203 * benefit of extensions written before Tcl_GetTime was exported from the 03204 * library. 03205 * 03206 * Results: 03207 * None. 03208 * 03209 * Side effects: 03210 * Stores current time in the buffer designated by "timePtr" 03211 * 03212 *---------------------------------------------------------------------- 03213 */ 03214 03215 void 03216 TclpGetTime( 03217 Tcl_Time *timePtr) 03218 { 03219 Tcl_GetTime(timePtr); 03220 } 03221 03222 /* 03223 *---------------------------------------------------------------------- 03224 * 03225 * TclGetPlatform -- 03226 * 03227 * This is a kludge that allows the test library to get access the 03228 * internal tclPlatform variable. 03229 * 03230 * Results: 03231 * Returns a pointer to the tclPlatform variable. 03232 * 03233 * Side effects: 03234 * None. 03235 * 03236 *---------------------------------------------------------------------- 03237 */ 03238 03239 TclPlatformType * 03240 TclGetPlatform(void) 03241 { 03242 return &tclPlatform; 03243 } 03244 03245 /* 03246 *---------------------------------------------------------------------- 03247 * 03248 * TclReToGlob -- 03249 * 03250 * Attempt to convert a regular expression to an equivalent glob pattern. 03251 * 03252 * Results: 03253 * Returns TCL_OK on success, TCL_ERROR on failure. If interp is not 03254 * NULL, an error message is placed in the result. On success, the 03255 * DString will contain an exact equivalent glob pattern. The caller is 03256 * responsible for calling Tcl_DStringFree on success. If exactPtr is not 03257 * NULL, it will be 1 if an exact match qualifies. 03258 * 03259 * Side effects: 03260 * None. 03261 * 03262 *---------------------------------------------------------------------- 03263 */ 03264 03265 int 03266 TclReToGlob( 03267 Tcl_Interp *interp, 03268 const char *reStr, 03269 int reStrLen, 03270 Tcl_DString *dsPtr, 03271 int *exactPtr) 03272 { 03273 int anchorLeft, anchorRight; 03274 char *dsStr, *dsStrStart, *msg; 03275 const char *p, *strEnd; 03276 03277 strEnd = reStr + reStrLen; 03278 Tcl_DStringInit(dsPtr); 03279 03280 /* 03281 * "***=xxx" == "*xxx*" 03282 */ 03283 03284 if ((reStrLen >= 4) && (memcmp("***=", reStr, 4) == 0)) { 03285 if (exactPtr) { 03286 *exactPtr = 1; 03287 } 03288 Tcl_DStringAppend(dsPtr, reStr + 4, reStrLen - 4); 03289 return TCL_OK; 03290 } 03291 03292 /* 03293 * Write to the ds directly without the function overhead. 03294 * An equivalent glob pattern can be no more than reStrLen+2 in size. 03295 */ 03296 03297 Tcl_DStringSetLength(dsPtr, reStrLen + 2); 03298 dsStrStart = Tcl_DStringValue(dsPtr); 03299 03300 /* 03301 * Check for anchored REs (ie ^foo$), so we can use string equal if 03302 * possible. Do not alter the start of str so we can free it correctly. 03303 */ 03304 03305 msg = NULL; 03306 p = reStr; 03307 anchorRight = 0; 03308 dsStr = dsStrStart; 03309 if (*p == '^') { 03310 anchorLeft = 1; 03311 p++; 03312 } else { 03313 anchorLeft = 0; 03314 *dsStr++ = '*'; 03315 } 03316 03317 for ( ; p < strEnd; p++) { 03318 switch (*p) { 03319 case '\\': 03320 p++; 03321 switch (*p) { 03322 case 'a': 03323 *dsStr++ = '\a'; 03324 break; 03325 case 'b': 03326 *dsStr++ = '\b'; 03327 break; 03328 case 'f': 03329 *dsStr++ = '\f'; 03330 break; 03331 case 'n': 03332 *dsStr++ = '\n'; 03333 break; 03334 case 'r': 03335 *dsStr++ = '\r'; 03336 break; 03337 case 't': 03338 *dsStr++ = '\t'; 03339 break; 03340 case 'v': 03341 *dsStr++ = '\v'; 03342 break; 03343 case 'B': case '\\': 03344 *dsStr++ = '\\'; 03345 *dsStr++ = '\\'; 03346 anchorLeft = 0; /* prevent exact match */ 03347 break; 03348 case '*': case '[': case ']': case '?': 03349 /* Only add \ where necessary for glob */ 03350 *dsStr++ = '\\'; 03351 anchorLeft = 0; /* prevent exact match */ 03352 /* fall through */ 03353 case '{': case '}': case '(': case ')': case '+': 03354 case '.': case '|': case '^': case '$': 03355 *dsStr++ = *p; 03356 break; 03357 default: 03358 msg = "invalid escape sequence"; 03359 goto invalidGlob; 03360 } 03361 break; 03362 case '.': 03363 anchorLeft = 0; /* prevent exact match */ 03364 if (p+1 < strEnd) { 03365 if (p[1] == '*') { 03366 p++; 03367 if ((dsStr == dsStrStart) || (dsStr[-1] != '*')) { 03368 *dsStr++ = '*'; 03369 } 03370 continue; 03371 } else if (p[1] == '+') { 03372 p++; 03373 *dsStr++ = '?'; 03374 *dsStr++ = '*'; 03375 continue; 03376 } 03377 } 03378 *dsStr++ = '?'; 03379 break; 03380 case '$': 03381 if (p+1 != strEnd) { 03382 msg = "$ not anchor"; 03383 goto invalidGlob; 03384 } 03385 anchorRight = 1; 03386 break; 03387 case '*': case '+': case '?': case '|': case '^': 03388 case '{': case '}': case '(': case ')': case '[': case ']': 03389 msg = "unhandled RE special char"; 03390 goto invalidGlob; 03391 break; 03392 default: 03393 *dsStr++ = *p; 03394 break; 03395 } 03396 } 03397 if (!anchorRight && ((dsStr == dsStrStart) || (dsStr[-1] != '*'))) { 03398 *dsStr++ = '*'; 03399 } 03400 Tcl_DStringSetLength(dsPtr, dsStr - dsStrStart); 03401 03402 if (exactPtr) { 03403 *exactPtr = (anchorLeft && anchorRight); 03404 } 03405 03406 #if 0 03407 fprintf(stderr, "INPUT RE '%.*s' OUTPUT GLOB '%s' anchor %d:%d \n", 03408 reStrLen, reStr, 03409 Tcl_DStringValue(dsPtr), anchorLeft, anchorRight); 03410 fflush(stderr); 03411 #endif 03412 return TCL_OK; 03413 03414 invalidGlob: 03415 #if 0 03416 fprintf(stderr, "INPUT RE '%.*s' NO OUTPUT GLOB %s (%c)\n", 03417 reStrLen, reStr, msg, *p); 03418 fflush(stderr); 03419 #endif 03420 if (interp != NULL) { 03421 Tcl_AppendResult(interp, msg, NULL); 03422 } 03423 Tcl_DStringFree(dsPtr); 03424 return TCL_ERROR; 03425 } 03426 03427 /* 03428 * Local Variables: 03429 * mode: c 03430 * c-basic-offset: 4 03431 * fill-column: 78 03432 * End: 03433 */
Generated on Wed Mar 12 12:18:23 2008 by 1.5.1 |