Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | fix back-ported from tclSE (with several modifications due to conflicts and compat reasons) |
|---|---|
| Timelines: | family | ancestors | descendants | both | bug-8f89e2e059 |
| Files: | files | file ages | folders |
| SHA3-256: |
e2f84651dd3763a1f6d99f98d5b64812 |
| User & Date: | sebres 2020-03-13 13:08:15.183 |
Context
|
2020-03-13
| ||
| 14:45 | Merge 8.6. Code review: Tcl 8.6 doesn't (need to) build with -DUNICODE -D_UNICODE any more, so thin... Closed-Leaf check-in: c4bba1629c user: jan.nijtmans tags: bug-8f89e2e059 | |
| 13:08 | fix back-ported from tclSE (with several modifications due to conflicts and compat reasons) check-in: e2f84651dd user: sebres tags: bug-8f89e2e059 | |
| 13:06 | env.test: added test for windows illustrating bug [8f89e2e059] - loss of multi-byte chars in environ... check-in: dcf2c77048 user: sebres tags: bug-8f89e2e059 | |
Changes
Changes to generic/tclEnv.c.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 37 38 39 40 41 42 43 | * malloced and has this many total entries * allocated to it (not all may be in use at * once). Zero means that the environment * array is in its original static state. */ #endif } env; /* * Declarations for local functions defined in this file: */ static char * EnvTraceProc(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags); static void ReplaceString(const char *oldStr, char *newStr); | > > > > > > > > > > > > > > > > > > > > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | * malloced and has this many total entries * allocated to it (not all may be in use at * once). Zero means that the environment * array is in its original static state. */ #endif } env; #if defined(_WIN32) && (defined(_UNICODE) || defined(UNICODE)) # define tenviron _wenviron # define tenviron2utfdstr(tenvstr, len, dstr) \ Tcl_WinTCharToUtf((TCHAR *)tenvstr, len, dstr) # define utf2tenvirondstr(str, len, dstr) \ (const char *)Tcl_WinUtfToTChar(str, len, dstr) # define techar TCHAR # ifdef USE_PUTENV # define putenv(env) _wputenv((const wchar_t *)env) # endif #else # define tenviron environ # define tenviron2utfdstr(tenvstr, len, dstr) \ Tcl_ExternalToUtfDString(NULL, tenvstr, len, dstr) # define utf2tenvirondstr(str, len, dstr) \ Tcl_UtfToExternalDString(NULL, str, len, dstr) # define techar char #endif #define tNTL sizeof(techar) /* * Declarations for local functions defined in this file: */ static char * EnvTraceProc(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags); static void ReplaceString(const char *oldStr, char *newStr); |
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
/*
* Go through the environment array and transfer its values into Tcl. At
* the same time, remove those elements we add/update from the hash table
* of existing elements, so that after this part processes, that table
* will hold just the parts to remove.
*/
| | | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
/*
* Go through the environment array and transfer its values into Tcl. At
* the same time, remove those elements we add/update from the hash table
* of existing elements, so that after this part processes, that table
* will hold just the parts to remove.
*/
if (tenviron[0] != NULL) {
int i;
Tcl_MutexLock(&envMutex);
for (i = 0; tenviron[i] != NULL; i++) {
Tcl_Obj *obj1, *obj2;
const char *p1;
char *p2;
p1 = tenviron2utfdstr(tenviron[i], -1, &envString);
p2 = strchr(p1, '=');
if (p2 == NULL) {
/*
* This condition seem to happen occasionally under some
* versions of Solaris, or when encoding accidents swallow the
* '='; ignore the entry.
*/
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 | #ifndef USE_PUTENV /* * We need to handle the case where the environment may be changed * outside our control. ourEnvironSize is only valid if the current * environment is the one we allocated. [Bug 979640] */ | | | | | | | | | | | | | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
#ifndef USE_PUTENV
/*
* We need to handle the case where the environment may be changed
* outside our control. ourEnvironSize is only valid if the current
* environment is the one we allocated. [Bug 979640]
*/
if ((env.ourEnviron != (char *)tenviron) || (length+2 > env.ourEnvironSize)) {
char **newEnviron = ckalloc((length + 5) * sizeof(char *));
memcpy(newEnviron, tenviron, length * sizeof(char *));
if ((env.ourEnvironSize != 0) && (env.ourEnviron != NULL)) {
ckfree(env.ourEnviron);
}
tenviron = (techar **)(env.ourEnviron = newEnviron);
env.ourEnvironSize = length + 5;
}
index = length;
tenviron[index + 1] = NULL;
#endif /* USE_PUTENV */
oldValue = NULL;
nameLength = strlen(name);
} else {
const char *oldEnv;
/*
* Compare the new value to the existing value. If they're the same
* then quit immediately (e.g. don't rewrite the value or propagate it
* to other interpreters). Otherwise, when there are N interpreters
* there will be N! propagations of the same value among the
* interpreters.
*/
oldEnv = tenviron2utfdstr(tenviron[index], -1, &envString);
if (strcmp(value, oldEnv + (length + 1)) == 0) {
Tcl_DStringFree(&envString);
Tcl_MutexUnlock(&envMutex);
return;
}
Tcl_DStringFree(&envString);
oldValue = (char *)tenviron[index];
nameLength = (unsigned) length;
}
/*
* Create a new entry. Build a complete UTF string that contains a
* "name=value" pattern. Then convert the string to the native encoding,
* and set the environ array value.
*/
valueLength = strlen(value);
p = ckalloc(nameLength + valueLength + 2);
memcpy(p, name, nameLength);
p[nameLength] = '=';
memcpy(p+nameLength+1, value, valueLength+1);
p2 = utf2tenvirondstr(p, -1, &envString);
/*
* Copy the native string to heap memory.
*/
p = ckrealloc(p, Tcl_DStringLength(&envString) + tNTL);
memcpy(p, p2, (unsigned) Tcl_DStringLength(&envString) + tNTL);
Tcl_DStringFree(&envString);
#ifdef USE_PUTENV
/*
* Update the system environment.
*/
putenv(p);
index = TclpFindVariable(name, &length);
#else
tenviron[index] = (techar *)p;
#endif /* USE_PUTENV */
/*
* Watch out for versions of putenv that copy the string (e.g. VC++). In
* this case we need to free the string immediately. Otherwise update the
* string in the cache.
*/
if ((index != -1) && (tenviron[index] == (techar *)p)) {
ReplaceString(oldValue, p);
#ifdef HAVE_PUTENV_THAT_COPIES
} else {
/*
* This putenv() copies instead of taking ownership.
*/
|
| ︙ | ︙ | |||
374 375 376 377 378 379 380 |
}
/*
* First convert the native string to UTF. Then separate the string into
* name and value parts, and call TclSetEnv to do all of the real work.
*/
| | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
}
/*
* First convert the native string to UTF. Then separate the string into
* name and value parts, and call TclSetEnv to do all of the real work.
*/
name = tenviron2utfdstr(assignment, -1, &nameString);
value = strchr(name, '=');
if ((value != NULL) && (value != name)) {
value[0] = '\0';
TclSetEnv(name, value+1);
}
|
| ︙ | ︙ | |||
436 437 438 439 440 441 442 |
return;
}
/*
* Remember the old value so we can free it if Tcl created the string.
*/
| | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
return;
}
/*
* Remember the old value so we can free it if Tcl created the string.
*/
oldValue = (char *)tenviron[index];
/*
* Update the system environment. This must be done before we update the
* interpreters or we will recurse.
*/
#ifdef USE_PUTENV_FOR_UNSET
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
string[length+1] = '\0';
#else
string = ckalloc(length + 1);
memcpy(string, name, (size_t) length);
string[length] = '\0';
#endif /* _WIN32 */
| | | | | | | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 |
string[length+1] = '\0';
#else
string = ckalloc(length + 1);
memcpy(string, name, (size_t) length);
string[length] = '\0';
#endif /* _WIN32 */
utf2tenvirondstr(string, -1, &envString);
string = ckrealloc(string, Tcl_DStringLength(&envString) + tNTL);
memcpy(string, Tcl_DStringValue(&envString),
(unsigned) Tcl_DStringLength(&envString) + tNTL);
Tcl_DStringFree(&envString);
putenv(string);
/*
* Watch out for versions of putenv that copy the string (e.g. VC++). In
* this case we need to free the string immediately. Otherwise update the
* string in the cache.
*/
if (tenviron[index] == (techar *)string) {
ReplaceString(oldValue, string);
#ifdef HAVE_PUTENV_THAT_COPIES
} else {
/*
* This putenv() copies instead of taking ownership.
*/
ckfree(string);
#endif /* HAVE_PUTENV_THAT_COPIES */
}
#else /* !USE_PUTENV_FOR_UNSET */
for (envPtr = (char *)(tenviron+index+1); ; envPtr++) {
envPtr[-1] = *envPtr;
if (*envPtr == NULL) {
break;
}
}
ReplaceString(oldValue, NULL);
#endif /* USE_PUTENV_FOR_UNSET */
|
| ︙ | ︙ | |||
535 536 537 538 539 540 541 |
Tcl_MutexLock(&envMutex);
index = TclpFindVariable(name, &length);
result = NULL;
if (index != -1) {
Tcl_DString envStr;
| | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
Tcl_MutexLock(&envMutex);
index = TclpFindVariable(name, &length);
result = NULL;
if (index != -1) {
Tcl_DString envStr;
result = tenviron2utfdstr(tenviron[index], -1, &envStr);
result += length;
if (*result == '=') {
result++;
Tcl_DStringInit(valuePtr);
Tcl_DStringAppend(valuePtr, result, -1);
result = Tcl_DStringValue(valuePtr);
} else {
|
| ︙ | ︙ |
Changes to win/Makefile.in.
| ︙ | ︙ | |||
524 525 526 527 528 529 530 531 532 533 534 |
.SUFFIXES: .${OBJEXT}
.SUFFIXES: .$(RES)
.SUFFIXES: .rc
# Special case object targets
tclTestMain.${OBJEXT}: tclAppInit.c
$(CC) -c $(CC_SWITCHES) -DTCL_TEST -DUNICODE -D_UNICODE $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinInit.${OBJEXT}: tclWinInit.c
| > > > | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
.SUFFIXES: .${OBJEXT}
.SUFFIXES: .$(RES)
.SUFFIXES: .rc
# Special case object targets
tclEnv.${OBJEXT}: tclEnv.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
tclTestMain.${OBJEXT}: tclAppInit.c
$(CC) -c $(CC_SWITCHES) -DTCL_TEST -DUNICODE -D_UNICODE $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinInit.${OBJEXT}: tclWinInit.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
tclWinPipe.${OBJEXT}: tclWinPipe.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinReg.${OBJEXT}: tclWinReg.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
|
| ︙ | ︙ |
Changes to win/tclWinInit.c.
| ︙ | ︙ | |||
679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclpFindVariable(
const char *name, /* Name of desired environment variable
* (UTF-8). */
int *lengthPtr) /* Used to return length of name (for
* successful searches) or number of non-NULL
* entries in environ (for unsuccessful
| > > > > > > > > > > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
#if defined(_WIN32) && (defined(_UNICODE) || defined(UNICODE))
# define tenviron _wenviron
# define tenviron2utfdstr(tenvstr, len, dstr) \
Tcl_WinTCharToUtf((TCHAR *)tenvstr, len, dstr)
#else
# define tenviron environ
# define tenviron2utfdstr(tenvstr, len, dstr) \
Tcl_ExternalToUtfDString(NULL, tenvstr, len, dstr)
#endif
int
TclpFindVariable(
const char *name, /* Name of desired environment variable
* (UTF-8). */
int *lengthPtr) /* Used to return length of name (for
* successful searches) or number of non-NULL
* entries in environ (for unsuccessful
|
| ︙ | ︙ | |||
703 704 705 706 707 708 709 |
length = strlen(name);
nameUpper = ckalloc(length + 1);
memcpy(nameUpper, name, (size_t) length+1);
Tcl_UtfToUpper(nameUpper);
Tcl_DStringInit(&envString);
| | > > | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
length = strlen(name);
nameUpper = ckalloc(length + 1);
memcpy(nameUpper, name, (size_t) length+1);
Tcl_UtfToUpper(nameUpper);
Tcl_DStringInit(&envString);
for (i = 0, env = (const char *)tenviron[i];
env != NULL;
i++, env = (const char *)tenviron[i]) {
/*
* Chop the env string off after the equal sign, then Convert the name
* to all upper case, so we do not have to convert all the characters
* after the equal sign.
*/
envUpper = tenviron2utfdstr(env, -1, &envString);
p1 = strchr(envUpper, '=');
if (p1 == NULL) {
continue;
}
length = (int) (p1 - envUpper);
Tcl_DStringSetLength(&envString, length+1);
Tcl_UtfToUpper(envUpper);
|
| ︙ | ︙ |