Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge 8.7 |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | tip-514 |
Files: | files | file ages | folders |
SHA3-256: |
eaf86378bc062c8218b25a9f74284033 |
User & Date: | jan.nijtmans 2018-09-27 21:38:11.764 |
Context
2018-09-28
| ||
19:58 | Merge 8.7 Closed-Leaf check-in: b4a19593fb user: jan.nijtmans tags: tip-514 | |
2018-09-27
| ||
21:38 | Merge 8.7 check-in: eaf86378bc user: jan.nijtmans tags: tip-514 | |
11:08 | Implementation of TIP 426: Determining the "Type" of Commands check-in: 4dbf61778e user: dkf tags: core-8-branch | |
2018-09-22
| ||
13:37 | merge tip-515 branch check-in: 686effa0af user: jan.nijtmans tags: tip-514 | |
Changes
Changes to doc/CrtObjCmd.3.
1 2 3 4 5 6 7 8 9 10 | '\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_CreateObjCommand 3 8.0 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | '\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_CreateObjCommand 3 8.0 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj Tcl_RegisterCommandTypeName, Tcl_GetCommandTypeName \- implement new commands in C .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp Tcl_Command \fBTcl_CreateObjCommand\fR(\fIinterp, cmdName, proc, clientData, deleteProc\fR) .sp |
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 | \fBTcl_GetCommandName\fR(\fIinterp, token\fR) .sp void \fBTcl_GetCommandFullName\fR(\fIinterp, token, objPtr\fR) .sp Tcl_Command \fBTcl_GetCommandFromObj\fR(\fIinterp, objPtr\fR) .SH ARGUMENTS .AS Tcl_CmdDeleteProc *deleteProc in/out .AP Tcl_Interp *interp in Interpreter in which to create a new command or that contains a command. .AP char *cmdName in Name of command. .AP Tcl_ObjCmdProc *proc in | > > > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | \fBTcl_GetCommandName\fR(\fIinterp, token\fR) .sp void \fBTcl_GetCommandFullName\fR(\fIinterp, token, objPtr\fR) .sp Tcl_Command \fBTcl_GetCommandFromObj\fR(\fIinterp, objPtr\fR) .sp .VS "info cmdtype feature" void \fBTcl_RegisterCommandTypeName\fR(\fIproc, typeName\fR) .sp const char * \fBTcl_GetCommandTypeName\fR(\fItoken\fR) .VE "info cmdtype feature" .SH ARGUMENTS .AS Tcl_CmdDeleteProc *deleteProc in/out .AP Tcl_Interp *interp in Interpreter in which to create a new command or that contains a command. .AP char *cmdName in Name of command. .AP Tcl_ObjCmdProc *proc in |
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 | Token for command, returned by previous call to \fBTcl_CreateObjCommand\fR. The command must not have been deleted. .AP Tcl_CmdInfo *infoPtr in/out Pointer to structure containing various information about a Tcl command. .AP Tcl_Obj *objPtr in Value containing the name of a Tcl command. .BE .SH DESCRIPTION .PP \fBTcl_CreateObjCommand\fR defines a new command in \fIinterp\fR and associates it with procedure \fIproc\fR such that whenever \fIname\fR is invoked as a Tcl command (e.g., via a call to \fBTcl_EvalObjEx\fR) | > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | Token for command, returned by previous call to \fBTcl_CreateObjCommand\fR. The command must not have been deleted. .AP Tcl_CmdInfo *infoPtr in/out Pointer to structure containing various information about a Tcl command. .AP Tcl_Obj *objPtr in Value containing the name of a Tcl command. .AP "const char" *typeName in Indicates the name of the type of command implementation associated with a particular \fIproc\fR, or NULL to break the association. .BE .SH DESCRIPTION .PP \fBTcl_CreateObjCommand\fR defines a new command in \fIinterp\fR and associates it with procedure \fIproc\fR such that whenever \fIname\fR is invoked as a Tcl command (e.g., via a call to \fBTcl_EvalObjEx\fR) |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 | The name, including all namespace prefixes, is appended to the value specified by \fIobjPtr\fR. .PP \fBTcl_GetCommandFromObj\fR returns a token for the command specified by the name in a \fBTcl_Obj\fR. The command name is resolved relative to the current namespace. Returns NULL if the command is not found. .SH "SEE ALSO" Tcl_CreateCommand(3), Tcl_ResetResult(3), Tcl_SetObjResult(3) .SH KEYWORDS bind, command, create, delete, namespace, value | > > > > > > > > > > > > > > > > | 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 | The name, including all namespace prefixes, is appended to the value specified by \fIobjPtr\fR. .PP \fBTcl_GetCommandFromObj\fR returns a token for the command specified by the name in a \fBTcl_Obj\fR. The command name is resolved relative to the current namespace. Returns NULL if the command is not found. .PP .VS "info cmdtype feature" \fBTcl_RegisterCommandTypeName\fR is used to associate a name (the \fItypeName\fR argument) with a particular implementation function so that it can then be looked up with \fBTcl_GetCommandTypeName\fR, which in turn is called with a command token that information is wanted for and which returns the name of the type that was registered for the implementation function used for that command. (The lookup functionality is surfaced virtually directly in Tcl via \fBinfo cmdtype\fR.) If there is no function registered for a particular function, the result will be the string literal .QW \fBnative\fR . The registration of a name can be undone by registering a mapping to NULL instead. The result from \fBTcl_GetCommandTypeName\fR will be exactly that string which was registered, and not a copy; use of a compile-time constant string is \fIstrongly recommended\fR. .VE "info cmdtype feature" .SH "SEE ALSO" Tcl_CreateCommand(3), Tcl_ResetResult(3), Tcl_SetObjResult(3) .SH KEYWORDS bind, command, create, delete, namespace, value |
Changes to doc/SaveResult.3.
1 2 3 | '\" '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" Contributions from Don Porter, NIST, 2004. (not subject to US copyright) | | | 1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Copyright (c) 1997 by Sun Microsystems, Inc. '\" Contributions from Don Porter, NIST, 2004. (not subject to US copyright) '\" Copyright (c) 2018 Nathan Coulter. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_SaveResult 3 8.1 Tcl "Tcl Library Procedures" .so man.macros .BS |
︙ | ︙ |
Changes to doc/append.n.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | .BE .SH DESCRIPTION .PP Append all of the \fIvalue\fR arguments to the current value of variable \fIvarName\fR. If \fIvarName\fR does not exist, it is given a value equal to the concatenation of all the \fIvalue\fR arguments. The result of this command is the new value stored in variable \fIvarName\fR. This command provides an efficient way to build up long variables incrementally. For example, .QW "\fBappend a $b\fR" is much more efficient than | > > > > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | .BE .SH DESCRIPTION .PP Append all of the \fIvalue\fR arguments to the current value of variable \fIvarName\fR. If \fIvarName\fR does not exist, it is given a value equal to the concatenation of all the \fIvalue\fR arguments. .VS TIP508 If \fIvarName\fR indicate an element that does not exist of an array that has a default value set, the concatenation of the default value and all the \fIvalue\fR arguments will be stored in the array element. .VE TIP508 The result of this command is the new value stored in variable \fIvarName\fR. This command provides an efficient way to build up long variables incrementally. For example, .QW "\fBappend a $b\fR" is much more efficient than |
︙ | ︙ | |||
40 41 42 43 44 45 46 | puts $var # Prints 0,1,2,3,4,5,6,7,8,9,10 .CE .SH "SEE ALSO" concat(n), lappend(n) .SH KEYWORDS append, variable | | | > | | 45 46 47 48 49 50 51 52 53 54 55 | puts $var # Prints 0,1,2,3,4,5,6,7,8,9,10 .CE .SH "SEE ALSO" concat(n), lappend(n) .SH KEYWORDS append, variable .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/array.n.
1 2 3 4 5 6 7 | '\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | '\" '\" Copyright (c) 1993-1994 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH array n 8.7 Tcl "Tcl Built-In Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME array \- Manipulate array variables .SH SYNOPSIS \fBarray \fIoption arrayName\fR ?\fIarg arg ...\fR? |
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | \fISearchId\fR indicates which search on \fIarrayName\fR to check, and must have been the return value from a previous invocation of \fBarray startsearch\fR. This option is particularly useful if an array has an element with an empty name, since the return value from \fBarray nextelement\fR will not indicate whether the search has been completed. .TP \fBarray donesearch \fIarrayName searchId\fR This command terminates an array search and destroys all the state associated with that search. \fISearchId\fR indicates which search on \fIarrayName\fR to destroy, and must have been the return value from a previous invocation of \fBarray startsearch\fR. Returns an empty string. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | \fISearchId\fR indicates which search on \fIarrayName\fR to check, and must have been the return value from a previous invocation of \fBarray startsearch\fR. This option is particularly useful if an array has an element with an empty name, since the return value from \fBarray nextelement\fR will not indicate whether the search has been completed. .TP \fBarray default \fIsubcommand arrayName args...\fR .VS TIP508 Manages the default value of the array. Arrays initially have no default value, but this command allows you to set one; the default value will be returned when reading from an element of the array \farrayName\fR if the read would otherwise result in an error. Note that this may cause the \fBappend\fR, \fBdict\fR, \fBincr\fR and \fBlappend\fR commands to change their behavior in relation to non-existing array elements. .RS .PP The \fIsubcommand\fR argument controls what exact operation will be performed on the default value of \fIarrayName\fR. Supported \fIsubcommand\fRs are: .VE TIP508 .TP \fBarray default exists \fIarrayName\fR .VS TIP508 This returns a boolean value indicating whether a default value has been set for the array \fIarrayName\fR. Returns a false value if \fIarrayName\fR does not exist. Raises an error if \fIarrayName\fR is an existing variable that is not an array. .VE TIP508 .TP \fBarray default get \fIarrayName\fR .VS TIP508 This returns the current default value for the array \fIarrayName\fR. Raises an error if \fIarrayName\fR is an existing variable that is not an array, or if \fIarrayName\fR is an array without a default value. .VE TIP508 .TP \fBarray default set \fIarrayName value\fR .VS TIP508 This sets the default value for the array \fIarrayName\fR to \fIvalue\fR. Returns the empty string. Raises an error if \fIarrayName\fR is an existing variable that is not an array, or if \fIarrayName\fR is an illegal name for an array. If \fIarrayName\fR does not currently exist, it is created as an empty array as well as having its default value set. .VE TIP508 .TP \fBarray default unset \fIarrayName\fR .VS TIP508 This removes the default value for the array \fIarrayName\fR and returns the empty string. Does nothing if \fIarrayName\fR does not have a default value. Raises an error if \fIarrayName\fR is an existing variable that is not an array. .VE TIP508 .RE .TP \fBarray donesearch \fIarrayName searchId\fR This command terminates an array search and destroys all the state associated with that search. \fISearchId\fR indicates which search on \fIarrayName\fR to destroy, and must have been the return value from a previous invocation of \fBarray startsearch\fR. Returns an empty string. |
︙ | ︙ | |||
190 191 192 193 194 195 196 | number of buckets with 10 or more entries: 0 average search distance for entry: 1.2 .CE .SH "SEE ALSO" list(n), string(n), variable(n), trace(n), foreach(n) .SH KEYWORDS array, element names, search | > > > > | 237 238 239 240 241 242 243 244 245 246 247 | number of buckets with 10 or more entries: 0 average search distance for entry: 1.2 .CE .SH "SEE ALSO" list(n), string(n), variable(n), trace(n), foreach(n) .SH KEYWORDS array, element names, search .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/define.n.
︙ | ︙ | |||
422 423 424 425 426 427 428 | \fBself call\fR). .VE TIP500 .SH "SLOTTED DEFINITIONS" Some of the configurable definitions of a class or object are \fIslotted definitions\fR. This means that the configuration is implemented by a slot object, that is an instance of the class \fBoo::Slot\fR, which manages a list of values (class names, variable names, etc.) that comprises the contents of | | > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 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 522 523 524 525 526 527 528 529 530 531 532 533 534 | \fBself call\fR). .VE TIP500 .SH "SLOTTED DEFINITIONS" Some of the configurable definitions of a class or object are \fIslotted definitions\fR. This means that the configuration is implemented by a slot object, that is an instance of the class \fBoo::Slot\fR, which manages a list of values (class names, variable names, etc.) that comprises the contents of the slot. The class defines five operations (as methods) that may be done on the slot: .TP \fIslot\fR \fB\-append\fR ?\fImember ...\fR? . This appends the given \fImember\fR elements to the slot definition. .TP \fIslot\fR \fB\-clear\fR . This sets the slot definition to the empty list. .TP \fIslot\fR \fB\-prepend\fR ?\fImember ...\fR? .VS TIP516 This prepends the given \fImember\fR elements to the slot definition. .VE TIP516 .TP \fIslot\fR \fB\-remove\fR ?\fImember ...\fR? .VS TIP516 This removes the given \fImember\fR elements from the slot definition. .VE TIP516 .TP \fIslot\fR \fB\-set\fR ?\fImember ...\fR? . This replaces the slot definition with the given \fImember\fR elements. .PP A consequence of this is that any use of a slot's default operation where the first member argument begins with a hyphen will be an error. One of the above operations should be used explicitly in those circumstances. .SS "SLOT IMPLEMENTATION" Internally, slot objects also define a method \fB\-\-default\-operation\fR which is forwarded to the default operation of the slot (thus, for the class .QW \fBvariable\fR slot, this is forwarded to .QW "\fBmy \-append\fR" ), and these methods which provide the implementation interface: .TP \fIslot\fR \fBGet\fR . Returns a list that is the current contents of the slot, but does not modify the slot. This method must always be called from a stack frame created by a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method \fIshould not\fR return an error unless it is called from outside a definition context or with the wrong number of arguments. .RS .PP .VS TIP516 The elements of the list should be fully resolved, if that is a meaningful concept to the slot. .VE TIP516 .RE .TP \fIslot\fR \fBResolve\fR \fIslotElement\fR .VS TIP516 Returns \fIslotElement\fR with a resolution operation applied to it, but does not modify the slot. For slots of simple strings, this is an operation that does nothing, whereas for slots of classes, this maps a class name to its fully-qualified class name. This method must always be called from a stack frame created by a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method \fIshould not\fR return an error unless it is called from outside a definition context or with the wrong number of arguments; unresolvable arguments should be returned as is (as not all slot operations strictly require that values are resolvable to work). .RS .PP Implementations \fIshould not\fR enforce uniqueness and ordering constraints in this method; that is the responsibility of the \fBSet\fR method. .RE .VE TIP516 .TP \fIslot\fR \fBSet \fIelementList\fR . Sets the contents of the slot to the list \fIelementList\fR and returns the empty string. This method must always be called from a stack frame created by a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an error if it rejects the change to the slot contents (e.g., because of invalid values) as well as if it is called from outside a definition context or with the wrong number of arguments. .RS .PP This method \fImay\fR reorder and filter the elements if this is necessary in order to satisfy the underlying constraints of the slot. (For example, slots of classes enforce a uniqueness constraint that places each element in the earliest location in the slot that it can.) .RE .PP The implementation of these methods is slot-dependent (and responsible for accessing the correct part of the class or object definition). Slots also have an unknown method handler to tie all these pieces together, and they hide their \fBdestroy\fR method so that it is not invoked inadvertently. It is \fIrecommended\fR that any user changes to the slot mechanism be restricted to defining new operations whose names start with a hyphen. .PP .VS TIP516 Most slot operations will initially \fBResolve\fR their argument list, combine it with the results of the \fBGet\fR method, and then \fBSet\fR the result. Some operations omit one or both of the first two steps; omitting the third would result in an idempotent read-only operation (but the standard mechanism for reading from slots is via \fBinfo class\fR and \fBinfo object\fR). .VE TIP516 .SH EXAMPLES This example demonstrates how to use both forms of the \fBoo::define\fR and \fBoo::objdefine\fR commands (they work in the same way), as well as illustrating four of the subcommands of them. .PP .CS oo::class create c |
︙ | ︙ |
Changes to doc/dict.n.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 | \fBdict append \fIdictionaryVariable key \fR?\fIstring ...\fR? . This appends the given string (or strings) to the value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to an empty string. The updated dictionary value is returned. .TP \fBdict create \fR?\fIkey value ...\fR? . Return a new dictionary that contains each of the key/value mappings listed as arguments (keys and values alternating, with each key being followed by its associated value.) .TP | > > > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | \fBdict append \fIdictionaryVariable key \fR?\fIstring ...\fR? . This appends the given string (or strings) to the value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to an empty string. The updated dictionary value is returned. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the appending operation. .VE TIP508 .TP \fBdict create \fR?\fIkey value ...\fR? . Return a new dictionary that contains each of the key/value mappings listed as arguments (keys and values alternating, with each key being followed by its associated value.) .TP |
︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | This adds the given increment value (an integer that defaults to 1 if not specified) to the value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to 0. It is an error to increment a value for an existing key if that value is not an integer. The updated dictionary value is returned. .TP \fBdict info \fIdictionaryValue\fR . This returns information (intended for display to people) about the given dictionary though the format of this data is dependent on the implementation of the dictionary. For dictionaries that are implemented by hash tables, it is expected that this will return the | > > > > > | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | This adds the given increment value (an integer that defaults to 1 if not specified) to the value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to 0. It is an error to increment a value for an existing key if that value is not an integer. The updated dictionary value is returned. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the incrementing operation. .VE TIP508 .TP \fBdict info \fIdictionaryValue\fR . This returns information (intended for display to people) about the given dictionary though the format of this data is dependent on the implementation of the dictionary. For dictionaries that are implemented by hash tables, it is expected that this will return the |
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | This appends the given items to the list value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to an empty list, and it is legal for there to be no items to append to the list. It is an error for the value that the key maps to to not be representable as a list. The updated dictionary value is returned. .TP \fBdict map \fR{\fIkeyVariable valueVariable\fR} \fIdictionaryValue body\fR . This command applies a transformation to each element of a dictionary, returning a new dictionary. It takes three arguments: the first is a two-element list of variable names (for the key and value respectively of each mapping in the dictionary), the second the dictionary value to iterate across, | > > > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | This appends the given items to the list value that the given key maps to in the dictionary value contained in the given variable, writing the resulting dictionary value back to that variable. Non-existent keys are treated as if they map to an empty list, and it is legal for there to be no items to append to the list. It is an error for the value that the key maps to to not be representable as a list. The updated dictionary value is returned. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the list-appending operation. .VE TIP508 .TP \fBdict map \fR{\fIkeyVariable valueVariable\fR} \fIdictionaryValue body\fR . This command applies a transformation to each element of a dictionary, returning a new dictionary. It takes three arguments: the first is a two-element list of variable names (for the key and value respectively of each mapping in the dictionary), the second the dictionary value to iterate across, |
︙ | ︙ | |||
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | \fBdict set \fIdictionaryVariable key \fR?\fIkey ...\fR? \fIvalue\fR . This operation takes the name of a variable containing a dictionary value and places an updated dictionary value in that variable containing a mapping from the given key to the given value. When multiple keys are present, this operation creates or updates a chain of nested dictionaries. The updated dictionary value is returned. .TP \fBdict size \fIdictionaryValue\fR . Return the number of key/value mappings in the given dictionary value. .TP \fBdict unset \fIdictionaryVariable key \fR?\fIkey ...\fR? . This operation (the companion to \fBdict set\fR) takes the name of a variable containing a dictionary value and places an updated dictionary value in that variable that does not contain a mapping for the given key. Where multiple keys are present, this describes a path through nested dictionaries to the mapping to remove. At least one key must be specified, but the last key on the key-path need not exist. All other components on the path must exist. The updated dictionary value is returned. .TP \fBdict update \fIdictionaryVariable key varName \fR?\fIkey varName ...\fR? \fIbody\fR . Execute the Tcl script in \fIbody\fR with the value for each \fIkey\fR (as found by reading the dictionary value in \fIdictionaryVariable\fR) mapped to the variable \fIvarName\fR. There may be multiple \fIkey\fR/\fIvarName\fR pairs. If a \fIkey\fR does not have a mapping, that corresponds to an unset \fIvarName\fR. When \fIbody\fR terminates, any changes made to the \fIvarName\fRs is reflected back to the dictionary within \fIdictionaryVariable\fR (unless \fIdictionaryVariable\fR itself becomes unreadable, when all updates are silently discarded), even if the result of \fIbody\fR is an error or some other kind of exceptional exit. The result of \fBdict update\fR is (unless some kind of error occurs) the result of the evaluation of \fIbody\fR. .RS .PP Each \fIvarName\fR is mapped in the scope enclosing the \fBdict update\fR; it is recommended that this command only be used in a local scope (\fBproc\fRedure, lambda term for \fBapply\fR, or method). Because of this, the variables set by \fBdict update\fR will continue to exist after the command finishes (unless explicitly \fBunset\fR). | > > > > > > > > > > > > > > > | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | \fBdict set \fIdictionaryVariable key \fR?\fIkey ...\fR? \fIvalue\fR . This operation takes the name of a variable containing a dictionary value and places an updated dictionary value in that variable containing a mapping from the given key to the given value. When multiple keys are present, this operation creates or updates a chain of nested dictionaries. The updated dictionary value is returned. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the value insert/update operation. .VE TIP508 .TP \fBdict size \fIdictionaryValue\fR . Return the number of key/value mappings in the given dictionary value. .TP \fBdict unset \fIdictionaryVariable key \fR?\fIkey ...\fR? . This operation (the companion to \fBdict set\fR) takes the name of a variable containing a dictionary value and places an updated dictionary value in that variable that does not contain a mapping for the given key. Where multiple keys are present, this describes a path through nested dictionaries to the mapping to remove. At least one key must be specified, but the last key on the key-path need not exist. All other components on the path must exist. The updated dictionary value is returned. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the value remove operation. .VE TIP508 .TP \fBdict update \fIdictionaryVariable key varName \fR?\fIkey varName ...\fR? \fIbody\fR . Execute the Tcl script in \fIbody\fR with the value for each \fIkey\fR (as found by reading the dictionary value in \fIdictionaryVariable\fR) mapped to the variable \fIvarName\fR. There may be multiple \fIkey\fR/\fIvarName\fR pairs. If a \fIkey\fR does not have a mapping, that corresponds to an unset \fIvarName\fR. When \fIbody\fR terminates, any changes made to the \fIvarName\fRs is reflected back to the dictionary within \fIdictionaryVariable\fR (unless \fIdictionaryVariable\fR itself becomes unreadable, when all updates are silently discarded), even if the result of \fIbody\fR is an error or some other kind of exceptional exit. The result of \fBdict update\fR is (unless some kind of error occurs) the result of the evaluation of \fIbody\fR. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the update operation. .VE TIP508 .RS .PP Each \fIvarName\fR is mapped in the scope enclosing the \fBdict update\fR; it is recommended that this command only be used in a local scope (\fBproc\fRedure, lambda term for \fBapply\fR, or method). Because of this, the variables set by \fBdict update\fR will continue to exist after the command finishes (unless explicitly \fBunset\fR). |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 278 279 | for the execution of \fIbody\fR. As with \fBdict update\fR, making \fIdictionaryVariable\fR unreadable will make the updates to the dictionary be discarded, and this also happens if the contents of \fIdictionaryVariable\fR are adjusted so that the chain of dictionaries no longer exists. The result of \fBdict with\fR is (unless some kind of error occurs) the result of the evaluation of \fIbody\fR. .RS .PP The variables are mapped in the scope enclosing the \fBdict with\fR; it is recommended that this command only be used in a local scope (\fBproc\fRedure, lambda term for \fBapply\fR, or method). Because of this, the variables set by \fBdict with\fR will continue to exist after the command finishes (unless explicitly \fBunset\fR). | > > > > > | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | for the execution of \fIbody\fR. As with \fBdict update\fR, making \fIdictionaryVariable\fR unreadable will make the updates to the dictionary be discarded, and this also happens if the contents of \fIdictionaryVariable\fR are adjusted so that the chain of dictionaries no longer exists. The result of \fBdict with\fR is (unless some kind of error occurs) the result of the evaluation of \fIbody\fR. .VS TIP508 If \fIdictionaryVarable\fR indicates an element that does not exist of an array that has a default value set, the default value and will be used as the value of the dictionary prior to the updating operation. .VE TIP508 .RS .PP The variables are mapped in the scope enclosing the \fBdict with\fR; it is recommended that this command only be used in a local scope (\fBproc\fRedure, lambda term for \fBapply\fR, or method). Because of this, the variables set by \fBdict with\fR will continue to exist after the command finishes (unless explicitly \fBunset\fR). |
︙ | ︙ |
Changes to doc/exec.n.
︙ | ︙ | |||
220 221 222 223 224 225 226 | Note that the current escape resp. quoting of arguments for windows works only with executables using CommandLineToArgv, CRT-library or similar, as well as with the windows batch files (excepting the newline, see below). Although it is the common escape algorithm, but, in fact, the way how the executable parses the command-line (resp. splits it into single arguments) is decisive. .PP | | | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | Note that the current escape resp. quoting of arguments for windows works only with executables using CommandLineToArgv, CRT-library or similar, as well as with the windows batch files (excepting the newline, see below). Although it is the common escape algorithm, but, in fact, the way how the executable parses the command-line (resp. splits it into single arguments) is decisive. .PP Unfortunately, there is currently no way to supply newline character within an argument to the batch files (\fB.cmd\fR or \fB.bat\fR) or to the command processor (\fBcmd.exe /c\fR), because this causes truncation of command-line (also the argument chain) on the first newline character. But it works properly with an executable (using CommandLineToArgv, etc). .PP The Tk console text widget does not provide real standard IO capabilities. Under Tk, when redirecting from standard input, all applications will see an immediate end-of-file; information redirected to standard output or standard error will be discarded. .PP |
︙ | ︙ |
Changes to doc/http.n.
1 2 3 4 5 6 7 8 | '\" '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-2000 by Ajuba Solutions. '\" Copyright (c) 2004 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | '\" '\" Copyright (c) 1995-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-2000 by Ajuba Solutions. '\" Copyright (c) 2004 ActiveState Corporation. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH "http" n 2.9 http "Tcl Bundled Packages" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME http \- Client-side implementation of the HTTP/1.1 protocol .SH SYNOPSIS \fBpackage require http ?2.8?\fR .\" See Also -useragent option documentation in body! .sp \fB::http::config ?\fI\-option value\fR ...? .sp \fB::http::geturl \fIurl\fR ?\fI\-option value\fR ...? .sp \fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...? .sp \fB::http::quoteString\fR \fIvalue\fR .sp \fB::http::reset\fR \fItoken\fR ?\fIwhy\fR? .sp \fB::http::wait \fItoken\fR .sp \fB::http::status \fItoken\fR .sp |
︙ | ︙ | |||
142 143 144 145 146 147 148 | retrying the POST. The value \fBtrue\fR should be used only under certain conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The default is 0. .TP \fB\-urlencoding\fR \fIencoding\fR . The \fIencoding\fR used for creating the x-url-encoded URLs with | > | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | retrying the POST. The value \fBtrue\fR should be used only under certain conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The default is 0. .TP \fB\-urlencoding\fR \fIencoding\fR . The \fIencoding\fR used for creating the x-url-encoded URLs with \fB::http::formatQuery\fR and \fB::http::quoteString\fR. The default is \fButf-8\fR, as specified by RFC 2718. Prior to http 2.5 this was unspecified, and that behavior can be returned by specifying the empty string (\fB{}\fR), although \fIiso8859-1\fR is recommended to restore similar behavior but without the \fB::http::formatQuery\fR or \fB::http::quoteString\fR throwing an error processing non-latin-1 characters. .TP \fB\-useragent\fR \fIstring\fR . The value of the User-Agent header in the HTTP request. In an unsafe interpreter, the default value depends upon the operating system, and the version numbers of \fBhttp\fR and \fBTcl\fR, and is (for example) .QW "\fBMozilla/5.0 (Windows; U; Windows NT 10.0) http/2.8.12 Tcl/8.6.8\fR" . |
︙ | ︙ | |||
370 371 372 373 374 375 376 377 378 379 380 381 382 383 | \fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...? . This procedure does x-url-encoding of query data. It takes an even number of arguments that are the keys and values of the query. It encodes the keys and values, and generates one string that has the proper & and = separators. The result is suitable for the \fB\-query\fR value passed to \fB::http::geturl\fR. .TP \fB::http::reset\fR \fItoken\fR ?\fIwhy\fR? . This command resets the HTTP transaction identified by \fItoken\fR, if any. This sets the \fBstate(status)\fR value to \fIwhy\fR, which defaults to \fBreset\fR, and then calls the registered \fB\-command\fR callback. .TP | > > > > > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | \fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...? . This procedure does x-url-encoding of query data. It takes an even number of arguments that are the keys and values of the query. It encodes the keys and values, and generates one string that has the proper & and = separators. The result is suitable for the \fB\-query\fR value passed to \fB::http::geturl\fR. .TP \fB::http::quoteString\fR \fIvalue\fR . This procedure does x-url-encoding of string. It takes a single argument and encodes it. .TP \fB::http::reset\fR \fItoken\fR ?\fIwhy\fR? . This command resets the HTTP transaction identified by \fItoken\fR, if any. This sets the \fBstate(status)\fR value to \fIwhy\fR, which defaults to \fBreset\fR, and then calls the registered \fB\-command\fR callback. .TP |
︙ | ︙ | |||
751 752 753 754 755 756 757 | delivered, and will not be sent if the POST fails. .PP Option \fB-postfresh\fR, if boolean \fBtrue\fR, will override the \fBhttp::geturl\fR option \fB-keepalive\fR, and always open a fresh connection for a POST request. .PP Option \fB-repost\fR, if \fBtrue\fR, permits automatic retry of a POST request that fails because it uses a persistent connection that the server has | | | 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | delivered, and will not be sent if the POST fails. .PP Option \fB-postfresh\fR, if boolean \fBtrue\fR, will override the \fBhttp::geturl\fR option \fB-keepalive\fR, and always open a fresh connection for a POST request. .PP Option \fB-repost\fR, if \fBtrue\fR, permits automatic retry of a POST request that fails because it uses a persistent connection that the server has half-closed (an .QW "asynchronous close event" ). Subsequent GET and HEAD requests in a failed pipeline will also be retried. \fIThe -repost option should be used only if the application understands that the retry is appropriate\fR - specifically, the application must know that if the failed POST successfully modified the state of the server, a repeat POST would have no adverse effect. .SH EXAMPLE |
︙ | ︙ |
Changes to doc/incr.n.
︙ | ︙ | |||
23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 1 is added to \fIvarName\fR. The new value is stored as a decimal string in variable \fIvarName\fR and also returned as result. .PP Starting with the Tcl 8.5 release, the variable \fIvarName\fR passed to \fBincr\fR may be unset, and in that case, it will be set to the value \fIincrement\fR or to the default increment value of \fB1\fR. .SH EXAMPLES .PP Add one to the contents of the variable \fIx\fR: .PP .CS \fBincr\fR x .CE | > > > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 1 is added to \fIvarName\fR. The new value is stored as a decimal string in variable \fIvarName\fR and also returned as result. .PP Starting with the Tcl 8.5 release, the variable \fIvarName\fR passed to \fBincr\fR may be unset, and in that case, it will be set to the value \fIincrement\fR or to the default increment value of \fB1\fR. .VS TIP508 If \fIvarName\fR indicate an element that does not exist of an array that has a default value set, the sum of the default value and the \fIincrement\fR (or 1) will be stored in the array element. .VE TIP508 .SH EXAMPLES .PP Add one to the contents of the variable \fIx\fR: .PP .CS \fBincr\fR x .CE |
︙ | ︙ | |||
55 56 57 58 59 60 61 | .CS \fBincr\fR x 0 .CE .SH "SEE ALSO" expr(n), set(n) .SH KEYWORDS add, increment, variable, value | > > > > | 60 61 62 63 64 65 66 67 68 69 70 | .CS \fBincr\fR x 0 .CE .SH "SEE ALSO" expr(n), set(n) .SH KEYWORDS add, increment, variable, value .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/info.n.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | Returns information about the class, \fIclass\fR. The \fIsubcommand\fRs are described in \fBCLASS INTROSPECTION\fR below. .TP \fBinfo cmdcount\fR . Returns a count of the total number of commands that have been invoked in this interpreter. .TP \fBinfo commands \fR?\fIpattern\fR? . If \fIpattern\fR is not specified, returns a list of names of all the Tcl commands visible (i.e. executable without using a qualified name) to the current namespace, including both the built-in commands written in C and | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | Returns information about the class, \fIclass\fR. The \fIsubcommand\fRs are described in \fBCLASS INTROSPECTION\fR below. .TP \fBinfo cmdcount\fR . Returns a count of the total number of commands that have been invoked in this interpreter. .TP \fBinfo cmdtype \fIcommandName\fR .VS TIP426 Returns a description of the kind of command named by \fIcommandName\fR. The supported types are: .RS .IP \fBalias\fR Indicates that \fIcommandName\fR was created by \fBinterp alias\fR. Note that safe interpreters can only see a subset of aliases (specifically those between two commands within themselves). .IP \fBcoroutine\fR Indicates that \fIcommandName\fR was created by \fBcoroutine\fR. .IP \fBensemble\fR Indicates that \fIcommandName\fR was created by \fBnamespace ensemble\fR. .IP \fBimport\fR Indicates that \fIcommandName\fR was created by \fBnamespace import\fR. .IP \fBnative\fR Indicates that \fIcommandName\fR was created by the \fBTcl_CreateObjProc\fR interface directly without further registration of the type of command. .IP \fBobject\fR Indicates that \fIcommandName\fR is the public command that represents an instance of \fBoo::object\fR or one of its subclasses. .IP \fBprivateObject\fR Indicates that \fIcommandName\fR is the private command (\fBmy\fR by default) that represents an instance of \fBoo::object\fR or one of its subclasses. .IP \fBproc\fR Indicates that \fIcommandName\fR was created by \fBproc\fR. .IP \fBslave\fR Indicates that \fIcommandName\fR was created by \fBinterp create\fR. .IP \fBzlibStream\fR Indicates that \fIcommandName\fR was created by \fBzlib stream\fR. .PP There may be other registered types as well; this is a set that is extensible at the implementation level with \fBTcl_RegisterCommandTypeName\fR. .RE .VE TIP426 .TP \fBinfo commands \fR?\fIpattern\fR? . If \fIpattern\fR is not specified, returns a list of names of all the Tcl commands visible (i.e. executable without using a qualified name) to the current namespace, including both the built-in commands written in C and |
︙ | ︙ |
Changes to doc/lappend.n.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | .SH DESCRIPTION .PP This command treats the variable given by \fIvarName\fR as a list and appends each of the \fIvalue\fR arguments to that list as a separate element, with spaces between elements. If \fIvarName\fR does not exist, it is created as a list with elements given by the \fIvalue\fR arguments. \fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs are appended as list elements rather than raw text. This command provides a relatively efficient way to build up large lists. For example, .QW "\fBlappend a $b\fR" is much more efficient than .QW "\fBset a [concat $a [list $b]]\fR" | > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | .SH DESCRIPTION .PP This command treats the variable given by \fIvarName\fR as a list and appends each of the \fIvalue\fR arguments to that list as a separate element, with spaces between elements. If \fIvarName\fR does not exist, it is created as a list with elements given by the \fIvalue\fR arguments. .VS TIP508 If \fIvarName\fR indicate an element that does not exist of an array that has a default value set, list that is comprised of the default value with all the \fIvalue\fR arguments appended as elements will be stored in the array element. .VE TIP508 \fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs are appended as list elements rather than raw text. This command provides a relatively efficient way to build up large lists. For example, .QW "\fBlappend a $b\fR" is much more efficient than .QW "\fBset a [concat $a [list $b]]\fR" |
︙ | ︙ | |||
43 44 45 46 47 48 49 | 1 2 3 4 5 .CE .SH "SEE ALSO" list(n), lindex(n), linsert(n), llength(n), lset(n), lsort(n), lrange(n) .SH KEYWORDS append, element, list, variable | > > > > | 49 50 51 52 53 54 55 56 57 58 59 | 1 2 3 4 5 .CE .SH "SEE ALSO" list(n), lindex(n), linsert(n), llength(n), lset(n), lsort(n), lrange(n) .SH KEYWORDS append, element, list, variable .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/lreplace.n.
︙ | ︙ | |||
26 27 28 29 30 31 32 | supporting simple index arithmetic and indices relative to the end of the list. 0 refers to the first element of the list, and \fBend\fR refers to the last element of the list. If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored. .PP If \fIfirst\fR is less than zero, it is considered to refer to before the | | > > > > > > | > > > > > > > | 26 27 28 29 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 | supporting simple index arithmetic and indices relative to the end of the list. 0 refers to the first element of the list, and \fBend\fR refers to the last element of the list. If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored. .PP If \fIfirst\fR is less than zero, it is considered to refer to before the first element of the list. .VS TIP505 If \fIfirst\fR indicates a position greater than the index of the last element of the list, it is treated as if it is an index one greater than the last element. This allows this command to append elements to the list. .VE TIP505 For non-empty lists, the element indicated by \fIfirst\fR must exist, or \fIfirst\fR must indicate before the start of the list. .PP If \fIlast\fR is less than \fIfirst\fR, then any specified elements will be inserted into the list before the point specified by \fIfirst\fR with no elements being deleted. .VS TIP505 If \fIlast\fR is greater than the index of the last item of the list, it is treated as if it is an index one greater than the last element. This means that if it is also greater than than \fIfirst\fR, all elements from \fIfirst\fR to the end of the list will be replaced, and otherwise the elements will be appended. .VE TIP505 .PP The \fIelement\fR arguments specify zero or more new arguments to be added to the list in place of those that were deleted. Each \fIelement\fR argument will become a separate element of the list. If no \fIelement\fR arguments are specified, then the elements between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR is empty, any \fIelement\fR arguments are added to the end of the list. |
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 | .CS proc lremove {listVariable value} { upvar 1 $listVariable var set idx [lsearch -exact $var $value] set var [\fBlreplace\fR $var $idx $idx] } .CE .SH "SEE ALSO" list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lrange(n), lsort(n), string(n) .SH KEYWORDS element, list, replace | > > > > > > > > > > > > > > > > > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | .CS proc lremove {listVariable value} { upvar 1 $listVariable var set idx [lsearch -exact $var $value] set var [\fBlreplace\fR $var $idx $idx] } .CE .PP .VS TIP505 Adding elements to the end of the list; note that \fBend+2\fR will initially be treated as if it is \fB6\fR here, but both that and \fB12345\fR are greater than the index of the final item so they behave identically: .PP .CS % set var {a b c d e} a b c d e % set var [\fBlreplace\fR $var 12345 end+2 f g h i] a b c d e f g h i .CE .VE TIP505 .SH "SEE ALSO" list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n), lset(n), lrange(n), lsort(n), string(n) .SH KEYWORDS element, list, replace .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/zipfs.3.
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | .SH DESCRIPTION \fBTclZipfs_AppHook()\fR is a utility function to perform standard application initialization procedures. If the current application has a mountable zip file system, that file system is mounted under \fIZIPROOT\fR\fB/app\fR. If a file named \fBmain.tcl\fR is located in that file system, it is treated as the startup script for the process. If the file \fIZIPROOT\fR\fB/app/tcl_library/init.tcl\fR is present, \fBtcl_library\fR is set to \fIZIPROOT\fR\fB/app/tcl_library. .PP If the \fBtcl_library\fR was not found in the application, the system will then search for it as either a VFS attached to the application dynamic library, or as a zip archive named libtcl_\fIMAJOR\fR_\fIMINOR\fR_\fIpatchLevel\fR.zip either in the present working directory or in the standard tcl install location. .PP \fBTclzipfs_Mount()\fR mount the ZIP archive \fIzipname\fR on the mount | > > > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | .SH DESCRIPTION \fBTclZipfs_AppHook()\fR is a utility function to perform standard application initialization procedures. If the current application has a mountable zip file system, that file system is mounted under \fIZIPROOT\fR\fB/app\fR. If a file named \fBmain.tcl\fR is located in that file system, it is treated as the startup script for the process. If the file \fIZIPROOT\fR\fB/app/tcl_library/init.tcl\fR is present, \fBtcl_library\fR is set to \fIZIPROOT\fR\fB/app/tcl_library. .PP On Windows, \fBTclZipfs_AppHook()\fR has a slightly different signature, it uses WCHAR in stead of char. As a result, it only works if your application is compiled using -DUNICODE. .PP If the \fBtcl_library\fR was not found in the application, the system will then search for it as either a VFS attached to the application dynamic library, or as a zip archive named libtcl_\fIMAJOR\fR_\fIMINOR\fR_\fIpatchLevel\fR.zip either in the present working directory or in the standard tcl install location. .PP \fBTclzipfs_Mount()\fR mount the ZIP archive \fIzipname\fR on the mount |
︙ | ︙ |
Changes to generic/tcl.decls.
︙ | ︙ | |||
2361 2362 2363 2364 2365 2366 2367 | # available on the designated platform. interface tclPlat ################################ # Unix specific functions # (none) | < < < < < | | 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 | # available on the designated platform. interface tclPlat ################################ # Unix specific functions # (none) ################################ # Windows specific functions # Added in Tcl 8.1 declare 0 win { TCHAR *Tcl_WinUtfToTChar(const char *str, int len, Tcl_DString *dsPtr) } declare 1 win { char *Tcl_WinTCharToUtf(const TCHAR *str, int len, Tcl_DString *dsPtr) } ################################ # Mac OS X specific functions declare 0 macosx { int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath) |
︙ | ︙ |
Changes to generic/tcl.h.
︙ | ︙ | |||
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 | #define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ (((Tcl_SetPanicProc)(Tcl_ConsolePanic), Tcl_CreateInterp)())) EXTERN void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, const char *version, int exact); EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); /* *---------------------------------------------------------------------------- * Include the public function declarations that are accessible via the stubs * table. */ | > > > | 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 | #define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \ (((Tcl_SetPanicProc)(Tcl_ConsolePanic), Tcl_CreateInterp)())) EXTERN void Tcl_MainEx(int argc, char **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); EXTERN const char * Tcl_PkgInitStubsCheck(Tcl_Interp *interp, const char *version, int exact); EXTERN void Tcl_GetMemoryInfo(Tcl_DString *dsPtr); #ifndef _WIN32 EXTERN int TclZipfs_AppHook(int *argc, char ***argv); #endif /* *---------------------------------------------------------------------------- * Include the public function declarations that are accessible via the stubs * table. */ |
︙ | ︙ |
Changes to generic/tclBasic.c.
︙ | ︙ | |||
67 68 69 70 71 72 73 | * a default result. */ int length; /* Length of the above error message. */ ClientData clientData; /* Ignored */ int flags; /* Additional flags */ } CancelInfo; static Tcl_HashTable cancelTable; static int cancelTableInitialized = 0; /* 0 means not yet initialized. */ | | > > > > > > > > > > > | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | * a default result. */ int length; /* Length of the above error message. */ ClientData clientData; /* Ignored */ int flags; /* Additional flags */ } CancelInfo; static Tcl_HashTable cancelTable; static int cancelTableInitialized = 0; /* 0 means not yet initialized. */ TCL_DECLARE_MUTEX(cancelLock); /* * Table used to map command implementation functions to a human-readable type * name, for [info type]. The keys in the table are function addresses, and * the values in the table are static char* containing strings in Tcl's * internal encoding (almost UTF-8). */ static Tcl_HashTable commandTypeTable; static int commandTypeInit = 0; TCL_DECLARE_MUTEX(commandTypeLock); /* * Declarations for managing contexts for non-recursive coroutines. Contexts * are used to save the evaluation state between NR calls to each coro. */ #define SAVE_CONTEXT(context) \ |
︙ | ︙ | |||
426 427 428 429 430 431 432 433 434 435 436 437 438 439 | { Tcl_MutexLock(&cancelLock); if (cancelTableInitialized == 1) { Tcl_DeleteHashTable(&cancelTable); cancelTableInitialized = 0; } Tcl_MutexUnlock(&cancelLock); } /* *---------------------------------------------------------------------- * * Tcl_CreateInterp -- * | > > > > > > > | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | { Tcl_MutexLock(&cancelLock); if (cancelTableInitialized == 1) { Tcl_DeleteHashTable(&cancelTable); cancelTableInitialized = 0; } Tcl_MutexUnlock(&cancelLock); Tcl_MutexLock(&commandTypeLock); if (commandTypeInit) { Tcl_DeleteHashTable(&commandTypeTable); commandTypeInit = 0; } Tcl_MutexUnlock(&commandTypeLock); } /* *---------------------------------------------------------------------- * * Tcl_CreateInterp -- * |
︙ | ︙ | |||
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | if (cancelTableInitialized == 0) { Tcl_MutexLock(&cancelLock); if (cancelTableInitialized == 0) { Tcl_InitHashTable(&cancelTable, TCL_ONE_WORD_KEYS); cancelTableInitialized = 1; } Tcl_MutexUnlock(&cancelLock); } /* * Initialize support for namespaces and create the global namespace * (whose name is ""; an alias is "::"). This also initializes the Tcl * object type table and other object management code. */ | > > > > > > > > > > > > > > | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | if (cancelTableInitialized == 0) { Tcl_MutexLock(&cancelLock); if (cancelTableInitialized == 0) { Tcl_InitHashTable(&cancelTable, TCL_ONE_WORD_KEYS); cancelTableInitialized = 1; } Tcl_MutexUnlock(&cancelLock); } if (commandTypeInit == 0) { TclRegisterCommandTypeName(TclObjInterpProc, "proc"); TclRegisterCommandTypeName(TclEnsembleImplementationCmd, "ensemble"); TclRegisterCommandTypeName(TclAliasObjCmd, "alias"); TclRegisterCommandTypeName(TclLocalAliasObjCmd, "alias"); TclRegisterCommandTypeName(TclSlaveObjCmd, "slave"); TclRegisterCommandTypeName(TclInvokeImportedCmd, "import"); TclRegisterCommandTypeName(TclOOPublicObjectCmd, "object"); TclRegisterCommandTypeName(TclOOPrivateObjectCmd, "privateObject"); TclRegisterCommandTypeName(TclOOMyClassObjCmd, "privateClass"); TclRegisterCommandTypeName(TclNRInterpCoroutine, "coroutine"); } /* * Initialize support for namespaces and create the global namespace * (whose name is ""; an alias is "::"). This also initializes the Tcl * object type table and other object management code. */ |
︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 | DeleteOpCmdClientData( ClientData clientData) { TclOpCmdClientData *occdPtr = clientData; ckfree(occdPtr); } /* *---------------------------------------------------------------------- * * TclHideUnsafeCommands -- * * Hides base commands that are not marked as safe from this interpreter. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | DeleteOpCmdClientData( ClientData clientData) { TclOpCmdClientData *occdPtr = clientData; ckfree(occdPtr); } /* * --------------------------------------------------------------------- * * TclRegisterCommandTypeName, TclGetCommandTypeName -- * * Command type registration and lookup mechanism. Everything is keyed by * the Tcl_ObjCmdProc for the command, and that is used as the *key* into * the hash table that maps to constant strings that are names. (It is * recommended that those names be ASCII.) * * --------------------------------------------------------------------- */ void TclRegisterCommandTypeName( Tcl_ObjCmdProc *implementationProc, const char *nameStr) { Tcl_HashEntry *hPtr; Tcl_MutexLock(&commandTypeLock); if (commandTypeInit == 0) { Tcl_InitHashTable(&commandTypeTable, TCL_ONE_WORD_KEYS); commandTypeInit = 1; } if (nameStr != NULL) { int isNew; hPtr = Tcl_CreateHashEntry(&commandTypeTable, (void *) implementationProc, &isNew); Tcl_SetHashValue(hPtr, (void *) nameStr); } else { hPtr = Tcl_FindHashEntry(&commandTypeTable, (void *) implementationProc); if (hPtr != NULL) { Tcl_DeleteHashEntry(hPtr); } } Tcl_MutexUnlock(&commandTypeLock); } const char * TclGetCommandTypeName( Tcl_Command command) { Command *cmdPtr = (Command *) command; void *procPtr = cmdPtr->objProc; const char *name = "native"; if (procPtr == NULL) { procPtr = cmdPtr->nreProc; } Tcl_MutexLock(&commandTypeLock); if (commandTypeInit) { Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&commandTypeTable, procPtr); if (hPtr && Tcl_GetHashValue(hPtr)) { name = (const char *) Tcl_GetHashValue(hPtr); } } Tcl_MutexUnlock(&commandTypeLock); return name; } /* *---------------------------------------------------------------------- * * TclHideUnsafeCommands -- * * Hides base commands that are not marked as safe from this interpreter. |
︙ | ︙ |
Changes to generic/tclCmdIL.c.
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | static int InfoPatchLevelCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoProcsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoScriptCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoSharedlibCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoTclVersionCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static SortElement * MergeLists(SortElement *leftPtr, SortElement *rightPtr, SortInfo *infoPtr); static int SortCompare(SortElement *firstPtr, SortElement *second, SortInfo *infoPtr); static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr, SortInfo *infoPtr); /* * Array of values describing how to implement each standard subcommand of the * "info" command. */ static const EnsembleImplMap defaultInfoMap[] = { {"args", InfoArgsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"body", InfoBodyCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"cmdcount", InfoCmdCountCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0}, {"complete", InfoCompleteCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0}, {"default", InfoDefaultCmd, TclCompileBasic3ArgCmd, NULL, NULL, 0}, {"errorstack", InfoErrorStackCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0}, {"frame", InfoFrameCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, | > > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | static int InfoPatchLevelCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoProcsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoScriptCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoSharedlibCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoCmdTypeCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int InfoTclVersionCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static SortElement * MergeLists(SortElement *leftPtr, SortElement *rightPtr, SortInfo *infoPtr); static int SortCompare(SortElement *firstPtr, SortElement *second, SortInfo *infoPtr); static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr, SortInfo *infoPtr); /* * Array of values describing how to implement each standard subcommand of the * "info" command. */ static const EnsembleImplMap defaultInfoMap[] = { {"args", InfoArgsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"body", InfoBodyCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"cmdcount", InfoCmdCountCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, {"cmdtype", InfoCmdTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0}, {"complete", InfoCompleteCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0}, {"default", InfoDefaultCmd, TclCompileBasic3ArgCmd, NULL, NULL, 0}, {"errorstack", InfoErrorStackCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0}, {"frame", InfoFrameCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, |
︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 | } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tcl_JoinObjCmd -- * * This procedure is invoked to process the "join" Tcl command. See the * user documentation for details on what it does. * * Results: * A standard Tcl object result. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 | } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InfoCmdTypeCmd -- * * Called to implement the "info cmdtype" command that returns the type * of a given command. Handles the following syntax: * * info cmdtype cmdName * * Results: * Returns TCL_OK if successful and TCL_ERROR if there is an error. * * Side effects: * Returns a type name. If there is an error, the result is an error * message. * *---------------------------------------------------------------------- */ static int InfoCmdTypeCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Command command; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "commandName"); return TCL_ERROR; } command = Tcl_FindCommand(interp, Tcl_GetString(objv[1]), NULL, TCL_LEAVE_ERR_MSG); if (command == NULL) { return TCL_ERROR; } /* * There's one special case: safe slave interpreters can't see aliases as * aliases as they're part of the security mechanisms. */ if (Tcl_IsSafe(interp) && (((Command *) command)->objProc == TclAliasObjCmd)) { Tcl_AppendResult(interp, "native", NULL); } else { Tcl_SetObjResult(interp, Tcl_NewStringObj(TclGetCommandTypeName(command), -1)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tcl_JoinObjCmd -- * * This procedure is invoked to process the "join" Tcl command. See the * user documentation for details on what it does. * * Results: * A standard Tcl object result. |
︙ | ︙ | |||
2726 2727 2728 2729 2730 2731 2732 | if (result != TCL_OK) { return result; } if (first < 0) { first = 0; } | | < < < | < < | < < < < < < | | 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 | if (result != TCL_OK) { return result; } if (first < 0) { first = 0; } if (first > listLen) { first = listLen; } if (last >= listLen) { last = listLen - 1; } if (first <= last) { numToDelete = last - first + 1; } else { numToDelete = 0; |
︙ | ︙ |
Changes to generic/tclCompCmdsGR.c.
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | * command. */ Command *cmdPtr, /* Points to defintion of command being * compiled. */ CompileEnv *envPtr) /* Holds the resulting instructions. */ { Tcl_Token *tokenPtr, *listTokenPtr; DefineLineInformation; /* TIP #280 */ | | < < < < < < < < < < < < < < < < < > > | | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | * command. */ Command *cmdPtr, /* Points to defintion of command being * compiled. */ CompileEnv *envPtr) /* Holds the resulting instructions. */ { Tcl_Token *tokenPtr, *listTokenPtr; DefineLineInformation; /* TIP #280 */ int idx1, idx2, i; int emptyPrefix=1, suffixStart = 0; if (parsePtr->numWords < 4) { return TCL_ERROR; } listTokenPtr = TokenAfter(parsePtr->tokenPtr); tokenPtr = TokenAfter(listTokenPtr); if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER, &idx1) != TCL_OK) { return TCL_ERROR; } tokenPtr = TokenAfter(tokenPtr); if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END, &idx2) != TCL_OK) { return TCL_ERROR; } /* * General structure of the [lreplace] result is * prefix replacement suffix * In a few cases we can predict various parts will be empty and * take advantage. * * The proper suffix begins with the greater of indices idx1 or * idx2 + 1. If we cannot tell at compile time which is greater, * we must defer to direct evaluation. */ if (idx1 == TCL_INDEX_AFTER) { suffixStart = idx1; } else if (idx2 == TCL_INDEX_BEFORE) { suffixStart = idx1; } else if (idx2 == TCL_INDEX_END) { suffixStart = TCL_INDEX_AFTER; } else if (((idx2 < TCL_INDEX_END) && (idx1 <= TCL_INDEX_END)) || ((idx2 >= TCL_INDEX_START) && (idx1 >= TCL_INDEX_START))) { suffixStart = (idx1 > idx2 + 1) ? idx1 : idx2 + 1; } else { |
︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 | /* Make a list of them... */ TclEmitInstInt4( INST_LIST, i - 4, envPtr); emptyPrefix = 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 | /* Make a list of them... */ TclEmitInstInt4( INST_LIST, i - 4, envPtr); emptyPrefix = 0; } if ((idx1 == suffixStart) && (parsePtr->numWords == 4)) { /* * This is a "no-op". Example: [lreplace {a b c} 2 0] * We still do a list operation to get list-verification * and canonicalization side effects. */ TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr); |
︙ | ︙ |
Changes to generic/tclDecls.h.
︙ | ︙ | |||
3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 | #endif #if defined(_WIN32) && defined(UNICODE) # define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) # define Tcl_MainEx Tcl_MainExW EXTERN void Tcl_MainExW(int argc, wchar_t **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); #endif #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #undef Tcl_SeekOld #undef Tcl_TellOld | > | 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 | #endif #if defined(_WIN32) && defined(UNICODE) # define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg))) # define Tcl_MainEx Tcl_MainExW EXTERN void Tcl_MainExW(int argc, wchar_t **argv, Tcl_AppInitProc *appInitProc, Tcl_Interp *interp); EXTERN int TclZipfs_AppHook(int *argc, wchar_t ***argv); #endif #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #undef Tcl_SeekOld #undef Tcl_TellOld |
︙ | ︙ |
Changes to generic/tclEnsemble.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | * Declarations for functions local to this file: */ static inline Tcl_Obj * NewNsObj(Tcl_Namespace *namespacePtr); static inline int EnsembleUnknownCallback(Tcl_Interp *interp, EnsembleConfig *ensemblePtr, int objc, Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr); | < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | * Declarations for functions local to this file: */ static inline Tcl_Obj * NewNsObj(Tcl_Namespace *namespacePtr); static inline int EnsembleUnknownCallback(Tcl_Interp *interp, EnsembleConfig *ensemblePtr, int objc, Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr); static int NsEnsembleImplementationCmdNR(ClientData clientData, Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); static void BuildEnsembleConfig(EnsembleConfig *ensemblePtr); static int NsEnsembleStringOrder(const void *strPtr1, const void *strPtr2); static void DeleteEnsembleConfig(ClientData clientData); static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr, |
︙ | ︙ | |||
660 661 662 663 664 665 666 | { Namespace *nsPtr = (Namespace *) ensembleNsPtr; EnsembleConfig *ensemblePtr; Tcl_Command token; ensemblePtr = ckalloc(sizeof(EnsembleConfig)); token = TclNRCreateCommandInNs(interp, name, | | | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | { Namespace *nsPtr = (Namespace *) ensembleNsPtr; EnsembleConfig *ensemblePtr; Tcl_Command token; ensemblePtr = ckalloc(sizeof(EnsembleConfig)); token = TclNRCreateCommandInNs(interp, name, (Tcl_Namespace *) nameNsPtr, TclEnsembleImplementationCmd, NsEnsembleImplementationCmdNR, ensemblePtr, DeleteEnsembleConfig); if (token == NULL) { ckfree(ensemblePtr); return NULL; } ensemblePtr->nsPtr = nsPtr; |
︙ | ︙ | |||
764 765 766 767 768 769 770 | Tcl_Command token, Tcl_Obj *subcmdList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; | | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | Tcl_Command token, Tcl_Obj *subcmdList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (subcmdList != NULL) { int length; |
︙ | ︙ | |||
840 841 842 843 844 845 846 | Tcl_Obj *paramList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; int length; | | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 | Tcl_Obj *paramList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; int length; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (paramList == NULL) { length = 0; |
︙ | ︙ | |||
916 917 918 919 920 921 922 | Tcl_Command token, Tcl_Obj *mapDict) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldDict; | | | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | Tcl_Command token, Tcl_Obj *mapDict) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldDict; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (mapDict != NULL) { int size, done; |
︙ | ︙ | |||
1015 1016 1017 1018 1019 1020 1021 | Tcl_Command token, Tcl_Obj *unknownList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; | | | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | Tcl_Command token, Tcl_Obj *unknownList) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; Tcl_Obj *oldList; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (unknownList != NULL) { int length; |
︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 | Tcl_Command token, int flags) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; int wasCompiled; | | | 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 | Tcl_Command token, int flags) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; int wasCompiled; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } ensemblePtr = cmdPtr->objClientData; |
︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **paramListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1282 1283 1284 1285 1286 1287 1288 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 | Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 | Tcl_Interp *interp, Tcl_Command token, int *flagsPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 | Tcl_Interp *interp, Tcl_Command token, int *flagsPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 | Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; | | | 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 | Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr) { Command *cmdPtr = (Command *) token; EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != TclEnsembleImplementationCmd) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "command is not an ensemble", -1)); Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } |
︙ | ︙ | |||
1414 1415 1416 1417 1418 1419 1420 | cmdPtr = (Command *) Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags); if (cmdPtr == NULL) { return NULL; } | | | > | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 | cmdPtr = (Command *) Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags); if (cmdPtr == NULL) { return NULL; } if (cmdPtr->objProc != TclEnsembleImplementationCmd) { /* * Reuse existing infrastructure for following import link chains * rather than duplicating it. */ cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); if (cmdPtr == NULL || cmdPtr->objProc != TclEnsembleImplementationCmd) { if (flags & TCL_LEAVE_ERR_MSG) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "\"%s\" is not an ensemble command", TclGetString(cmdNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE", TclGetString(cmdNameObj), NULL); } |
︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 | int Tcl_IsEnsemble( Tcl_Command token) { Command *cmdPtr = (Command *) token; | | | | 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 | int Tcl_IsEnsemble( Tcl_Command token) { Command *cmdPtr = (Command *) token; if (cmdPtr->objProc == TclEnsembleImplementationCmd) { return 1; } cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); if (cmdPtr == NULL || cmdPtr->objProc != TclEnsembleImplementationCmd) { return 0; } return 1; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1635 1636 1637 1638 1639 1640 1641 | } return ensemble; } /* *---------------------------------------------------------------------- * | | | | | 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 | } return ensemble; } /* *---------------------------------------------------------------------- * * TclEnsembleImplementationCmd -- * * Implements an ensemble of commands (being those exported by a * namespace other than the global namespace) as a command with the same * (short) name as the namespace in the parent namespace. * * Results: * A standard Tcl result code. Will be TCL_ERROR if the command is not an * unambiguous prefix of any command exported by the ensemble's * namespace. * * Side effects: * Depends on the command within the namespace that gets executed. If the * ensemble itself returns TCL_ERROR, a descriptive error message will be * placed in the interpreter's result. * *---------------------------------------------------------------------- */ int TclEnsembleImplementationCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { return Tcl_NRCallObjProc(interp, NsEnsembleImplementationCmdNR, clientData, objc, objv); |
︙ | ︙ |
Changes to generic/tclExecute.c.
︙ | ︙ | |||
4066 4067 4068 4069 4070 4071 4072 | "variable isn't array", opnd); DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); CACHE_STACK_INFO(); TRACE_ERROR(interp); goto gotError; } | | < < < | 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 | "variable isn't array", opnd); DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); CACHE_STACK_INFO(); TRACE_ERROR(interp); goto gotError; } TclInitArrayVar(varPtr); #ifdef TCL_COMPILE_DEBUG TRACE_APPEND(("done\n")); } else { TRACE_APPEND(("nothing to do\n")); #endif } NEXT_INST_V(pcAdjustment, cleanup, 0); |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 | int *clNextOuter, const char *outerScript); MODULE_SCOPE int TclTrim(const char *bytes, int numBytes, const char *trim, int numTrim, int *trimRight); MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes, const char *trim, int numTrim); MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes, const char *trim, int numTrim); MODULE_SCOPE int TclUtfCmp(const char *cs, const char *ct); MODULE_SCOPE int TclUtfCasecmp(const char *cs, const char *ct); MODULE_SCOPE int TclUtfCount(int ch); MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, | > > > > | 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 | int *clNextOuter, const char *outerScript); MODULE_SCOPE int TclTrim(const char *bytes, int numBytes, const char *trim, int numTrim, int *trimRight); MODULE_SCOPE int TclTrimLeft(const char *bytes, int numBytes, const char *trim, int numTrim); MODULE_SCOPE int TclTrimRight(const char *bytes, int numBytes, const char *trim, int numTrim); MODULE_SCOPE const char*TclGetCommandTypeName(Tcl_Command command); MODULE_SCOPE void TclRegisterCommandTypeName( Tcl_ObjCmdProc *implementationProc, const char *nameStr); MODULE_SCOPE int TclUtfCmp(const char *cs, const char *ct); MODULE_SCOPE int TclUtfCasecmp(const char *cs, const char *ct); MODULE_SCOPE int TclUtfCount(int ch); MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, |
︙ | ︙ | |||
4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 | MODULE_SCOPE int TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr); MODULE_SCOPE void TclFreeObjEntry(Tcl_HashEntry *hPtr); MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr); MODULE_SCOPE int TclFullFinalizationRequested(void); /* * TIP #462. */ /* * The following enum values give the status of a spawned process. */ | > > > > > > > > > > > > > | 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 | MODULE_SCOPE int TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr); MODULE_SCOPE void TclFreeObjEntry(Tcl_HashEntry *hPtr); MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr); MODULE_SCOPE int TclFullFinalizationRequested(void); /* * Just for the purposes of command-type registration. */ MODULE_SCOPE Tcl_ObjCmdProc TclEnsembleImplementationCmd; MODULE_SCOPE Tcl_ObjCmdProc TclAliasObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclLocalAliasObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclSlaveObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInvokeImportedCmd; MODULE_SCOPE Tcl_ObjCmdProc TclOOPublicObjectCmd; MODULE_SCOPE Tcl_ObjCmdProc TclOOPrivateObjectCmd; MODULE_SCOPE Tcl_ObjCmdProc TclOOMyClassObjCmd; /* * TIP #462. */ /* * The following enum values give the status of a spawned process. */ |
︙ | ︙ | |||
4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 | MODULE_SCOPE Tcl_Command TclInitProcessCmd(Tcl_Interp *interp); MODULE_SCOPE void TclProcessCreated(Tcl_Pid pid); MODULE_SCOPE TclProcessWaitStatus TclProcessWait(Tcl_Pid pid, int options, int *codePtr, Tcl_Obj **msgObjPtr, Tcl_Obj **errorObjPtr); /* * Utility routines for encoding index values as integers. Used by both * some of the command compilers and by [lsort] and [lsearch]. */ MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr, int before, int after, int *indexPtr); | > > > > > > > | 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 | MODULE_SCOPE Tcl_Command TclInitProcessCmd(Tcl_Interp *interp); MODULE_SCOPE void TclProcessCreated(Tcl_Pid pid); MODULE_SCOPE TclProcessWaitStatus TclProcessWait(Tcl_Pid pid, int options, int *codePtr, Tcl_Obj **msgObjPtr, Tcl_Obj **errorObjPtr); /* * TIP #508: [array default] */ MODULE_SCOPE void TclInitArrayVar(Var *arrayPtr); MODULE_SCOPE Tcl_Obj * TclGetArrayDefault(Var *arrayPtr); /* * Utility routines for encoding index values as integers. Used by both * some of the command compilers and by [lsort] and [lsearch]. */ MODULE_SCOPE int TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr, int before, int after, int *indexPtr); |
︙ | ︙ |
Changes to generic/tclInterp.c.
︙ | ︙ | |||
218 219 220 221 222 223 224 | Tcl_Obj *namePtr, Tcl_Obj *targetPtr, int objc, Tcl_Obj *const objv[]); static int AliasDelete(Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *namePtr); static int AliasDescribe(Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *objPtr); static int AliasList(Tcl_Interp *interp, Tcl_Interp *slaveInterp); | < < < | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | Tcl_Obj *namePtr, Tcl_Obj *targetPtr, int objc, Tcl_Obj *const objv[]); static int AliasDelete(Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *namePtr); static int AliasDescribe(Tcl_Interp *interp, Tcl_Interp *slaveInterp, Tcl_Obj *objPtr); static int AliasList(Tcl_Interp *interp, Tcl_Interp *slaveInterp); static int AliasNRCmd(ClientData dummy, Tcl_Interp *currentInterp, int objc, Tcl_Obj *const objv[]); static void AliasObjCmdDeleteProc(ClientData clientData); static Tcl_Interp * GetInterp(Tcl_Interp *interp, Tcl_Obj *pathPtr); static Tcl_Interp * GetInterp2(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); |
︙ | ︙ | |||
253 254 255 256 257 258 259 | Tcl_Interp *slaveInterp); static int SlaveInvokeHidden(Tcl_Interp *interp, Tcl_Interp *slaveInterp, const char *namespaceName, int objc, Tcl_Obj *const objv[]); static int SlaveMarkTrusted(Tcl_Interp *interp, Tcl_Interp *slaveInterp); | < < | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | Tcl_Interp *slaveInterp); static int SlaveInvokeHidden(Tcl_Interp *interp, Tcl_Interp *slaveInterp, const char *namespaceName, int objc, Tcl_Obj *const objv[]); static int SlaveMarkTrusted(Tcl_Interp *interp, Tcl_Interp *slaveInterp); static void SlaveObjCmdDeleteProc(ClientData clientData); static int SlaveRecursionLimit(Tcl_Interp *interp, Tcl_Interp *slaveInterp, int objc, Tcl_Obj *const objv[]); static int SlaveCommandLimitCmd(Tcl_Interp *interp, Tcl_Interp *slaveInterp, int consumedObjc, int objc, Tcl_Obj *const objv[]); |
︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 | Command *aliasCmdPtr; /* * If we are not creating or renaming an alias, then it is always OK to * create or rename the command. */ | | > | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | Command *aliasCmdPtr; /* * If we are not creating or renaming an alias, then it is always OK to * create or rename the command. */ if (cmdPtr->objProc != TclAliasObjCmd && cmdPtr->objProc != TclLocalAliasObjCmd) { return TCL_OK; } /* * OK, we are dealing with an alias, so traverse the chain of aliases. If * we encounter the alias we are defining (or renaming to) any in the * chain then we have a loop. |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | /* * Otherwise, follow the chain one step further. See if the target * command is an alias - if so, follow the loop to its target command. * Otherwise we do not have a loop. */ | | > | 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | /* * Otherwise, follow the chain one step further. See if the target * command is an alias - if so, follow the loop to its target command. * Otherwise we do not have a loop. */ if (aliasCmdPtr->objProc != TclAliasObjCmd && aliasCmdPtr->objProc != TclLocalAliasObjCmd) { return TCL_OK; } nextAliasPtr = aliasCmdPtr->objClientData; } /* NOTREACHED */ } |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 | } Tcl_Preserve(slaveInterp); Tcl_Preserve(masterInterp); if (slaveInterp == masterInterp) { aliasPtr->slaveCmd = Tcl_NRCreateCommand(slaveInterp, | | | | | | | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 | } Tcl_Preserve(slaveInterp); Tcl_Preserve(masterInterp); if (slaveInterp == masterInterp) { aliasPtr->slaveCmd = Tcl_NRCreateCommand(slaveInterp, TclGetString(namePtr), TclLocalAliasObjCmd, AliasNRCmd, aliasPtr, AliasObjCmdDeleteProc); } else { aliasPtr->slaveCmd = Tcl_CreateObjCommand(slaveInterp, TclGetString(namePtr), TclAliasObjCmd, aliasPtr, AliasObjCmdDeleteProc); } if (TclPreventAliasLoop(interp, slaveInterp, aliasPtr->slaveCmd) != TCL_OK) { /* * Found an alias loop! The last call to Tcl_CreateObjCommand made the * alias point to itself. Delete the command and its alias record. Be |
︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 | Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * | | > > > > > | 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 | Tcl_SetObjResult(interp, resultPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclAliasObjCmd, TclLocalAliasObjCmd -- * * This is the function that services invocations of aliases in a slave * interpreter. One such command exists for each alias. When invoked, * this function redirects the invocation to the target command in the * master interpreter as designated by the Alias record associated with * this command. * * TclLocalAliasObjCmd is a stripped down version used when the source * and target interpreters of the alias are the same. That lets a number * of safety precautions be avoided: the state is much more precisely * known. * * Results: * A standard Tcl result. * * Side effects: * Causes forwarding of the invocation; all possible side effects may * occur as a result of invoking the command to which the invocation is |
︙ | ︙ | |||
1844 1845 1846 1847 1848 1849 1850 | if (TclInitRewriteEnsemble(interp, 1, prefc, objv)) { TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL); } TclSkipTailcall(interp); return Tcl_NREvalObj(interp, listPtr, flags); } | | | | 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 | if (TclInitRewriteEnsemble(interp, 1, prefc, objv)) { TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL); } TclSkipTailcall(interp); return Tcl_NREvalObj(interp, listPtr, flags); } int TclAliasObjCmd( ClientData clientData, /* Alias record. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument vector. */ { #define ALIAS_CMDV_PREALLOC 10 Alias *aliasPtr = clientData; |
︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 | * on the target interpreter. */ if (targetInterp != interp) { Tcl_TransferResult(targetInterp, result, interp); Tcl_Release(targetInterp); } for (i=0; i<cmdc; i++) { Tcl_DecrRefCount(cmdv[i]); } if (cmdv != cmdArr) { TclStackFree(interp, cmdv); } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 | * on the target interpreter. */ if (targetInterp != interp) { Tcl_TransferResult(targetInterp, result, interp); Tcl_Release(targetInterp); } for (i=0; i<cmdc; i++) { Tcl_DecrRefCount(cmdv[i]); } if (cmdv != cmdArr) { TclStackFree(interp, cmdv); } return result; #undef ALIAS_CMDV_PREALLOC } int TclLocalAliasObjCmd( ClientData clientData, /* Alias record. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument vector. */ { #define ALIAS_CMDV_PREALLOC 10 Alias *aliasPtr = clientData; int result, prefc, cmdc, i; Tcl_Obj **prefv, **cmdv; Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC]; Interp *iPtr = (Interp *) interp; int isRootEnsemble; /* * Append the arguments to the command prefix and invoke the command in * the global namespace. */ prefc = aliasPtr->objc; prefv = &aliasPtr->objPtr; cmdc = prefc + objc - 1; if (cmdc <= ALIAS_CMDV_PREALLOC) { cmdv = cmdArr; } else { cmdv = TclStackAlloc(interp, cmdc * sizeof(Tcl_Obj *)); } memcpy(cmdv, prefv, (size_t) (prefc * sizeof(Tcl_Obj *))); memcpy(cmdv+prefc, objv+1, (size_t) ((objc-1) * sizeof(Tcl_Obj *))); for (i=0; i<cmdc; i++) { Tcl_IncrRefCount(cmdv[i]); } /* * Use the ensemble rewriting machinery to ensure correct error messages: * only the source command should show, not the full target prefix. */ isRootEnsemble = TclInitRewriteEnsemble((Tcl_Interp *)iPtr, 1, prefc, objv); /* * Execute the target command in the target interpreter. */ result = Tcl_EvalObjv(interp, cmdc, cmdv, TCL_EVAL_INVOKE); /* * Clean up the ensemble rewrite info if we set it in the first place. */ if (isRootEnsemble) { TclResetRewriteEnsemble((Tcl_Interp *)iPtr, 1); } for (i=0; i<cmdc; i++) { Tcl_DecrRefCount(cmdv[i]); } if (cmdv != cmdArr) { TclStackFree(interp, cmdv); } |
︙ | ︙ | |||
2373 2374 2375 2376 2377 2378 2379 | slaveInterp = Tcl_CreateInterp(); slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; slavePtr->masterInterp = masterInterp; slavePtr->slaveEntryPtr = hPtr; slavePtr->slaveInterp = slaveInterp; slavePtr->interpCmd = Tcl_NRCreateCommand(masterInterp, path, | | | 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 | slaveInterp = Tcl_CreateInterp(); slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; slavePtr->masterInterp = masterInterp; slavePtr->slaveEntryPtr = hPtr; slavePtr->slaveInterp = slaveInterp; slavePtr->interpCmd = Tcl_NRCreateCommand(masterInterp, path, TclSlaveObjCmd, NRSlaveCmd, slaveInterp, SlaveObjCmdDeleteProc); Tcl_InitHashTable(&slavePtr->aliasTable, TCL_STRING_KEYS); Tcl_SetHashValue(hPtr, slavePtr); Tcl_SetVar2(slaveInterp, "tcl_interactive", NULL, "0", TCL_GLOBAL_ONLY); /* * Inherit the recursion limit. */ |
︙ | ︙ | |||
2441 2442 2443 2444 2445 2446 2447 | return NULL; } /* *---------------------------------------------------------------------- * | | | | | 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 | return NULL; } /* *---------------------------------------------------------------------- * * TclSlaveObjCmd -- * * Command to manipulate an interpreter, e.g. to send commands to it to * be evaluated. One such command exists for each slave interpreter. * * Results: * A standard Tcl result. * * Side effects: * See user documentation for details. * *---------------------------------------------------------------------- */ int TclSlaveObjCmd( ClientData clientData, /* Slave interpreter. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { return Tcl_NRCallObjProc(interp, NRSlaveCmd, clientData, objc, objv); } |
︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 | OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_DEBUG, OPT_EVAL, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHIDDEN, OPT_LIMIT, OPT_MARKTRUSTED, OPT_RECLIMIT }; if (slaveInterp == NULL) { | | | 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 | OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_DEBUG, OPT_EVAL, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHIDDEN, OPT_LIMIT, OPT_MARKTRUSTED, OPT_RECLIMIT }; if (slaveInterp == NULL) { Tcl_Panic("TclSlaveObjCmd: interpreter has been deleted"); } if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, |
︙ | ︙ |
Changes to generic/tclNamesp.c.
︙ | ︙ | |||
85 86 87 88 89 90 91 | const char *name2, int flags); static char * EstablishErrorInfoTraces(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags); static void FreeNsNameInternalRep(Tcl_Obj *objPtr); static int GetNamespaceFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr); | < < | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | const char *name2, int flags); static char * EstablishErrorInfoTraces(ClientData clientData, Tcl_Interp *interp, const char *name1, const char *name2, int flags); static void FreeNsNameInternalRep(Tcl_Obj *objPtr); static int GetNamespaceFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr); static int InvokeImportedNRCmd(ClientData clientData, Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); static int NamespaceChildrenCmd(ClientData dummy, Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); static int NamespaceCodeCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int NamespaceCurrentCmd(ClientData dummy, |
︙ | ︙ | |||
1762 1763 1764 1765 1766 1767 1768 | return TCL_ERROR; } } } dataPtr = ckalloc(sizeof(ImportedCmdData)); importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds), | | | 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | return TCL_ERROR; } } } dataPtr = ckalloc(sizeof(ImportedCmdData)); importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds), TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr, DeleteImportedCmd); dataPtr->realCmdPtr = cmdPtr; dataPtr->selfPtr = (Command *) importedCmd; dataPtr->selfPtr->compileProc = cmdPtr->compileProc; Tcl_DStringFree(&ds); /* |
︙ | ︙ | |||
1983 1984 1985 1986 1987 1988 1989 | } return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * | | | 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 | } return (Tcl_Command) cmdPtr; } /* *---------------------------------------------------------------------- * * TclInvokeImportedCmd -- * * Invoked by Tcl whenever the user calls an imported command that was * created by Tcl_Import. Finds the "real" command (in another * namespace), and passes control to it. * * Results: * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. |
︙ | ︙ | |||
2014 2015 2016 2017 2018 2019 2020 | ImportedCmdData *dataPtr = clientData; Command *realCmdPtr = dataPtr->realCmdPtr; TclSkipTailcall(interp); return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, realCmdPtr); } | | | | 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 | ImportedCmdData *dataPtr = clientData; Command *realCmdPtr = dataPtr->realCmdPtr; TclSkipTailcall(interp); return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, realCmdPtr); } int TclInvokeImportedCmd( ClientData clientData, /* Points to the imported command's * ImportedCmdData structure. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* The argument objects. */ { return Tcl_NRCallObjProc(interp, InvokeImportedNRCmd, clientData, |
︙ | ︙ |
Changes to generic/tclOO.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | const char *newName, int flags); static void ReleaseClassContents(Tcl_Interp *interp,Object *oPtr); static void DeleteDescendants(Tcl_Interp *interp,Object *oPtr); static inline void RemoveClass(Class **list, int num, int idx); static inline void RemoveObject(Object **list, int num, int idx); static inline void SquelchCachedName(Object *oPtr); | < < < < < < < < < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | const char *newName, int flags); static void ReleaseClassContents(Tcl_Interp *interp,Object *oPtr); static void DeleteDescendants(Tcl_Interp *interp,Object *oPtr); static inline void RemoveClass(Class **list, int num, int idx); static inline void RemoveObject(Object **list, int num, int idx); static inline void SquelchCachedName(Object *oPtr); static int PublicNRObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int PrivateNRObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int MyClassNRObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static void MyClassDeleted(ClientData clientData); /* * Methods in the oo::object and oo::class classes. First, we define a helper |
︙ | ︙ | |||
717 718 719 720 721 722 723 | if (!nameStr) { nameStr = oPtr->namespacePtr->name; nsPtr = (Namespace *)oPtr->namespacePtr; if (nsPtr->parentPtr != NULL) { nsPtr = nsPtr->parentPtr; } | | < | | | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | if (!nameStr) { nameStr = oPtr->namespacePtr->name; nsPtr = (Namespace *)oPtr->namespacePtr; if (nsPtr->parentPtr != NULL) { nsPtr = nsPtr->parentPtr; } } oPtr->command = TclCreateObjCommandInNs(interp, nameStr, (Tcl_Namespace *)nsPtr, TclOOPublicObjectCmd, oPtr, NULL); /* * Add the NRE command and trace directly. While this breaks a number of * abstractions, it is faster and we're inside Tcl here so we're allowed. */ cmdPtr = (Command *) oPtr->command; cmdPtr->nreProc = PublicNRObjectCmd; cmdPtr->tracePtr = tracePtr = ckalloc(sizeof(CommandTrace)); tracePtr->traceProc = ObjectRenamedTrace; tracePtr->clientData = oPtr; tracePtr->flags = TCL_TRACE_RENAME|TCL_TRACE_DELETE; tracePtr->nextPtr = NULL; tracePtr->refCount = 1; oPtr->myCommand = TclNRCreateCommandInNs(interp, "my", oPtr->namespacePtr, TclOOPrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted); oPtr->myclassCommand = TclNRCreateCommandInNs(interp, "myclass", oPtr->namespacePtr, TclOOMyClassObjCmd, MyClassNRObjCmd, oPtr, MyClassDeleted); return oPtr; } /* * ---------------------------------------------------------------------- * |
︙ | ︙ | |||
2408 2409 2410 2411 2412 2413 2414 | } Tcl_SetHashValue(hPtr, metadata); } /* * ---------------------------------------------------------------------- * | | | | | | | 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 | } Tcl_SetHashValue(hPtr, metadata); } /* * ---------------------------------------------------------------------- * * TclOOPublicObjectCmd, TclOOPrivateObjectCmd, TclOOInvokeObject -- * * Main entry point for object invocations. The Public* and Private* * wrapper functions (implementations of both object instance commands * and [my]) are just thin wrappers round the main TclOOObjectCmdCore * function. Note that the core is function is NRE-aware. * * ---------------------------------------------------------------------- */ int TclOOPublicObjectCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return Tcl_NRCallObjProc(interp, PublicNRObjectCmd, clientData,objc,objv); } static int PublicNRObjectCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return TclOOObjectCmdCore(clientData, interp, objc, objv, PUBLIC_METHOD, NULL); } int TclOOPrivateObjectCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return Tcl_NRCallObjProc(interp, PrivateNRObjectCmd,clientData,objc,objv); } |
︙ | ︙ | |||
2493 2494 2495 2496 2497 2498 2499 | (Class *) startCls); } } /* * ---------------------------------------------------------------------- * | | | | | 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 | (Class *) startCls); } } /* * ---------------------------------------------------------------------- * * TclOOMyClassObjCmd, MyClassNRObjCmd -- * * Special trap door to allow an object to delegate simply to its class. * * ---------------------------------------------------------------------- */ int TclOOMyClassObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return Tcl_NRCallObjProc(interp, MyClassNRObjCmd, clientData, objc, objv); } |
︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 | * exactly the name of its public command. */ { Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr); if (cmdPtr == NULL) { goto notAnObject; } | | | | 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 | * exactly the name of its public command. */ { Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr); if (cmdPtr == NULL) { goto notAnObject; } if (cmdPtr->objProc != TclOOPublicObjectCmd) { cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); if (cmdPtr == NULL || cmdPtr->objProc != TclOOPublicObjectCmd) { goto notAnObject; } } return cmdPtr->objClientData; notAnObject: Tcl_SetObjResult(interp, Tcl_ObjPrintf( |
︙ | ︙ |
Changes to generic/tclOODefineCmds.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 | * Some things that make it easier to declare a slot. */ struct DeclaredSlot { const char *name; const Tcl_MethodType getterType; const Tcl_MethodType setterType; }; | > | | > > | 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 | * Some things that make it easier to declare a slot. */ struct DeclaredSlot { const char *name; const Tcl_MethodType getterType; const Tcl_MethodType setterType; const Tcl_MethodType resolverType; }; #define SLOT(name,getter,setter,resolver) \ {"::oo::" name, \ {TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Getter", \ getter, NULL, NULL}, \ {TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Setter", \ setter, NULL, NULL}, \ {TCL_OO_METHOD_VERSION_CURRENT, "core method: " name " Setter", \ resolver, NULL, NULL}} /* * Forward declarations. */ static inline void BumpGlobalEpoch(Tcl_Interp *interp, Class *classPtr); static Tcl_Command FindCommand(Tcl_Interp *interp, Tcl_Obj *stringObj, |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 | int objc, Tcl_Obj *const *objv); static int ObjVarsGet(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); static int ObjVarsSet(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); /* * Now define the slots used in declarations. */ static const struct DeclaredSlot slots[] = { | > > > | | | | | | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | int objc, Tcl_Obj *const *objv); static int ObjVarsGet(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); static int ObjVarsSet(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); static int ResolveClass(ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv); /* * Now define the slots used in declarations. */ static const struct DeclaredSlot slots[] = { SLOT("define::filter", ClassFilterGet, ClassFilterSet, NULL), SLOT("define::mixin", ClassMixinGet, ClassMixinSet, ResolveClass), SLOT("define::superclass", ClassSuperGet, ClassSuperSet, ResolveClass), SLOT("define::variable", ClassVarsGet, ClassVarsSet, NULL), SLOT("objdefine::filter", ObjFilterGet, ObjFilterSet, NULL), SLOT("objdefine::mixin", ObjMixinGet, ObjMixinSet, ResolveClass), SLOT("objdefine::variable", ObjVarsGet, ObjVarsSet, NULL), {NULL, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}} }; /* * How to build the in-namespace name of a private variable. This is a pattern * used with Tcl_ObjPrintf(). */ |
︙ | ︙ | |||
2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 | int TclOODefineSlots( Foundation *fPtr) { const struct DeclaredSlot *slotInfoPtr; Tcl_Obj *getName = Tcl_NewStringObj("Get", -1); Tcl_Obj *setName = Tcl_NewStringObj("Set", -1); Class *slotCls; slotCls = ((Object *) Tcl_NewObjectInstance(fPtr->interp, (Tcl_Class) fPtr->classCls, "::oo::Slot", NULL, -1, NULL, 0))->classPtr; if (slotCls == NULL) { return TCL_ERROR; } Tcl_IncrRefCount(getName); Tcl_IncrRefCount(setName); for (slotInfoPtr = slots ; slotInfoPtr->name ; slotInfoPtr++) { Tcl_Object slotObject = Tcl_NewObjectInstance(fPtr->interp, | > > | > > > > > | 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 | int TclOODefineSlots( Foundation *fPtr) { const struct DeclaredSlot *slotInfoPtr; Tcl_Obj *getName = Tcl_NewStringObj("Get", -1); Tcl_Obj *setName = Tcl_NewStringObj("Set", -1); Tcl_Obj *resolveName = Tcl_NewStringObj("Resolve", -1); Class *slotCls; slotCls = ((Object *) Tcl_NewObjectInstance(fPtr->interp, (Tcl_Class) fPtr->classCls, "::oo::Slot", NULL, -1, NULL, 0))->classPtr; if (slotCls == NULL) { return TCL_ERROR; } Tcl_IncrRefCount(getName); Tcl_IncrRefCount(setName); Tcl_IncrRefCount(resolveName); for (slotInfoPtr = slots ; slotInfoPtr->name ; slotInfoPtr++) { Tcl_Object slotObject = Tcl_NewObjectInstance(fPtr->interp, (Tcl_Class) slotCls, slotInfoPtr->name, NULL, -1, NULL, 0); if (slotObject == NULL) { continue; } Tcl_NewInstanceMethod(fPtr->interp, slotObject, getName, 0, &slotInfoPtr->getterType, NULL); Tcl_NewInstanceMethod(fPtr->interp, slotObject, setName, 0, &slotInfoPtr->setterType, NULL); if (slotInfoPtr->resolverType.callProc) { Tcl_NewInstanceMethod(fPtr->interp, slotObject, resolveName, 0, &slotInfoPtr->resolverType, NULL); } } Tcl_DecrRefCount(getName); Tcl_DecrRefCount(setName); Tcl_DecrRefCount(resolveName); return TCL_OK; } /* * ---------------------------------------------------------------------- * * ClassFilterGet, ClassFilterSet -- |
︙ | ︙ | |||
2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 | if (IsPrivateDefine(interp)) { InstallPrivateVariableMapping(&oPtr->privateVariables, varc, varv, oPtr->creationEpoch); } else { InstallStandardVariableMapping(&oPtr->variables, varc, varv); } return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 | if (IsPrivateDefine(interp)) { InstallPrivateVariableMapping(&oPtr->privateVariables, varc, varv, oPtr->creationEpoch); } else { InstallStandardVariableMapping(&oPtr->variables, varc, varv); } return TCL_OK; } /* * ---------------------------------------------------------------------- * * ResolveClass -- * * Implementation of the "Resolve" support method for some slots (those * that are slots around a list of classes). This resolves possible class * names to their fully-qualified names if possible. * * ---------------------------------------------------------------------- */ static int ResolveClass( ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv) { int idx = Tcl_ObjectContextSkippedArgs(context); Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp); Class *clsPtr; /* * Check if were called wrongly. The definition context isn't used... * except that GetClassInOuterContext() assumes that it is there. */ if (oPtr == NULL) { return TCL_ERROR; } else if (objc != idx + 1) { Tcl_WrongNumArgs(interp, idx, objv, "slotElement"); return TCL_ERROR; } /* * Resolve the class if possible. If not, remove any resolution error and * return what we've got anyway as the failure might not be fatal overall. */ clsPtr = GetClassInOuterContext(interp, objv[idx], "USER SHOULD NOT SEE THIS MESSAGE"); if (clsPtr == NULL) { Tcl_ResetResult(interp); Tcl_SetObjResult(interp, objv[idx]); } else { Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->thisPtr)); } return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tclOOScript.h.
︙ | ︙ | |||
143 144 145 146 147 148 149 | "\tdefine Slot {\n" "\t\tmethod Get {} {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" "\t\tmethod Set list {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" | > > > | > > > > > > | > > > > > > > > > > > > > > | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | "\tdefine Slot {\n" "\t\tmethod Get {} {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" "\t\tmethod Set list {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" "\t\tmethod Resolve list {\n" "\t\t\treturn $list\n" "\t\t}\n" "\t\tmethod -set args {\n" "\t\t\tset my [namespace which my]\n" "\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n" "\t\t\ttailcall my Set $args\n" "\t\t}\n" "\t\tmethod -append args {\n" "\t\t\tset my [namespace which my]\n" "\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n" "\t\t\tset current [uplevel 1 [list $my Get]]\n" "\t\t\ttailcall my Set [list {*}$current {*}$args]\n" "\t\t}\n" "\t\tmethod -clear {} {tailcall my Set {}}\n" "\t\tmethod -prepend args {\n" "\t\t\tset my [namespace which my]\n" "\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n" "\t\t\tset current [uplevel 1 [list $my Get]]\n" "\t\t\ttailcall my Set [list {*}$args {*}$current]\n" "\t\t}\n" "\t\tmethod -remove args {\n" "\t\t\tset my [namespace which my]\n" "\t\t\tset args [lmap a $args {uplevel 1 [list $my Resolve $a]}]\n" "\t\t\tset current [uplevel 1 [list $my Get]]\n" "\t\t\ttailcall my Set [lmap val $current {\n" "\t\t\t\tif {$val in $args} continue else {set val}\n" "\t\t\t}]\n" "\t\t}\n" "\t\tforward --default-operation my -append\n" "\t\tmethod unknown {args} {\n" "\t\t\tset def --default-operation\n" "\t\t\tif {[llength $args] == 0} {\n" "\t\t\t\ttailcall my $def\n" "\t\t\t} elseif {![string match -* [lindex $args 0]]} {\n" "\t\t\t\ttailcall my $def {*}$args\n" "\t\t\t}\n" "\t\t\tnext {*}$args\n" "\t\t}\n" "\t\texport -set -append -clear -prepend -remove\n" "\t\tunexport unknown destroy\n" "\t}\n" "\tobjdefine define::superclass forward --default-operation my -set\n" "\tobjdefine define::mixin forward --default-operation my -set\n" "\tobjdefine objdefine::mixin forward --default-operation my -set\n" "\tdefine object method <cloned> {originObject} {\n" "\t\tforeach p [info procs [info object namespace $originObject]::*] {\n" |
︙ | ︙ |
Changes to generic/tclOOScript.tcl.
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 | method Set list { return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented" } # ------------------------------------------------------------------ # # Slot -set, -append, -clear, --default-operation -- # # Standard public slot operations. If a slot can't figure out # what method to call directly, it uses --default-operation. # # ------------------------------------------------------------------ | > > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > | | 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 346 347 | method Set list { return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented" } # ------------------------------------------------------------------ # # Slot Resolve -- # # Helper that lets a slot convert a list of arguments of a # particular type to their canonical forms. Defaults to doing # nothing (suitable for simple strings). # # ------------------------------------------------------------------ method Resolve list { return $list } # ------------------------------------------------------------------ # # Slot -set, -append, -clear, --default-operation -- # # Standard public slot operations. If a slot can't figure out # what method to call directly, it uses --default-operation. # # ------------------------------------------------------------------ method -set args { set my [namespace which my] set args [lmap a $args {uplevel 1 [list $my Resolve $a]}] tailcall my Set $args } method -append args { set my [namespace which my] set args [lmap a $args {uplevel 1 [list $my Resolve $a]}] set current [uplevel 1 [list $my Get]] tailcall my Set [list {*}$current {*}$args] } method -clear {} {tailcall my Set {}} method -prepend args { set my [namespace which my] set args [lmap a $args {uplevel 1 [list $my Resolve $a]}] set current [uplevel 1 [list $my Get]] tailcall my Set [list {*}$args {*}$current] } method -remove args { set my [namespace which my] set args [lmap a $args {uplevel 1 [list $my Resolve $a]}] set current [uplevel 1 [list $my Get]] tailcall my Set [lmap val $current { if {$val in $args} continue else {set val} }] } # Default handling forward --default-operation my -append method unknown {args} { set def --default-operation if {[llength $args] == 0} { tailcall my $def } elseif {![string match -* [lindex $args 0]]} { tailcall my $def {*}$args } next {*}$args } # Set up what is exported and what isn't export -set -append -clear -prepend -remove unexport unknown destroy } # Set the default operation differently for these slots objdefine define::superclass forward --default-operation my -set objdefine define::mixin forward --default-operation my -set objdefine objdefine::mixin forward --default-operation my -set |
︙ | ︙ |
Changes to generic/tclPlatDecls.h.
︙ | ︙ | |||
46 47 48 49 50 51 52 | extern "C" { #endif /* * Exported function declarations: */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | extern "C" { #endif /* * Exported function declarations: */ #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ /* 0 */ EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len, Tcl_DString *dsPtr); /* 1 */ EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len, Tcl_DString *dsPtr); #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ /* 0 */ EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */ EXTERN int Tcl_MacOSXOpenVersionedBundleResources( Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); #endif /* MACOSX */ typedef struct TclPlatStubs { int magic; void *hooks; #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, int maxPathLen, char *libraryPath); /* 0 */ int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, int maxPathLen, char *libraryPath); /* 1 */ #endif /* MACOSX */ } TclPlatStubs; extern const TclPlatStubs *tclPlatStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_TCL_STUBS) /* * Inline function declarations: */ #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ #define Tcl_WinUtfToTChar \ (tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */ #define Tcl_WinTCharToUtf \ (tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ #define Tcl_MacOSXOpenBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */ #define Tcl_MacOSXOpenVersionedBundleResources \ (tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */ #endif /* MACOSX */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLPLATDECLS */ |
Changes to generic/tclProc.c.
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | static int ProcWrongNumArgs( Tcl_Interp *interp, int skip) { CallFrame *framePtr = ((Interp *)interp)->varFramePtr; register Proc *procPtr = framePtr->procPtr; | < | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 | static int ProcWrongNumArgs( Tcl_Interp *interp, int skip) { CallFrame *framePtr = ((Interp *)interp)->varFramePtr; register Proc *procPtr = framePtr->procPtr; int localCt = procPtr->numCompiledLocals, numArgs, i; Tcl_Obj **desiredObjs; const char *final = NULL; /* * Build up desired argument list for Tcl_WrongNumArgs */ |
︙ | ︙ | |||
1027 1028 1029 1030 1031 1032 1033 | desiredObjs[0] = framePtr->objv[skip-1]; #else desiredObjs[0] = Tcl_NewListObj(1, framePtr->objv + skip - 1); #endif /* AVOID_HACKS_FOR_ITCL */ } Tcl_IncrRefCount(desiredObjs[0]); | > | > | | | | | | | | | | | | | | | > | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 | desiredObjs[0] = framePtr->objv[skip-1]; #else desiredObjs[0] = Tcl_NewListObj(1, framePtr->objv + skip - 1); #endif /* AVOID_HACKS_FOR_ITCL */ } Tcl_IncrRefCount(desiredObjs[0]); if (localCt > 0) { register Var *defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt); for (i=1 ; i<=numArgs ; i++, defPtr++) { Tcl_Obj *argObj; Tcl_Obj *namePtr = localName(framePtr, i-1); if (defPtr->value.objPtr != NULL) { TclNewObj(argObj); Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL); } else if (defPtr->flags & VAR_IS_ARGS) { numArgs--; final = "?arg ...?"; break; } else { argObj = namePtr; Tcl_IncrRefCount(namePtr); } desiredObjs[i] = argObj; } } Tcl_ResetResult(interp); Tcl_WrongNumArgs(interp, numArgs+1, desiredObjs, final); for (i=0 ; i<=numArgs ; i++) { Tcl_DecrRefCount(desiredObjs[i]); |
︙ | ︙ |
Changes to generic/tclStubInit.c.
︙ | ︙ | |||
254 255 256 257 258 259 260 | char * Tcl_WinTCharToUtf( const char *string, int len, Tcl_DString *dsPtr) { | | | | | | | | > | | 254 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 | char * Tcl_WinTCharToUtf( const char *string, int len, Tcl_DString *dsPtr) { char *p; int size, i = 0; if (len > 0) { len /= 2; } size = WideCharToMultiByte(CP_UTF8, 0, string, len, 0, 0, NULL, NULL); Tcl_DStringInit(dsPtr); Tcl_DStringSetLength(dsPtr, size+8); /* Add some spare, in case of NULL-bytes */ p = (char *)Tcl_DStringValue(dsPtr); WideCharToMultiByte(CP_UTF8, 0, string, len, p, size, NULL, NULL); if (len == -1) --size; /* account for 0-byte at string end */ while (i < size) { if (!p[i]) { /* Output contains '\0'-byte, but Tcl expect two-bytes: C0 80 */ memmove(p+i+2, p+i+1, size-i-1); memcpy(p + i++, "\xC0\x80", 2); Tcl_DStringSetLength(dsPtr, ++size + 1); p = (char *)Tcl_DStringValue(dsPtr); } ++i; } Tcl_DStringSetLength(dsPtr, size); p[size] = 0; return p; } #if defined(TCL_WIDE_INT_IS_LONG) |
︙ | ︙ | |||
850 851 852 853 854 855 856 | TclUnixOpenTemporaryFile, /* 30 */ #endif /* MACOSX */ }; static const TclPlatStubs tclPlatStubs = { TCL_STUB_MAGIC, 0, | < < < < < < < | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 | TclUnixOpenTemporaryFile, /* 30 */ #endif /* MACOSX */ }; static const TclPlatStubs tclPlatStubs = { TCL_STUB_MAGIC, 0, #if defined(_WIN32) || defined(__CYGWIN__) /* WIN */ Tcl_WinUtfToTChar, /* 0 */ Tcl_WinTCharToUtf, /* 1 */ #endif /* WIN */ #ifdef MAC_OSX_TCL /* MACOSX */ Tcl_MacOSXOpenBundleResources, /* 0 */ Tcl_MacOSXOpenVersionedBundleResources, /* 1 */ #endif /* MACOSX */ }; const TclTomMathStubs tclTomMathStubs = { TCL_STUB_MAGIC, 0, TclBN_epoch, /* 0 */ |
︙ | ︙ |
Changes to generic/tclVar.c.
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 | * Tcl_NextHashEntry to get value to * return. */ struct ArraySearch *nextPtr;/* Next in list of all active searches for * this variable, or NULL if this is the last * one. */ } ArraySearch; /* * Forward references to functions defined later in this file: */ static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *patternPtr, int includeLinks); static void ArrayPopulateSearch(Tcl_Interp *interp, | > > > > > > > > > > > > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | * Tcl_NextHashEntry to get value to * return. */ struct ArraySearch *nextPtr;/* Next in list of all active searches for * this variable, or NULL if this is the last * one. */ } ArraySearch; /* * TIP #508: [array default] * * The following structure extends the regular TclVarHashTable used by array * variables to store their optional default value. */ typedef struct ArrayVarHashTable { TclVarHashTable table; Tcl_Obj *defaultObj; } ArrayVarHashTable; /* * Forward references to functions defined later in this file: */ static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *patternPtr, int includeLinks); static void ArrayPopulateSearch(Tcl_Interp *interp, |
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | Tcl_Obj *myNamePtr, int myFlags, int index); static ArraySearch * ParseSearchId(Tcl_Interp *interp, const Var *varPtr, Tcl_Obj *varNamePtr, Tcl_Obj *handleObj); static void UnsetVarStruct(Var *varPtr, Var *arrayPtr, Interp *iPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags, int index); /* * Functions defined in this file that may be exported in the future for use * by the bytecode compiler and engine or to the public interface. */ MODULE_SCOPE Var * TclLookupSimpleVar(Tcl_Interp *interp, Tcl_Obj *varNamePtr, int flags, const int create, | > > > > > > > > > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | Tcl_Obj *myNamePtr, int myFlags, int index); static ArraySearch * ParseSearchId(Tcl_Interp *interp, const Var *varPtr, Tcl_Obj *varNamePtr, Tcl_Obj *handleObj); static void UnsetVarStruct(Var *varPtr, Var *arrayPtr, Interp *iPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags, int index); /* * TIP #508: [array default] */ static int ArrayDefaultCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static void DeleteArrayVar(Var *arrayPtr); static void SetArrayDefault(Var *arrayPtr, Tcl_Obj *defaultObj); /* * Functions defined in this file that may be exported in the future for use * by the bytecode compiler and engine or to the public interface. */ MODULE_SCOPE Var * TclLookupSimpleVar(Tcl_Interp *interp, Tcl_Obj *varNamePtr, int flags, const int create, |
︙ | ︙ | |||
232 233 234 235 236 237 238 | FreeLocalVarName, DupLocalVarName, NULL, NULL }; static const Tcl_ObjType tclParsedVarNameType = { "parsedVarName", FreeParsedVarName, DupParsedVarName, NULL, NULL }; | < | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | FreeLocalVarName, DupLocalVarName, NULL, NULL }; static const Tcl_ObjType tclParsedVarNameType = { "parsedVarName", FreeParsedVarName, DupParsedVarName, NULL, NULL }; Var * TclVarHashCreateVar( TclVarHashTable *tablePtr, const char *key, int *newPtr) { |
︙ | ︙ | |||
912 913 914 915 916 917 918 | *indexPtr = -1; } else { *indexPtr = -2; } } } else { /* Local var: look in frame varFramePtr. */ | | > > | | > | | | | | | | > | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | *indexPtr = -1; } else { *indexPtr = -2; } } } else { /* Local var: look in frame varFramePtr. */ int localCt = varFramePtr->numCompiledLocals; if (localCt > 0) { Tcl_Obj **objPtrPtr = &varFramePtr->localCachePtr->varName0; const char *localNameStr; int localLen; for (i=0 ; i<localCt ; i++, objPtrPtr++) { register Tcl_Obj *objPtr = *objPtrPtr; if (objPtr) { localNameStr = TclGetStringFromObj(objPtr, &localLen); if ((varLen == localLen) && (varName[0] == localNameStr[0]) && !memcmp(varName, localNameStr, varLen)) { *indexPtr = i; return (Var *) &varFramePtr->compiledLocals[i]; } } } } tablePtr = varFramePtr->varTablePtr; if (create) { if (tablePtr == NULL) { tablePtr = ckalloc(sizeof(TclVarHashTable)); |
︙ | ︙ | |||
1011 1012 1013 1014 1015 1016 1017 | * element, if it doesn't already exist. If 0, * return error if it doesn't exist. */ Var *arrayPtr, /* Pointer to the array's Var structure. */ int index) /* If >=0, the index of the local array. */ { int isNew; Var *varPtr; | < < | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 | * element, if it doesn't already exist. If 0, * return error if it doesn't exist. */ Var *arrayPtr, /* Pointer to the array's Var structure. */ int index) /* If >=0, the index of the local array. */ { int isNew; Var *varPtr; /* * We're dealing with an array element. Make sure the variable is an array * and look up the element (create the element if desired). */ if (TclIsVarUndefined(arrayPtr) && !TclIsVarArrayElement(arrayPtr)) { |
︙ | ︙ | |||
1045 1046 1047 1048 1049 1050 1051 | danglingVar, index); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME", arrayNamePtr?TclGetString(arrayNamePtr):NULL, NULL); } return NULL; } | | < < < < < < < < < | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 | danglingVar, index); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME", arrayNamePtr?TclGetString(arrayNamePtr):NULL, NULL); } return NULL; } TclInitArrayVar(arrayPtr); } else if (!TclIsVarArray(arrayPtr)) { if (flags & TCL_LEAVE_ERR_MSG) { TclObjVarErrMsg(interp, arrayNamePtr, elNamePtr, msg, needArray, index); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME", arrayNamePtr?TclGetString(arrayNamePtr):NULL, NULL); } |
︙ | ︙ | |||
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 | /* * Return the element if it's an existing scalar variable. */ if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { return varPtr->value.objPtr; } if (flags & TCL_LEAVE_ERR_MSG) { if (TclIsVarUndefined(varPtr) && arrayPtr && !TclIsVarUndefined(arrayPtr)) { msg = noSuchElement; } else if (TclIsVarArray(varPtr)) { msg = isArray; | > > > > > > > > > > > > > > > > > > > > > > | 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 | /* * Return the element if it's an existing scalar variable. */ if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr)) { return varPtr->value.objPtr; } /* * Return the array default value if any. */ if (arrayPtr && TclIsVarArray(arrayPtr) && TclGetArrayDefault(arrayPtr)) { return TclGetArrayDefault(arrayPtr); } if (TclIsVarArrayElement(varPtr) && !arrayPtr) { /* * UGLY! Peek inside the implementation of things. This lets us get * the default of an array even when we've been [upvar]ed to just an * element of the array. */ ArrayVarHashTable *avhtPtr = (ArrayVarHashTable *) ((VarInHash *) varPtr)->entry.tablePtr; if (avhtPtr->defaultObj) { return avhtPtr->defaultObj; } } if (flags & TCL_LEAVE_ERR_MSG) { if (TclIsVarUndefined(varPtr) && arrayPtr && !TclIsVarUndefined(arrayPtr)) { msg = noSuchElement; } else if (TclIsVarArray(varPtr)) { msg = isArray; |
︙ | ︙ | |||
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | return TclPtrSetVarIdx(interp, (Var *) varPtr, (Var *) arrayPtr, part1Ptr, part2Ptr, newValuePtr, flags, -1); } /* *---------------------------------------------------------------------- * * TclPtrSetVarIdx -- * * This function is the same as Tcl_SetVar2Ex above, except that it * requires pointers to the variable's Var structs in addition to the * variable names. * * Results: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 | return TclPtrSetVarIdx(interp, (Var *) varPtr, (Var *) arrayPtr, part1Ptr, part2Ptr, newValuePtr, flags, -1); } /* *---------------------------------------------------------------------- * * ListAppendInVar, StringAppendInVar -- * * Support functions for TclPtrSetVarIdx that implement various types of * appending operations. * * Results: * ListAppendInVar returns a Tcl result code (from the core list append * operation). StringAppendInVar has no return value. * * Side effects: * The variable or element of the array is updated. This may make the * variable/element exist. Reference counts of values may be updated. * *---------------------------------------------------------------------- */ static inline int ListAppendInVar( Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, Tcl_Obj *oldValuePtr, Tcl_Obj *newValuePtr) { if (oldValuePtr == NULL) { /* * No previous value. Check for defaults if there's an array we can * ask this of. */ if (arrayPtr) { Tcl_Obj *defValuePtr = TclGetArrayDefault(arrayPtr); if (defValuePtr) { oldValuePtr = Tcl_DuplicateObj(defValuePtr); } } if (oldValuePtr == NULL) { /* * No default. [lappend] semantics say this is like being an empty * string. */ TclNewObj(oldValuePtr); } varPtr->value.objPtr = oldValuePtr; Tcl_IncrRefCount(oldValuePtr); /* Since var is referenced. */ } else if (Tcl_IsShared(oldValuePtr)) { varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); TclDecrRefCount(oldValuePtr); oldValuePtr = varPtr->value.objPtr; Tcl_IncrRefCount(oldValuePtr); /* Since var is referenced. */ } return Tcl_ListObjAppendElement(interp, oldValuePtr, newValuePtr); } static inline void StringAppendInVar( Var *varPtr, Var *arrayPtr, Tcl_Obj *oldValuePtr, Tcl_Obj *newValuePtr) { /* * If there was no previous value, either we use the array's default (if * this is an array with a default at all) or we treat this as a simple * set. */ if (oldValuePtr == NULL) { if (arrayPtr) { Tcl_Obj *defValuePtr = TclGetArrayDefault(arrayPtr); if (defValuePtr) { /* * This is *almost* the same as the shared path below, except * that the original value reference in defValuePtr is not * decremented. */ Tcl_Obj *valuePtr = Tcl_DuplicateObj(defValuePtr); varPtr->value.objPtr = valuePtr; TclContinuationsCopy(valuePtr, defValuePtr); Tcl_IncrRefCount(valuePtr); Tcl_AppendObjToObj(valuePtr, newValuePtr); if (newValuePtr->refCount == 0) { Tcl_DecrRefCount(newValuePtr); } return; } } varPtr->value.objPtr = newValuePtr; Tcl_IncrRefCount(newValuePtr); return; } /* * We append newValuePtr's bytes but don't change its ref count. Unless * the reference is shared, when we have to duplicate in order to be safe * to modify at all. */ if (Tcl_IsShared(oldValuePtr)) { /* Append to copy. */ varPtr->value.objPtr = Tcl_DuplicateObj(oldValuePtr); TclContinuationsCopy(varPtr->value.objPtr, oldValuePtr); TclDecrRefCount(oldValuePtr); oldValuePtr = varPtr->value.objPtr; Tcl_IncrRefCount(oldValuePtr); /* Since var is ref */ } Tcl_AppendObjToObj(oldValuePtr, newValuePtr); if (newValuePtr->refCount == 0) { Tcl_DecrRefCount(newValuePtr); } } /* *---------------------------------------------------------------------- * * TclPtrSetVarIdx -- * * This function is the same as Tcl_SetVar2Ex above, except that it * requires pointers to the variable's Var structs in addition to the * variable names. * * Results: |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | oldValuePtr = varPtr->value.objPtr; if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) { varPtr->value.objPtr = NULL; } if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) { if (flags & TCL_LIST_ELEMENT) { /* Append list element. */ | < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 | oldValuePtr = varPtr->value.objPtr; if (flags & TCL_LIST_ELEMENT && !(flags & TCL_APPEND_VALUE)) { varPtr->value.objPtr = NULL; } if (flags & (TCL_APPEND_VALUE|TCL_LIST_ELEMENT)) { if (flags & TCL_LIST_ELEMENT) { /* Append list element. */ result = ListAppendInVar(interp, varPtr, arrayPtr, oldValuePtr, newValuePtr); if (result != TCL_OK) { goto earlyError; } } else { /* Append string. */ StringAppendInVar(varPtr, arrayPtr, oldValuePtr, newValuePtr); } } else if (newValuePtr != oldValuePtr) { /* * In this case we are replacing the value, so we don't need to do * more than swap the objects. */ |
︙ | ︙ | |||
4070 4071 4072 4073 4074 4075 4076 | TclObjVarErrMsg(interp, arrayNameObj, NULL, "array set", needArray, -1); Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); return TCL_ERROR; } } | | < < | 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 | TclObjVarErrMsg(interp, arrayNameObj, NULL, "array set", needArray, -1); Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); return TCL_ERROR; } } TclInitArrayVar(varPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * ArraySizeCmd -- |
︙ | ︙ | |||
4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 | /* ARGSUSED */ Tcl_Command TclInitArrayCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap arrayImplMap[] = { {"anymore", ArrayAnyMoreCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"donesearch", ArrayDoneSearchCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0}, {"for", ArrayForObjCmd, TclCompileBasic3ArgCmd, ArrayForNRCmd, NULL, 0}, {"get", ArrayGetCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, {"names", ArrayNamesCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, {"nextelement", ArrayNextElementCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0}, | > | 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 | /* ARGSUSED */ Tcl_Command TclInitArrayCmd( Tcl_Interp *interp) /* Current interpreter. */ { static const EnsembleImplMap arrayImplMap[] = { {"anymore", ArrayAnyMoreCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"default", ArrayDefaultCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0}, {"donesearch", ArrayDoneSearchCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0}, {"for", ArrayForObjCmd, TclCompileBasic3ArgCmd, ArrayForNRCmd, NULL, 0}, {"get", ArrayGetCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, {"names", ArrayNamesCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0}, {"nextelement", ArrayNextElementCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0}, |
︙ | ︙ | |||
5542 5543 5544 5545 5546 5547 5548 | * variables, some combinations of [upvar] and [variable] may create * such beasts - see [Bug 604239]. This is necessary to avoid leaking * the corresponding Var struct, and is otherwise harmless. */ TclClearVarNamespaceVar(elPtr); } | < | | 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 | * variables, some combinations of [upvar] and [variable] may create * such beasts - see [Bug 604239]. This is necessary to avoid leaking * the corresponding Var struct, and is otherwise harmless. */ TclClearVarNamespaceVar(elPtr); } DeleteArrayVar(varPtr); } /* *---------------------------------------------------------------------- * * TclObjVarErrMsg -- * |
︙ | ︙ | |||
6232 6233 6234 6235 6236 6237 6238 | Tcl_Obj *listPtr, /* List object to append names to. */ Tcl_Obj *patternPtr, /* Pattern to match against. */ int includeLinks) /* 1 if upvars should be included, else 0. */ { Interp *iPtr = (Interp *) interp; Var *varPtr; int i, localVarCt, added; | | < > > > | | | | | | | | | | | | | | > | 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 | Tcl_Obj *listPtr, /* List object to append names to. */ Tcl_Obj *patternPtr, /* Pattern to match against. */ int includeLinks) /* 1 if upvars should be included, else 0. */ { Interp *iPtr = (Interp *) interp; Var *varPtr; int i, localVarCt, added; Tcl_Obj *objNamePtr; const char *varName; TclVarHashTable *localVarTablePtr; Tcl_HashSearch search; Tcl_HashTable addedTable; const char *pattern = patternPtr? TclGetString(patternPtr) : NULL; localVarCt = iPtr->varFramePtr->numCompiledLocals; varPtr = iPtr->varFramePtr->compiledLocals; localVarTablePtr = iPtr->varFramePtr->varTablePtr; if (includeLinks) { Tcl_InitObjHashTable(&addedTable); } if (localVarCt > 0) { Tcl_Obj **varNamePtr = &iPtr->varFramePtr->localCachePtr->varName0; for (i = 0; i < localVarCt; i++, varNamePtr++) { /* * Skip nameless (temporary) variables and undefined variables. */ if (*varNamePtr && !TclIsVarUndefined(varPtr) && (includeLinks || !TclIsVarLink(varPtr))) { varName = TclGetString(*varNamePtr); if ((pattern == NULL) || Tcl_StringMatch(varName, pattern)) { Tcl_ListObjAppendElement(interp, listPtr, *varNamePtr); if (includeLinks) { Tcl_CreateHashEntry(&addedTable, *varNamePtr, &added); } } } varPtr++; } } /* * Do nothing if no local variables. */ if (localVarTablePtr == NULL) { |
︙ | ︙ | |||
6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 | /* * Only compare string representations of the same length. */ return ((l1 == l2) && !memcmp(p1, p2, l1)); } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 | /* * Only compare string representations of the same length. */ return ((l1 == l2) && !memcmp(p1, p2, l1)); } /*---------------------------------------------------------------------- * * ArrayDefaultCmd -- * * This function implements the 'array default' Tcl command. * Refer to the user documentation for details on what it does. * * Results: * Returns a standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ /* ARGSUSED */ static int ArrayDefaultCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { static const char *const options[] = { "get", "set", "exists", "unset", NULL }; enum options { OPT_GET, OPT_SET, OPT_EXISTS, OPT_UNSET }; Tcl_Obj *arrayNameObj, *defaultValueObj; Var *varPtr, *arrayPtr; int isArray, option; /* * Parse arguments. */ if (objc != 3 && objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "option arrayName ?value?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option) != TCL_OK) { return TCL_ERROR; } arrayNameObj = objv[2]; if (TCL_ERROR == LocateArray(interp, arrayNameObj, &varPtr, &isArray)) { return TCL_ERROR; } switch (option) { case OPT_GET: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } if (!varPtr || TclIsVarUndefined(varPtr) || !isArray) { return NotArrayError(interp, arrayNameObj); } defaultValueObj = TclGetArrayDefault(varPtr); if (!defaultValueObj) { /* Array default must exist. */ Tcl_SetObjResult(interp, Tcl_NewStringObj( "array has no default value", -1)); Tcl_SetErrorCode(interp, "TCL", "READ", "ARRAY", "DEFAULT", NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, defaultValueObj); return TCL_OK; case OPT_SET: if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName value"); return TCL_ERROR; } /* * Attempt to create array if needed. */ varPtr = TclObjLookupVarEx(interp, arrayNameObj, NULL, /*flags*/ TCL_LEAVE_ERR_MSG, /*msg*/ "array default set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { return TCL_ERROR; } if (arrayPtr) { /* * Not a valid array name. */ CleanupVar(varPtr, arrayPtr); TclObjVarErrMsg(interp, arrayNameObj, NULL, "array default set", needArray, -1); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME", TclGetString(arrayNameObj), NULL); return TCL_ERROR; } if (!TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) { /* * Not an array. */ TclObjVarErrMsg(interp, arrayNameObj, NULL, "array default set", needArray, -1); Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); return TCL_ERROR; } if (!TclIsVarArray(varPtr)) { TclInitArrayVar(varPtr); } defaultValueObj = objv[3]; SetArrayDefault(varPtr, defaultValueObj); return TCL_OK; case OPT_EXISTS: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } /* * Undefined variables (whether or not they have storage allocated) do * not have defaults, and this is not an error case. */ if (!varPtr || TclIsVarUndefined(varPtr)) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); } else if (!isArray) { return NotArrayError(interp, arrayNameObj); } else { defaultValueObj = TclGetArrayDefault(varPtr); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(!!defaultValueObj)); } return TCL_OK; case OPT_UNSET: if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "arrayName"); return TCL_ERROR; } if (varPtr && !TclIsVarUndefined(varPtr)) { if (!isArray) { return NotArrayError(interp, arrayNameObj); } SetArrayDefault(varPtr, NULL); } return TCL_OK; } /* Unreached */ return TCL_ERROR; } /* * Initialize array variable. */ void TclInitArrayVar( Var *arrayPtr) { ArrayVarHashTable *tablePtr = ckalloc(sizeof(ArrayVarHashTable)); /* * Mark the variable as an array. */ TclSetVarArray(arrayPtr); /* * Regular TclVarHashTable initialization. */ arrayPtr->value.tablePtr = (TclVarHashTable *) tablePtr; TclInitVarHashTable(arrayPtr->value.tablePtr, TclGetVarNsPtr(arrayPtr)); /* * Default value initialization. */ tablePtr->defaultObj = NULL; } /* * Cleanup array variable. */ static void DeleteArrayVar( Var *arrayPtr) { ArrayVarHashTable *tablePtr = (ArrayVarHashTable *) arrayPtr->value.tablePtr; /* * Default value cleanup. */ SetArrayDefault(arrayPtr, NULL); /* * Regular TclVarHashTable cleanup. */ VarHashDeleteTable(arrayPtr->value.tablePtr); ckfree(tablePtr); } /* * Get array default value if any. */ Tcl_Obj * TclGetArrayDefault( Var *arrayPtr) { ArrayVarHashTable *tablePtr = (ArrayVarHashTable *) arrayPtr->value.tablePtr; return tablePtr->defaultObj; } /* * Set/replace/unset array default value. */ static void SetArrayDefault( Var *arrayPtr, Tcl_Obj *defaultObj) { ArrayVarHashTable *tablePtr = (ArrayVarHashTable *) arrayPtr->value.tablePtr; /* * Increment/decrement refcount twice to ensure that the object is shared, * so that it doesn't get modified accidentally by the folling code: * * array default set v 1 * lappend v(a) 2; # returns a new object {1 2} * set v(b); # returns the original default object "1" */ if (tablePtr->defaultObj) { Tcl_DecrRefCount(tablePtr->defaultObj); Tcl_DecrRefCount(tablePtr->defaultObj); } tablePtr->defaultObj = defaultObj; if (tablePtr->defaultObj) { Tcl_IncrRefCount(tablePtr->defaultObj); Tcl_IncrRefCount(tablePtr->defaultObj); } } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tclZipfs.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | * generic/tclZipfs.c file in the TIP430 enabled tcl cores * compat/tclZipfs.c file in the tclconfig (TEA) file system, for pre-tip430 projects */ #include "tclInt.h" #include "tclFileSystem.h" | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | * generic/tclZipfs.c file in the TIP430 enabled tcl cores * compat/tclZipfs.c file in the tclconfig (TEA) file system, for pre-tip430 projects */ #include "tclInt.h" #include "tclFileSystem.h" #ifdef _WIN32 #include <winbase.h> #else #include <sys/mman.h> #endif #include <errno.h> #include <string.h> #include <sys/stat.h> #include <time.h> #include <stdlib.h> #include <fcntl.h> |
︙ | ︙ | |||
138 139 140 141 142 143 144 | #define zip_write_short(p, v) \ (p)[0] = (v) & 0xff; (p)[1] = ((v) >> 8) & 0xff; /* * Windows drive letters. */ | | < < < | | < < < > > | > < < | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | #define zip_write_short(p, v) \ (p)[0] = (v) & 0xff; (p)[1] = ((v) >> 8) & 0xff; /* * Windows drive letters. */ #ifdef _WIN32 static const char drvletters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; #endif /* * Mutex to protect localtime(3) when no reentrant version available. */ #ifndef _WIN32 #ifndef HAVE_LOCALTIME_R #ifdef TCL_THREADS TCL_DECLARE_MUTEX(localtimeMutex) #endif #endif #endif /* * In-core description of mounted ZIP archive file. */ typedef struct ZipFile { char *name; /* Archive name */ size_t namelen; char is_membuf; /* When true, not a file but a memory buffer */ Tcl_Channel chan; /* Channel handle or NULL */ unsigned char *data; /* Memory mapped or malloc'ed file */ size_t length; /* Length of memory mapped file */ void *tofree; /* Non-NULL if malloc'ed file */ size_t nfiles; /* Number of files in archive */ size_t baseoffs; /* Archive start */ size_t baseoffsp; /* Password start */ size_t centoffs; /* Archive directory start */ unsigned char pwbuf[264]; /* Password buffer */ size_t nopen; /* Number of open files on archive */ struct ZipEntry *entries; /* List of files in archive */ struct ZipEntry *topents; /* List of top-level dirs in archive */ size_t mntptlen; char *mntpt; /* Mount point */ #ifdef _WIN32 HANDLE mh; int mntdrv; /* Drive letter of mount point */ #endif } ZipFile; /* * In-core description of file contained in mounted ZIP archive. */ typedef struct ZipEntry { |
︙ | ︙ | |||
512 513 514 515 516 517 518 | static int ToDosTime(time_t when) { struct tm *tmp, tm; #ifdef TCL_THREADS | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | static int ToDosTime(time_t when) { struct tm *tmp, tm; #ifdef TCL_THREADS #ifdef _WIN32 /* Win32 uses thread local storage */ tmp = localtime(&when); tm = *tmp; #else #ifdef HAVE_LOCALTIME_R tmp = &tm; localtime_r(&when, tmp); |
︙ | ︙ | |||
540 541 542 543 544 545 546 | static int ToDosDate(time_t when) { struct tm *tmp, tm; #ifdef TCL_THREADS | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | static int ToDosDate(time_t when) { struct tm *tmp, tm; #ifdef TCL_THREADS #ifdef _WIN32 /* Win32 uses thread local storage */ tmp = localtime(&when); tm = *tmp; #else #ifdef HAVE_LOCALTIME_R tmp = &tm; localtime_r(&when, tmp); |
︙ | ︙ | |||
617 618 619 620 621 622 623 | static char * CanonicalPath(const char *root, const char *tail, Tcl_DString *dsPtr,int ZIPFSPATH) { char *path; char *result; int i, j, c, isunc = 0, isvfs=0, n=0; | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | static char * CanonicalPath(const char *root, const char *tail, Tcl_DString *dsPtr,int ZIPFSPATH) { char *path; char *result; int i, j, c, isunc = 0, isvfs=0, n=0; #ifdef _WIN32 int zipfspath=1; if ( (tail[0] != '\0') && (strchr(drvletters, tail[0]) != NULL) && (tail[1] == ':') ) { tail += 2; |
︙ | ︙ | |||
651 652 653 654 655 656 657 | isvfs=2; } if(isvfs!=1) { if ((root[0] == '/') && (root[1] == '/')) { isunc = 1; } } | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | isvfs=2; } if(isvfs!=1) { if ((root[0] == '/') && (root[1] == '/')) { isunc = 1; } } #ifdef _WIN32 } #endif if(isvfs!=2) { if (tail[0] == '/') { if(isvfs!=1) { root = ""; } |
︙ | ︙ | |||
703 704 705 706 707 708 709 | Tcl_DStringSetLength(dsPtr, i + j + 1); path = Tcl_DStringValue(dsPtr); memcpy(path, root, i); path[i++] = '/'; memcpy(path + i, tail, j); } } | | | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | Tcl_DStringSetLength(dsPtr, i + j + 1); path = Tcl_DStringValue(dsPtr); memcpy(path, root, i); path[i++] = '/'; memcpy(path + i, tail, j); } } #ifdef _WIN32 for (i = 0; path[i] != '\0'; i++) { if (path[i] == '\\') { path[i] = '/'; } } #endif if(ZIPFSPATH) { |
︙ | ︙ | |||
853 854 855 856 857 858 859 | { if(zf->namelen) { free(zf->name); //Allocated by strdup } if(zf->is_membuf==1) { /* Pointer to memory */ if (zf->tofree != NULL) { | | | | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | { if(zf->namelen) { free(zf->name); //Allocated by strdup } if(zf->is_membuf==1) { /* Pointer to memory */ if (zf->tofree != NULL) { Tcl_Free(zf->tofree); zf->tofree = NULL; } zf->data = NULL; return; } #ifdef _WIN32 if ((zf->data != NULL) && (zf->tofree == NULL)) { UnmapViewOfFile(zf->data); zf->data = NULL; } if (zf->mh != INVALID_HANDLE_VALUE) { CloseHandle(zf->mh); } #else if ((zf->data != MAP_FAILED) && (zf->tofree == NULL)) { munmap(zf->data, zf->length); zf->data = MAP_FAILED; } #endif if (zf->tofree != NULL) { Tcl_Free(zf->tofree); zf->tofree = NULL; } if(zf->chan != NULL) { Tcl_Close(interp, zf->chan); zf->chan = NULL; } } |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | static int ZipFSOpenArchive(Tcl_Interp *interp, const char *zipname, int needZip, ZipFile *zf) { size_t i; ClientData handle; zf->namelen=0; zf->is_membuf=0; | | | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | static int ZipFSOpenArchive(Tcl_Interp *interp, const char *zipname, int needZip, ZipFile *zf) { size_t i; ClientData handle; zf->namelen=0; zf->is_membuf=0; #ifdef _WIN32 zf->data = NULL; zf->mh = INVALID_HANDLE_VALUE; #else zf->data = MAP_FAILED; #endif zf->length = 0; zf->nfiles = 0; |
︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 | if (i != zf->length) { ZIPFS_ERROR(interp,"file read error"); goto error; } Tcl_Close(interp, zf->chan); zf->chan = NULL; } else { | | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | if (i != zf->length) { ZIPFS_ERROR(interp,"file read error"); goto error; } Tcl_Close(interp, zf->chan); zf->chan = NULL; } else { #ifdef _WIN32 # ifdef _WIN64 i = GetFileSizeEx((HANDLE) handle, (PLARGE_INTEGER)&zf->length); if ( (i == 0) || # else zf->length = GetFileSize((HANDLE) handle, 0); if ( |
︙ | ︙ | |||
1915 1916 1917 1918 1919 1920 1921 | char *buf, int bufsize, Tcl_HashTable *fileHash ) { Tcl_Channel in; Tcl_HashEntry *hPtr; ZipEntry *z; z_stream stream; const char *zpath; | | | | 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 | char *buf, int bufsize, Tcl_HashTable *fileHash ) { Tcl_Channel in; Tcl_HashEntry *hPtr; ZipEntry *z; z_stream stream; const char *zpath; int crc, flush, zpathlen; size_t nbyte, nbytecompr, len, olen, align = 0; Tcl_WideInt pos[3]; int mtime = 0, isNew, cmeth; unsigned long keys[3], keys0[3]; char obuf[4096]; zpath = name; while (zpath != NULL && zpath[0] == '/') { |
︙ | ︙ | |||
1940 1941 1942 1943 1944 1945 1946 | } in = Tcl_OpenFileChannel(interp, path, "r", 0); if ( (in == NULL) || (Tcl_SetChannelOption(interp, in, "-translation", "binary") != TCL_OK) || (Tcl_SetChannelOption(interp, in, "-encoding", "binary") != TCL_OK) ) { | | | 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 | } in = Tcl_OpenFileChannel(interp, path, "r", 0); if ( (in == NULL) || (Tcl_SetChannelOption(interp, in, "-translation", "binary") != TCL_OK) || (Tcl_SetChannelOption(interp, in, "-encoding", "binary") != TCL_OK) ) { #ifdef _WIN32 /* hopefully a directory */ if (strcmp("permission denied", Tcl_PosixError(interp)) == 0) { Tcl_Close(interp, in); return TCL_OK; } #endif Tcl_Close(interp, in); |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 | (char *) NULL); deflateEnd(&stream); Tcl_Close(interp, in); return TCL_ERROR; } olen = sizeof (obuf) - stream.avail_out; if (passwd != NULL) { | > | | | 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 | (char *) NULL); deflateEnd(&stream); Tcl_Close(interp, in); return TCL_ERROR; } olen = sizeof (obuf) - stream.avail_out; if (passwd != NULL) { size_t i; int tmp; for (i = 0; i < olen; i++) { obuf[i] = (char) zencode(keys, crc32tab, obuf[i], tmp); } } if (olen && ((size_t)Tcl_Write(out, obuf, olen) != olen)) { Tcl_AppendResult(interp, "write error", (char *) NULL); deflateEnd(&stream); Tcl_Close(interp, in); return TCL_ERROR; } nbytecompr += olen; } while (stream.avail_out == 0); |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 | Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(z->name, -1)); } } Unlock(); return TCL_OK; } | | | 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 | Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(z->name, -1)); } } Unlock(); return TCL_OK; } #ifdef _WIN32 #define LIBRARY_SIZE 64 static int ToUtf( const WCHAR *wSrc, char *dst) { char *start; |
︙ | ︙ | |||
2894 2895 2896 2897 2898 2899 2900 | Tcl_Obj *TclZipfs_TclLibrary(void) { if(zipfs_literal_tcl_library) { return Tcl_NewStringObj(zipfs_literal_tcl_library,-1); } else { Tcl_Obj *vfsinitscript; int found=0; | | | | 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 | Tcl_Obj *TclZipfs_TclLibrary(void) { if(zipfs_literal_tcl_library) { return Tcl_NewStringObj(zipfs_literal_tcl_library,-1); } else { Tcl_Obj *vfsinitscript; int found=0; #ifdef _WIN32 HMODULE hModule = TclWinGetTclInstance(); WCHAR wName[MAX_PATH + LIBRARY_SIZE]; char dllname[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX]; #endif /* Look for the library file system within the executable */ vfsinitscript=Tcl_NewStringObj(ZIPFS_APP_MOUNT "/tcl_library/init.tcl",-1); Tcl_IncrRefCount(vfsinitscript); found=Tcl_FSAccess(vfsinitscript,F_OK); Tcl_DecrRefCount(vfsinitscript); if(found==TCL_OK) { zipfs_literal_tcl_library=ZIPFS_APP_MOUNT "/tcl_library"; return Tcl_NewStringObj(zipfs_literal_tcl_library,-1); } #ifdef _WIN32 if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) { GetModuleFileNameA(hModule, dllname, MAX_PATH); } else { ToUtf(wName, dllname); } /* Mount zip file and dll before releasing to search */ if(TclZipfs_AppHook_FindTclInit(dllname)==TCL_OK) { |
︙ | ︙ | |||
4397 4398 4399 4400 4401 4402 4403 | if(found==0) { zipfs_literal_tcl_library=ZIPFS_ZIP_MOUNT "/tcl_library"; return TCL_OK; } return TCL_ERROR; } | | > > > | 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 | if(found==0) { zipfs_literal_tcl_library=ZIPFS_ZIP_MOUNT "/tcl_library"; return TCL_OK; } return TCL_ERROR; } #ifdef _WIN32 int TclZipfs_AppHook(int *argc, TCHAR ***argv) #else int TclZipfs_AppHook(int *argc, char ***argv) #endif { #ifdef _WIN32 Tcl_DString ds; #endif /* * Tclkit_MainHook -- * Performs the argument munging for the shell */ char *archive; Tcl_FindExecutable((*argv)[0]); |
︙ | ︙ | |||
4438 4439 4440 4441 4442 4443 4444 | Tcl_DecrRefCount(vfsinitscript); if(found==TCL_OK) { zipfs_literal_tcl_library=ZIPFS_APP_MOUNT "/tcl_library"; return TCL_OK; } } } else if (*argc>1) { | > | < | < | | 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 | Tcl_DecrRefCount(vfsinitscript); if(found==TCL_OK) { zipfs_literal_tcl_library=ZIPFS_APP_MOUNT "/tcl_library"; return TCL_OK; } } } else if (*argc>1) { return TCL_OK; #ifdef _WIN32 archive = Tcl_WinTCharToUtf((*argv)[1], -1, &ds); #else archive=(*argv)[1]; #endif if (strcmp(archive,"install")==0) { /* If the first argument is mkzip, run the mkzip program */ Tcl_Obj *vfsinitscript; /* Run this now to ensure the file is present by the time Tcl_Main wants it */ TclZipfs_TclLibrary(); vfsinitscript=Tcl_NewStringObj(ZIPFS_ZIP_MOUNT "/tcl_library/install.tcl",-1); Tcl_IncrRefCount(vfsinitscript); if(Tcl_FSAccess(vfsinitscript,F_OK)==0) { |
︙ | ︙ | |||
4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 | Tcl_DecrRefCount(vfsinitscript); if(found==TCL_OK) { zipfs_literal_tcl_library=ZIPFS_APP_MOUNT "/tcl_library"; return TCL_OK; } } } } return TCL_OK; } | > > > < | 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 | Tcl_DecrRefCount(vfsinitscript); if(found==TCL_OK) { zipfs_literal_tcl_library=ZIPFS_APP_MOUNT "/tcl_library"; return TCL_OK; } } } #ifdef _WIN32 Tcl_DStringFree(&ds); #endif } return TCL_OK; } #ifndef HAVE_ZLIB /* *------------------------------------------------------------------------- * |
︙ | ︙ |
Changes to generic/tclZlib.c.
︙ | ︙ | |||
3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 | */ cfg[0].key = "zlibVersion"; cfg[0].value = zlibVersion(); cfg[1].key = NULL; Tcl_RegisterConfig(interp, "zlib", cfg, "iso8859-1"); /* * Formally provide the package as a Tcl built-in. */ return Tcl_PkgProvide(interp, "zlib", TCL_ZLIB_VERSION); } | > > > > > > | 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 | */ cfg[0].key = "zlibVersion"; cfg[0].value = zlibVersion(); cfg[1].key = NULL; Tcl_RegisterConfig(interp, "zlib", cfg, "iso8859-1"); /* * Allow command type introspection to do something sensible with streams. */ TclRegisterCommandTypeName(ZlibStreamCmd, "zlibStream"); /* * Formally provide the package as a Tcl built-in. */ return Tcl_PkgProvide(interp, "zlib", TCL_ZLIB_VERSION); } |
︙ | ︙ |
Changes to library/http/http.tcl.
︙ | ︙ | |||
96 97 98 99 100 101 102 | array set socketMapping {} array set socketRdState {} array set socketWrState {} array set socketRdQueue {} array set socketWrQueue {} array set socketClosing {} array set socketPlayCmd {} | < | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | array set socketMapping {} array set socketRdState {} array set socketWrState {} array set socketRdQueue {} array set socketWrQueue {} array set socketClosing {} array set socketPlayCmd {} } init variable urlTypes if {![info exists urlTypes]} { set urlTypes(http) [list 80 ::socket] } |
︙ | ︙ | |||
124 125 126 127 128 129 130 | # Let user control default keepalive for compatibility variable defaultKeepalive if {![info exists defaultKeepalive]} { set defaultKeepalive 0 } | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | # Let user control default keepalive for compatibility variable defaultKeepalive if {![info exists defaultKeepalive]} { set defaultKeepalive 0 } namespace export geturl config reset wait formatQuery quoteString namespace export register unregister registerError # - Useful, but not exported: data, size, status, code, cleanup, error, # meta, ncode, mapReply, init. Comments suggest that "init" can be used # for re-initialisation, although the command is undocumented. # - Not exported, probably should be upper-case initial letter as part # of the internals: getTextLine, make-transformation-chunked. } |
︙ | ︙ | |||
157 158 159 160 161 162 163 | # command Command to use to create socket # Results: # list of port and command that was registered. proc http::register {proto port command} { variable urlTypes set urlTypes([string tolower $proto]) [list $port $command] | < | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | # command Command to use to create socket # Results: # list of port and command that was registered. proc http::register {proto port command} { variable urlTypes set urlTypes([string tolower $proto]) [list $port $command] } # http::unregister -- # # Unregisters URL protocol handler # # Arguments: |
︙ | ︙ | |||
215 216 217 218 219 220 221 | } else { foreach {flag value} $args { if {![regexp -- $pat $flag]} { return -code error "Unknown option $flag, must be: $usage" } set http($flag) $value } | < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | } else { foreach {flag value} $args { if {![regexp -- $pat $flag]} { return -code error "Unknown option $flag, must be: $usage" } set http($flag) $value } } } # http::Finish -- # # Clean up the socket and eval close time callbacks # |
︙ | ︙ | |||
289 290 291 292 293 294 295 | if { $closeQueue && [info exists socketMapping($connId)] && ($socketMapping($connId) eq $sock) } { http::CloseQueuedQueries $connId $token } | < < | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | if { $closeQueue && [info exists socketMapping($connId)] && ($socketMapping($connId) eq $sock) } { http::CloseQueuedQueries $connId $token } } # http::KeepSocket - # # Keep a socket in the persistent sockets table and connect it to its next # queued task if possible. Otherwise leave it idle and ready for its next # use. |
︙ | ︙ | |||
331 332 333 334 335 336 337 | # The line below should not be changed in production code. # It is edited by the test suite. set TEST_EOF 0 if {$TEST_EOF} { # ONLY for testing reaction to server eof. # No server timeouts will be caught. catch {fileevent $state(sock) readable {}} | < < < | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | # The line below should not be changed in production code. # It is edited by the test suite. set TEST_EOF 0 if {$TEST_EOF} { # ONLY for testing reaction to server eof. # No server timeouts will be caught. catch {fileevent $state(sock) readable {}} } if { [info exists state(socketinfo)] && [info exists socketMapping($state(socketinfo))] } { set connId $state(socketinfo) # The value "Rready" is set only here. |
︙ | ︙ | |||
382 383 384 385 386 387 388 | } { # This case: # - Now it the time to run the "pending" request. # - The next token in the write queue is nonpipeline, and # socketWrState has been marked "pending" (in # http::NextPipelinedWrite or http::geturl) so a new pipelined # request cannot jump the queue. | | | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | } { # This case: # - Now it the time to run the "pending" request. # - The next token in the write queue is nonpipeline, and # socketWrState has been marked "pending" (in # http::NextPipelinedWrite or http::geturl) so a new pipelined # request cannot jump the queue. # # Tests: # - In this case the read queue (tested above) is empty and this # "pending" write token is in front of the rest of the write # queue. # - The write state is not Wready and therefore appears to be busy, # but because it is "pending" we know that it is reserved for the # first item in the write queue, a non-pipelined request that is |
︙ | ︙ | |||
472 473 474 475 476 477 478 | # Connect does its own fconfigure. fileevent $state(sock) writable [list http::Connect $token3 {*}$conn] #Log ---- $state(sock) << conn to $token3 for HTTP request (d) } elseif {(!$state(-pipeline))} { set socketWrState($connId) Wready # Rready and Wready and idle: nothing to do. | < < < | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | # Connect does its own fconfigure. fileevent $state(sock) writable [list http::Connect $token3 {*}$conn] #Log ---- $state(sock) << conn to $token3 for HTTP request (d) } elseif {(!$state(-pipeline))} { set socketWrState($connId) Wready # Rready and Wready and idle: nothing to do. } } else { CloseSocket $state(sock) $token # There is no socketMapping($state(socketinfo)), so it does not matter # that CloseQueuedQueries is not called. } } # http::CheckEof - # # Read from a socket and close it if eof. # The command is bound to "fileevent readable" on an idle socket, and # "eof" is the only event that should trigger the binding, occurring when |
︙ | ︙ | |||
507 508 509 510 511 512 513 | if {[catch {eof $sock} res] || $res} { # The server has half-closed the socket. # If a new write has started, its transaction will fail and # will then be error-handled. CloseSocket $sock } | < | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | if {[catch {eof $sock} res] || $res} { # The server has half-closed the socket. # If a new write has started, its transaction will fail and # will then be error-handled. CloseSocket $sock } } # http::CloseSocket - # # Close a socket and remove it from the persistent sockets table. If # possible an http token is included here but when we are called from a # fileevent on remote closure we need to find the correct entry - hence |
︙ | ︙ | |||
535 536 537 538 539 540 541 | catch {fileevent $s readable {}} set connId {} if {$token ne ""} { variable $token upvar 0 $token state if {[info exists state(socketinfo)]} { set connId $state(socketinfo) | < < < < < < | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | catch {fileevent $s readable {}} set connId {} if {$token ne ""} { variable $token upvar 0 $token state if {[info exists state(socketinfo)]} { set connId $state(socketinfo) } } else { set map [array get socketMapping] set ndx [lsearch -exact $map $s] if {$ndx != -1} { incr ndx -1 set connId [lindex $map $ndx] } } if { ($connId ne {}) && [info exists socketMapping($connId)] && ($socketMapping($connId) eq $s) } { Log "Closing connection $connId (sock $socketMapping($connId))" if {[catch {close $socketMapping($connId)} err]} { Log "Error closing connection: $err" } if {$token eq {}} { # Cases with a non-empty token are handled by Finish, so the tokens # are finished in connection order. http::CloseQueuedQueries $connId } } else { Log "Closing socket $s (no connection info)" if {[catch {close $s} err]} { Log "Error closing socket: $err" } } } # http::CloseQueuedQueries # # connId - identifier "domain:port" for the connection # token - (optional) used only for logging # |
︙ | ︙ | |||
625 626 627 628 629 630 631 | Unset $connId if {$unfinished ne {}} { Log ^R$tk Any unfinished transactions (excluding $token) failed \ - token $token {*}$unfinished } | < | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | Unset $connId if {$unfinished ne {}} { Log ^R$tk Any unfinished transactions (excluding $token) failed \ - token $token {*}$unfinished } } # http::Unset # # The trace on "unset socketRdState(*)" will call CancelReadPipeline # and cancel any queued responses. # The trace on "unset socketWrState(*)" will call CancelWritePipeline |
︙ | ︙ | |||
651 652 653 654 655 656 657 | unset socketMapping($connId) unset socketRdState($connId) unset socketWrState($connId) unset -nocomplain socketRdQueue($connId) unset -nocomplain socketWrQueue($connId) unset -nocomplain socketClosing($connId) unset -nocomplain socketPlayCmd($connId) | < < | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | unset socketMapping($connId) unset socketRdState($connId) unset socketWrState($connId) unset -nocomplain socketRdQueue($connId) unset -nocomplain socketWrQueue($connId) unset -nocomplain socketClosing($connId) unset -nocomplain socketPlayCmd($connId) } # http::reset -- # # See documentation for details. # # Arguments: |
︙ | ︙ | |||
678 679 680 681 682 683 684 | catch {fileevent $state(sock) writable {}} Finish $token if {[info exists state(error)]} { set errorlist $state(error) unset state eval ::error $errorlist } | < | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | catch {fileevent $state(sock) writable {}} Finish $token if {[info exists state(error)]} { set errorlist $state(error) unset state eval ::error $errorlist } } # http::geturl -- # # Establishes a connection to a remote url via http. # # Arguments: |
︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 | set socketWrState($state(socketinfo)) $token } elseif {$reusing} { # Cf tests above - both are ready. #Log re-use nonpipeline, GRANT r/w access to $token in geturl set socketRdState($state(socketinfo)) $token set socketWrState($state(socketinfo)) $token | < < < | 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | set socketWrState($state(socketinfo)) $token } elseif {$reusing} { # Cf tests above - both are ready. #Log re-use nonpipeline, GRANT r/w access to $token in geturl set socketRdState($state(socketinfo)) $token set socketWrState($state(socketinfo)) $token } # All (!$reusing) cases come here, and also some $reusing cases if the # connection is ready. #Log ---- $state(socketinfo) << conn to $token for HTTP request (a) # Connect does its own fconfigure. fileevent $sock writable \ |
︙ | ︙ | |||
1524 1525 1526 1527 1528 1529 1530 | # be discarded. } elseif {$state(status) eq ""} { # ...https handshake errors come here. set msg [registerError $sock] registerError $sock {} if {$msg eq {}} { set msg {failed to use socket} | < < < < < | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 | # be discarded. } elseif {$state(status) eq ""} { # ...https handshake errors come here. set msg [registerError $sock] registerError $sock {} if {$msg eq {}} { set msg {failed to use socket} } Finish $token $msg } elseif {$state(status) ne "error"} { Finish $token $err } } } # http::registerError # # Called (for example when processing TclTLS activity) to register # an error for a connection on a specific socket. This helps # http::Connected to deliver meaningful error messages, e.g. when a TLS |
︙ | ︙ | |||
1563 1564 1565 1566 1567 1568 1569 | } elseif { ([llength $args] == 1) && ([lindex $args 0] eq {}) } { unset -nocomplain registeredErrors($sock) return } set registeredErrors($sock) {*}$args | < | 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | } elseif { ([llength $args] == 1) && ([lindex $args 0] eq {}) } { unset -nocomplain registeredErrors($sock) return } set registeredErrors($sock) {*}$args } # http::DoneRequest -- # # Command called when a request has been sent. It will arrange the # next request and/or response as appropriate. # |
︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 | lappend socketRdQueue($state(socketinfo)) $token } else { # In the pipelined case, connection for reading depends on the # value of socketRdState. # In the nonpipeline case, connection for reading always occurs. ReceiveResponse $token } | < < | 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | lappend socketRdQueue($state(socketinfo)) $token } else { # In the pipelined case, connection for reading depends on the # value of socketRdState. # In the nonpipeline case, connection for reading always occurs. ReceiveResponse $token } } # http::ReceiveResponse # # Connects token to its socket for reading. proc http::ReceiveResponse {token} { variable $token upvar 0 $token state set tk [namespace tail $token] set sock $state(sock) #Log ---- $state(socketinfo) >> conn to $token for HTTP response lassign [fconfigure $sock -translation] trRead trWrite fconfigure $sock -translation [list auto $trWrite] \ -buffersize $state(-blocksize) Log ^D$tk begin receiving response - token $token coroutine ${token}EventCoroutine http::Event $sock $token fileevent $sock readable ${token}EventCoroutine } # http::NextPipelinedWrite # # - Connecting a socket to a token for writing is done by this command and by # command KeepSocket. # - If another request has a pipelined write scheduled for $token's socket, |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 | # pipelined request (in http::geturl) jumping the queue. # - Because socketWrState($connId) is not set to Wready, the assignment # of the connection to $token2 will be done elsewhere - by command # http::KeepSocket when $socketRdState($connId) is set to "Rready". #Log re-use nonpipeline, GRANT delayed write access to $token in NextP.. set socketWrState($connId) peNding | | < < < < < | 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 | # pipelined request (in http::geturl) jumping the queue. # - Because socketWrState($connId) is not set to Wready, the assignment # of the connection to $token2 will be done elsewhere - by command # http::KeepSocket when $socketRdState($connId) is set to "Rready". #Log re-use nonpipeline, GRANT delayed write access to $token in NextP.. set socketWrState($connId) peNding } } # http::CancelReadPipeline # # Cancel pipelined responses on a closing "Keep-Alive" socket. # # - Called by a variable trace on "unset socketRdState($connId)". |
︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 | set tk [namespace tail $token] Log ^X$tk end of response "($msg)" - token $token set ${token}(status) eof Finish $token ;#$msg } set socketRdQueue($connId) {} } | < | 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 | set tk [namespace tail $token] Log ^X$tk end of response "($msg)" - token $token set ${token}(status) eof Finish $token ;#$msg } set socketRdQueue($connId) {} } } # http::CancelWritePipeline # # Cancel queued events on a closing "Keep-Alive" socket. # # - Called by a variable trace on "unset socketWrState($connId)". |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | set tk [namespace tail $token] Log ^X$tk end of response "($msg)" - token $token set ${token}(status) eof Finish $token ;#$msg } set socketWrQueue($connId) {} } | < | 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 | set tk [namespace tail $token] Log ^X$tk end of response "($msg)" - token $token set ${token}(status) eof Finish $token ;#$msg } set socketWrQueue($connId) {} } } # http::ReplayIfDead -- # # - A query on a re-used persistent socket failed at the earliest opportunity, # because the socket had been closed by the server. Keep the token, tidy up, # and try to connect on a fresh socket. |
︙ | ︙ | |||
1903 1904 1905 1906 1907 1908 1909 | if { [info exists socketRdState($stateArg(socketinfo))] && ($socketRdState($stateArg(socketinfo)) ne "Rready") } { lappend InFlightR $socketRdState($stateArg(socketinfo)) } elseif {($doing eq "read")} { lappend InFlightR $tokenArg | < < < < < | 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 | if { [info exists socketRdState($stateArg(socketinfo))] && ($socketRdState($stateArg(socketinfo)) ne "Rready") } { lappend InFlightR $socketRdState($stateArg(socketinfo)) } elseif {($doing eq "read")} { lappend InFlightR $tokenArg } if { [info exists socketWrState($stateArg(socketinfo))] && $socketWrState($stateArg(socketinfo)) ni {Wready peNding} } { lappend InFlightW $socketWrState($stateArg(socketinfo)) } elseif {($doing eq "write")} { lappend InFlightW $tokenArg } # Report any inconsistency of $tokenArg with socket*state. if { ($doing eq "read") && [info exists socketRdState($stateArg(socketinfo))] && ($tokenArg ne $socketRdState($stateArg(socketinfo))) } { Log WARNING - ReplayIfDead pipelined tokenArg $tokenArg $doing \ ne socketRdState($stateArg(socketinfo)) \ $socketRdState($stateArg(socketinfo)) } elseif { ($doing eq "write") && [info exists socketWrState($stateArg(socketinfo))] && ($tokenArg ne $socketWrState($stateArg(socketinfo))) } { Log WARNING - ReplayIfDead pipelined tokenArg $tokenArg $doing \ ne socketWrState($stateArg(socketinfo)) \ $socketWrState($stateArg(socketinfo)) } } else { # One transaction should be in flight. # socketRdState, socketWrQueue are used. # socketRdQueue should be empty. # Report any inconsistency of $tokenArg with socket*state. if {$tokenArg ne $socketRdState($stateArg(socketinfo))} { Log WARNING - ReplayIfDead nonpipeline tokenArg $tokenArg $doing \ ne socketRdState($stateArg(socketinfo)) \ $socketRdState($stateArg(socketinfo)) } # Report the inconsistency that socketRdQueue is non-empty. if { [info exists socketRdQueue($stateArg(socketinfo))] && ($socketRdQueue($stateArg(socketinfo)) ne {}) } { Log WARNING - ReplayIfDead nonpipeline tokenArg $tokenArg $doing \ has read queue socketRdQueue($stateArg(socketinfo)) \ $socketRdQueue($stateArg(socketinfo)) ne {} } lappend InFlightW $socketRdState($stateArg(socketinfo)) set socketRdQueue($stateArg(socketinfo)) {} } set newQueue {} |
︙ | ︙ | |||
1985 1986 1987 1988 1989 1990 1991 | # - All tokens are preserved for re-use by ReplayCore, and their variables # will be re-initialised by calls to ReInit. # - The relevant element of socketMapping, socketRdState, socketWrState, # socketRdQueue, socketWrQueue, socketClosing, socketPlayCmd will be set # to new values in ReplayCore. ReplayCore $newQueue | < | 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 | # - All tokens are preserved for re-use by ReplayCore, and their variables # will be re-initialised by calls to ReInit. # - The relevant element of socketMapping, socketRdState, socketWrState, # socketRdQueue, socketWrQueue, socketClosing, socketPlayCmd will be set # to new values in ReplayCore. ReplayCore $newQueue } # http::ReplayIfClose -- # # A request on a socket that was previously "Connection: keep-alive" has # received a "Connection: close" response header. The server supplies # that response correctly, but any later requests already queued on this |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | lappend newQueue {*}$Rqueue lappend newQueue {*}$InFlightW lappend newQueue {*}$Wqueue # 2. Cleanup - none needed, done by the caller. ReplayCore $newQueue | < | 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 | lappend newQueue {*}$Rqueue lappend newQueue {*}$InFlightW lappend newQueue {*}$Wqueue # 2. Cleanup - none needed, done by the caller. ReplayCore $newQueue } # http::ReInit -- # # Command to restore a token's state to a condition that # makes it ready to replay a request. # |
︙ | ︙ | |||
2232 2233 2234 2235 2236 2237 2238 | ##Log socket opened, now fconfigure - token $token fconfigure $sock -translation {auto crlf} -buffersize $state(-blocksize) ##Log socket opened, DONE fconfigure - token $token # Connect does its own fconfigure. fileevent $sock writable [list http::Connect $token {*}$tmpConnArgs] #Log ---- $sock << conn to $token for HTTP request (e) | < | 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 | ##Log socket opened, now fconfigure - token $token fconfigure $sock -translation {auto crlf} -buffersize $state(-blocksize) ##Log socket opened, DONE fconfigure - token $token # Connect does its own fconfigure. fileevent $sock writable [list http::Connect $token {*}$tmpConnArgs] #Log ---- $sock << conn to $token for HTTP request (e) } # Data access functions: # Data - the URL data # Status - the transaction status: ok, reset, eof, timeout, error # Code - the HTTP transaction code, e.g., 200 # Size - the size of the URL data |
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 | if {[info exists state(after)]} { after cancel $state(after) unset state(after) } if {[info exists state]} { unset state } | < | 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 | if {[info exists state(after)]} { after cancel $state(after) unset state(after) } if {[info exists state]} { unset state } } # http::Connect # # This callback is made when an asyncronous connection completes. # # Arguments |
︙ | ︙ | |||
2354 2355 2356 2357 2358 2359 2360 | } Finish $token "connect failed $err" } else { set state(state) connecting fileevent $state(sock) writable {} ::http::Connected $token $proto $phost $srvurl } | < | 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 | } Finish $token "connect failed $err" } else { set state(state) connecting fileevent $state(sock) writable {} ::http::Connected $token $proto $phost $srvurl } } # http::Write # # Write POST query data to the socket # # Arguments |
︙ | ︙ | |||
2459 2460 2461 2462 2463 2464 2465 | # Callback to the client after we've completely handled everything. if {[string length $state(-queryprogress)]} { eval $state(-queryprogress) \ [list $token $state(querylength) $state(queryoffset)] } | < | 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 | # Callback to the client after we've completely handled everything. if {[string length $state(-queryprogress)]} { eval $state(-queryprogress) \ [list $token $state(querylength) $state(queryoffset)] } } # http::Event # # Handle input on the socket. This command is the core of # the coroutine commands ${token}EventCoroutine that are # bound to "fileevent $sock readable" and process input. |
︙ | ︙ | |||
2556 2557 2558 2559 2560 2561 2562 | } # else: # This is NOT a persistent socket that has been closed since its # last use. # If any other requests are in flight or pipelined/queued, they # will be discarded. | < < < < | 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 | } # else: # This is NOT a persistent socket that has been closed since its # last use. # If any other requests are in flight or pipelined/queued, they # will be discarded. } } elseif {$state(state) eq "header"} { if {[catch {gets $sock line} nhl]} { ##Log header failed - token $token Log ^X$tk end of response (error) - token $token Finish $token $nhl return |
︙ | ︙ | |||
2791 2792 2793 2794 2795 2796 2797 | # HTTP/1.0 equivalent; or it MUST fail (as # above) if the server sends # "Connection: keep-alive" or the HTTP/1.0 # equivalent. set n 0 set state(state) complete } | < | 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 | # HTTP/1.0 equivalent; or it MUST fail (as # above) if the server sends # "Connection: keep-alive" or the HTTP/1.0 # equivalent. set n 0 set state(state) complete } } } elseif {[info exists state(transfer_final)]} { # This code forgives EOF in place of the final CRLF. set line [getTextLine $sock] set n [string length $line] set state(state) complete if {$n > 0} { |
︙ | ︙ | |||
2951 2952 2953 2954 2955 2956 2957 | } else { # open connection closed on a token that has been cleaned up. Log ^X$tk end of response (token error) - token $token CloseSocket $sock } } elseif {$cc} { return | < < < | 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 | } else { # open connection closed on a token that has been cleaned up. Log ^X$tk end of response (token error) - token $token CloseSocket $sock } } elseif {$cc} { return } } } # http::TestForReplay # # Command called if eof is discovered when a socket is first used for a # new transaction. Typically this occurs if a persistent socket is used # after a period of idleness and the server has half-closed the socket. |
︙ | ︙ | |||
3144 3145 3146 3147 3148 3149 3150 | # solution. fcopy $sock $state(-channel) -size $state(-blocksize) -command \ [list http::CopyDone $token] } err]} { Finish $token $err } } | < | 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 | # solution. fcopy $sock $state(-channel) -size $state(-blocksize) -command \ [list http::CopyDone $token] } err]} { Finish $token $err } } } proc http::CopyChunk {token chunk} { upvar 0 $token state if {[set count [string length $chunk]]} { incr state(currentsize) $count if {[info exists state(zlib)]} { |
︙ | ︙ | |||
3174 3175 3176 3177 3178 3179 3180 | } puts -nonewline $state(-channel) $excess foreach stream $state(zlib) { $stream close } unset state(zlib) } Eot $token ;# FIX ME: pipelining. } | < | 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | } puts -nonewline $state(-channel) $excess foreach stream $state(zlib) { $stream close } unset state(zlib) } Eot $token ;# FIX ME: pipelining. } } # http::CopyDone # # fcopy completion callback # # Arguments |
︙ | ︙ | |||
3205 3206 3207 3208 3209 3210 3211 | if {[string length $error]} { Finish $token $error } elseif {[catch {eof $sock} iseof] || $iseof} { Eot $token } else { CopyStart $sock $token 0 } | < | 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 | if {[string length $error]} { Finish $token $error } elseif {[catch {eof $sock} iseof] || $iseof} { Eot $token } else { CopyStart $sock $token 0 } } # http::Eot # # Called when either: # a. An eof condition is detected on the socket. # b. The client decides that the response is complete. |
︙ | ︙ | |||
3275 3276 3277 3278 3279 3280 3281 | } # Translate text line endings. set state(body) [string map {\r\n \n \r \n} $state(body)] } } Finish $token $reason | < | 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 | } # Translate text line endings. set state(body) [string map {\r\n \n \r \n} $state(body)] } } Finish $token $reason } # http::wait -- # # See documentation for details. # # Arguments: |
︙ | ︙ | |||
3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 | # Arguments: # args A list of name-value pairs. # # Results: # TODO proc http::formatQuery {args} { set result "" set sep "" foreach i $args { append result $sep [mapReply $i] if {$sep eq "="} { set sep & } else { | > > > > > > | 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 | # Arguments: # args A list of name-value pairs. # # Results: # TODO proc http::formatQuery {args} { if {[llength $args] % 2} { return \ -code error \ -errorcode [list HTTP BADARGCNT $args] \ {Incorrect number of arguments, must be an even number.} } set result "" set sep "" foreach i $args { append result $sep [mapReply $i] if {$sep eq "="} { set sep & } else { |
︙ | ︙ | |||
3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 | regexp "\[\u0100-\uffff\]" $converted badChar # Return this error message for maximum compatibility... :^/ return -code error \ "can't read \"formMap($badChar)\": no such element in array" } return $converted } # http::ProxyRequired -- # Default proxy filter. # # Arguments: # host The destination host # | > | 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 | regexp "\[\u0100-\uffff\]" $converted badChar # Return this error message for maximum compatibility... :^/ return -code error \ "can't read \"formMap($badChar)\": no such element in array" } return $converted } interp alias {} http::quoteString {} http::mapReply # http::ProxyRequired -- # Default proxy filter. # # Arguments: # host The destination host # |
︙ | ︙ | |||
3378 3379 3380 3381 3382 3383 3384 | ![info exists http(-proxyport)] || ![string length $http(-proxyport)] } { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] } | < | 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 | ![info exists http(-proxyport)] || ![string length $http(-proxyport)] } { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] } } # http::CharsetToEncoding -- # # Tries to map a given IANA charset to a tcl encoding. If no encoding # can be found, returns binary. # |
︙ | ︙ | |||
3432 3433 3434 3435 3436 3437 3438 | foreach coding [split $state(coding) ,] { switch -exact -- $coding { deflate { lappend r inflate } gzip - x-gzip { lappend r gunzip } compress - x-compress { lappend r decompress } identity {} default { | | < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | > | > | | < | 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 | foreach coding [split $state(coding) ,] { switch -exact -- $coding { deflate { lappend r inflate } gzip - x-gzip { lappend r gunzip } compress - x-compress { lappend r decompress } identity {} default { return -code error "unsupported content-encoding \"$coding\"" } } } } return $r } proc http::ReceiveChunked {chan command} { set data "" set size -1 yield while {1} { chan configure $chan -translation {crlf binary} while {[gets $chan line] < 1} { yield } chan configure $chan -translation {binary binary} if {[scan $line %x size] != 1} { return -code error "invalid size: \"$line\"" } set chunk "" while {$size && ![chan eof $chan]} { set part [chan read $chan $size] incr size -[string length $part] append chunk $part } if {[catch { uplevel #0 [linsert $command end $chunk] }]} { http::Log "Error in callback: $::errorInfo" } if {[string length $chunk] == 0} { # channel might have been closed in the callback catch {chan event $chan readable {}} return } } } proc http::make-transformation-chunked {chan command} { coroutine [namespace current]::dechunk$chan ::http::ReceiveChunked $chan $command chan event $chan readable [namespace current]::dechunk$chan } # Local variables: # indent-tabs-mode: t # End: |
Changes to tests/httpPipeline.test.
︙ | ︙ | |||
528 529 530 531 532 533 534 | return [list "$start$middle$end" $result] } # ------------------------------------------------------------------------------ # Proc MakeMessage # ------------------------------------------------------------------------------ # WHD's one-line command to generate multi-line strings from readable code. | | | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | return [list "$start$middle$end" $result] } # ------------------------------------------------------------------------------ # Proc MakeMessage # ------------------------------------------------------------------------------ # WHD's one-line command to generate multi-line strings from readable code. # # Example: # set blurb [MakeMessage { # |This command allows multi-line strings to be created with readable # |code, and without breaking the rules for indentation. # | # |The command shifts the entire block of text to the left, omitting # |the pipe character and the spaces to its left. |
︙ | ︙ |
Changes to tests/httpTest.tcl.
︙ | ︙ | |||
21 22 23 24 25 26 27 | # logs that these commands create. # ------------------------------------------------------------------------------ package require http namespace eval ::http { variable TestStartTimeInMs [clock milliseconds] | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # logs that these commands create. # ------------------------------------------------------------------------------ package require http namespace eval ::http { variable TestStartTimeInMs [clock milliseconds] # catch {puts stdout "Start time (zero ms) is $TestStartTimeInMs"} } namespace eval ::httpTest { variable testResults {} variable testOptions array set testOptions { -verbose 0 |
︙ | ︙ |
Changes to tests/httpTestScript.tcl.
︙ | ︙ | |||
492 493 494 495 496 497 498 | return $RequestsWhenStopped } proc httpTestScript::cleanupHttpTestScript {} { variable TimeOutDone variable RequestsWhenStopped | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | return $RequestsWhenStopped } proc httpTestScript::cleanupHttpTestScript {} { variable TimeOutDone variable RequestsWhenStopped if {![info exists RequestsWhenStopped]} { return -code error {Cleanup Failed: RequestsWhenStopped is undefined} } for {set i 1} {$i <= $RequestsWhenStopped} {incr i} { http::cleanup ::http::$i } |
︙ | ︙ |
Changes to tests/info.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # # DO NOT DELETE THIS LINE if {{::tcltest} ni [namespace children]} { package require tcltest 2 namespace import -force ::tcltest::* } | < > | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # # DO NOT DELETE THIS LINE if {{::tcltest} ni [namespace children]} { package require tcltest 2 namespace import -force ::tcltest::* } ::tcltest::loadTestedCommands catch [list package require -exact Tcltest [info patchlevel]] testConstraint zlib [llength [info commands zlib]] # Set up namespaces needed to test operation of "info args", "info body", # "info default", and "info procs" with imported procedures. catch {namespace delete test_ns_info1 test_ns_info2} namespace eval test_ns_info1 { namespace export * proc p {x} {return "x=$x"} proc q {{y 27} {z {}}} {return "y=$y"} } test info-1.1 {info args option} { proc t1 {a bbb c} {return foo} info args t1 } {a bbb c} test info-1.2 {info args option} { proc t1 {{a default1} {bbb default2} {c default3} args} {return foo} info a t1 |
︙ | ︙ | |||
106 107 108 109 110 111 112 | list [string bytelength [info body foo]] \ [foo; string bytelength [info body foo]] } {9 9} proc testinfocmdcount {} { set x [info cmdcount] set y 12345 | | | | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | list [string bytelength [info body foo]] \ [foo; string bytelength [info body foo]] } {9 9} proc testinfocmdcount {} { set x [info cmdcount] set y 12345 set z [info cmdc] expr {$z-$x} } test info-3.1 {info cmdcount compiled} { testinfocmdcount } 4 test info-3.2 {info cmdcount evaled} -body { set x [info cmdcount] set y 12345 set z [info cmdc] expr {$z-$x} } -cleanup {unset x y z} -result 4 test info-3.3 {info cmdcount evaled} -body [info body testinfocmdcount] -cleanup {unset x y z} -result 4 test info-3.4 {info cmdcount option} -body { info cmdcount 1 } -returnCodes error -result {wrong # args: should be "info cmdcount"} |
︙ | ︙ | |||
674 675 676 677 678 679 680 | unset functions msg test info-21.1 {miscellaneous error conditions} -returnCodes error -body { info } -result {wrong # args: should be "info subcommand ?arg ...?"} test info-21.2 {miscellaneous error conditions} -returnCodes error -body { info gorp | | | | | | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | unset functions msg test info-21.1 {miscellaneous error conditions} -returnCodes error -body { info } -result {wrong # args: should be "info subcommand ?arg ...?"} test info-21.2 {miscellaneous error conditions} -returnCodes error -body { info gorp } -result {unknown or ambiguous subcommand "gorp": must be args, body, class, cmdcount, cmdtype, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars} test info-21.3 {miscellaneous error conditions} -returnCodes error -body { info c } -result {unknown or ambiguous subcommand "c": must be args, body, class, cmdcount, cmdtype, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars} test info-21.4 {miscellaneous error conditions} -returnCodes error -body { info l } -result {unknown or ambiguous subcommand "l": must be args, body, class, cmdcount, cmdtype, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars} test info-21.5 {miscellaneous error conditions} -returnCodes error -body { info s } -result {unknown or ambiguous subcommand "s": must be args, body, class, cmdcount, cmdtype, commands, complete, coroutine, default, errorstack, exists, frame, functions, globals, hostname, level, library, loaded, locals, nameofexecutable, object, patchlevel, procs, script, sharedlibextension, tclversion, or vars} ## # ### ### ### ######### ######### ######### ## info frame ## Helper # For the more complex results we cut the file name down to remove path |
︙ | ︙ | |||
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 | } test info-33.35 {{*}, literal, simple, bytecompiled} -body { reduce [foo::bar] } -cleanup { namespace delete foo } -result {type source line 2389 file info.test cmd {info frame 0} proc ::foo::bar level 0} # ------------------------------------------------------------------------- unset -nocomplain res test info-39.2 {Bug 4b61afd660} -setup { proc probe {} { return [dict get [info frame -1] line] } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 | } test info-33.35 {{*}, literal, simple, bytecompiled} -body { reduce [foo::bar] } -cleanup { namespace delete foo } -result {type source line 2389 file info.test cmd {info frame 0} proc ::foo::bar level 0} # ------------------------------------------------------------------------- namespace eval ::testinfocmdtype { apply {cmds { foreach c $cmds {rename $c {}} } ::testinfocmdtype} [info commands ::testinfocmdtype::*] } test info-40.1 {info cmdtype: syntax} -body { info cmdtype } -returnCodes error -result {wrong # args: should be "info cmdtype commandName"} test info-40.2 {info cmdtype: syntax} -body { info cmdtype foo bar } -returnCodes error -result {wrong # args: should be "info cmdtype commandName"} test info-40.3 {info cmdtype: no such command} -body { info cmdtype ::testinfocmdtype::foo } -returnCodes error -result {unknown command "::testinfocmdtype::foo"} test info-40.4 {info cmdtype: native commands} -body { info cmdtype ::if } -result native test info-40.5 {info cmdtype: native commands} -body { info cmdtype ::puts } -result native test info-40.6 {info cmdtype: native commands} -body { info cmdtype ::yield } -result native test info-40.7 {info cmdtype: procedures} -setup { proc ::testinfocmdtype::someproc {} {} } -body { info cmdtype ::testinfocmdtype::someproc } -cleanup { rename ::testinfocmdtype::someproc {} } -result proc test info-40.8 {info cmdtype: aliases} -setup { interp alias {} ::testinfocmdtype::somealias {} ::puts } -body { info cmdtype ::testinfocmdtype::somealias } -cleanup { rename ::testinfocmdtype::somealias {} } -result alias test info-40.9 {info cmdtype: imports} -setup { namespace eval ::testinfocmdtype { namespace eval foo { proc bar {} {} namespace export bar } namespace import foo::bar } } -body { info cmdtype ::testinfocmdtype::bar } -cleanup { rename ::testinfocmdtype::bar {} namespace delete ::testinfocmdtype::foo } -result import test info-40.10 {info cmdtype: slaves} -setup { apply {i { rename $i ::testinfocmdtype::slave variable ::testinfocmdtype::slave $i }} [interp create] } -body { info cmdtype ::testinfocmdtype::slave } -cleanup { interp delete $::testinfocmdtype::slave } -result slave test info-40.11 {info cmdtype: objects} -setup { apply {{} { oo::object create obj } ::testinfocmdtype} } -body { info cmdtype ::testinfocmdtype::obj } -cleanup { ::testinfocmdtype::obj destroy } -result object test info-40.12 {info cmdtype: objects} -setup { apply {{} { oo::object create obj } ::testinfocmdtype} } -body { info cmdtype [info object namespace ::testinfocmdtype::obj]::my } -cleanup { ::testinfocmdtype::obj destroy } -result privateObject test info-40.13 {info cmdtype: ensembles} -setup { namespace eval ::testinfocmdtype { namespace eval ensmbl { proc bar {} {} namespace export * namespace ensemble create } } } -body { info cmdtype ::testinfocmdtype::ensmbl } -cleanup { namespace delete ::testinfocmdtype::ensmbl } -result ensemble test info-40.14 {info cmdtype: zlib streams} -constraints zlib -setup { namespace eval ::testinfocmdtype { rename [zlib stream gzip] zstream } } -body { info cmdtype ::testinfocmdtype::zstream } -cleanup { ::testinfocmdtype::zstream close } -result zlibStream test info-40.15 {info cmdtype: coroutines} -setup { coroutine ::testinfocmdtype::coro eval yield } -body { info cmdtype ::testinfocmdtype::coro } -cleanup { ::testinfocmdtype::coro } -result coroutine test info-40.16 {info cmdtype: dynamic behavior} -setup { proc ::testinfocmdtype::foo {} {} } -body { namespace eval ::testinfocmdtype { list [catch {info cmdtype foo}] [catch {info cmdtype bar}] \ [namespace which foo] [rename foo bar] [namespace which bar] \ [catch {info cmdtype foo}] [catch {info cmdtype bar}] } } -cleanup { namespace eval ::testinfocmdtype { catch {rename foo {}} catch {rename bar {}} } } -result {0 1 ::testinfocmdtype::foo {} ::testinfocmdtype::bar 1 0} test info-40.17 {info cmdtype: aliases in slave interpreters} -setup { set i [interp create] } -body { $i alias foo gorp $i eval { info cmdtype foo } } -cleanup { interp delete $i } -result alias test info-40.18 {info cmdtype: aliases in slave interpreters} -setup { set safe [interp create -safe] } -body { $safe alias foo gorp $safe eval { info cmdtype foo } } -cleanup { interp delete $safe } -result native test info-40.19 {info cmdtype: aliases in slave interpreters} -setup { set safe [interp create -safe] } -body { set inner [interp create [list $safe bar]] interp alias $inner foo $safe gorp $safe eval { bar eval { info cmdtype foo } } } -cleanup { interp delete $safe } -result native test info-40.20 {info cmdtype: aliases in slave interpreters} -setup { set safe [interp create -safe] } -body { $safe eval { interp alias {} foo {} gorp info cmdtype foo } } -cleanup { interp delete $safe } -result alias namespace delete ::testinfocmdtype # ------------------------------------------------------------------------- unset -nocomplain res test info-39.2 {Bug 4b61afd660} -setup { proc probe {} { return [dict get [info frame -1] line] } |
︙ | ︙ |
Changes to tests/lreplace.test.
︙ | ︙ | |||
96 97 98 99 100 101 102 | set foo {a b} list [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] } {a {} {}} test lreplace-1.27 {lreplace command} -body { lreplace x 1 1 | | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | set foo {a b} list [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] } {a {} {}} test lreplace-1.27 {lreplace command} -body { lreplace x 1 1 } -result x test lreplace-1.28 {lreplace command} -body { lreplace x 1 1 y } -result {x y} test lreplace-1.29 {lreplace command} -body { lreplace x 1 1 [error foo] } -returnCodes 1 -result {foo} test lreplace-1.30 {lreplace command} -body { lreplace {not {}alist} 0 0 [error foo] } -returnCodes 1 -result {foo} |
︙ | ︙ | |||
124 125 126 127 128 129 130 | list [catch {lreplace x 10 x} msg] $msg } {1 {bad index "x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.5 {lreplace errors} { list [catch {lreplace x 10 1x} msg] $msg } {1 {bad index "1x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.6 {lreplace errors} { list [catch {lreplace x 3 2} msg] $msg | | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | list [catch {lreplace x 10 x} msg] $msg } {1 {bad index "x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.5 {lreplace errors} { list [catch {lreplace x 10 1x} msg] $msg } {1 {bad index "1x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.6 {lreplace errors} { list [catch {lreplace x 3 2} msg] $msg } {0 x} test lreplace-2.7 {lreplace errors} { list [catch {lreplace x 2 2} msg] $msg } {0 x} test lreplace-3.1 {lreplace won't modify shared argument objects} { proc p {} { lreplace "a b c" 1 1 "x y" return "a b c" } p |
︙ | ︙ |
Changes to tests/oo.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | package require TclOO 1.0.3 package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package require TclOO 1.0.3 package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } # The foundational objects oo::object and oo::class are sensitive to reference # counting errors and are deallocated only when an interp is deleted, so in # this test suite, interp creation and interp deletion are often used in # leaktests in order to leverage this sensitivity. testConstraint memory [llength [info commands memory]] if {[testConstraint memory]} { proc getbytes {} { set lines [split [memory info] \n] return [lindex $lines 3 3] } |
︙ | ︙ | |||
3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 | } method Set {lst} { variable contents $lst variable ops lappend ops [info level] Set $lst return } } } append script0 \n$script } proc SampleSlotCleanup script { set script0 { | > > > > > | 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 | } method Set {lst} { variable contents $lst variable ops lappend ops [info level] Set $lst return } method Resolve {lst} { variable ops lappend ops [info level] Resolve $lst return $lst } } } append script0 \n$script } proc SampleSlotCleanup script { set script0 { |
︙ | ︙ | |||
3868 3869 3870 3871 3872 3873 3874 | test oo-32.3 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -append g h i] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} | | | | > > > > > > > > > > > > > > > > | 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 | test oo-32.3 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -append g h i] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} }] -result {0 {} {a b c g h i} {1 Resolve g 1 Resolve h 1 Resolve i 1 Get 1 Set {a b c g h i}}} test oo-32.4 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -set d e f] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} }] -result {0 {} {d e f} {1 Resolve d 1 Resolve e 1 Resolve f 1 Set {d e f}}} test oo-32.5 {TIP 380: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -set d e f] [sampleSlot -append g h i] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} }] -result {0 {} {} {d e f g h i} {1 Resolve d 1 Resolve e 1 Resolve f 1 Set {d e f} 1 Resolve g 1 Resolve h 1 Resolve i 1 Get 1 Set {d e f g h i}}} test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -prepend g h i] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} }] -result {0 {} {g h i a b c} {1 Resolve g 1 Resolve h 1 Resolve i 1 Get 1 Set {g h i a b c}}} test oo-32.6 {TIP 516: slots - class test} -setup [SampleSlotSetup { SampleSlot create sampleSlot }] -body { list [info level] [sampleSlot -remove c a] \ [sampleSlot contents] [sampleSlot ops] } -cleanup [SampleSlotCleanup { rename sampleSlot {} }] -result {0 {} b {1 Resolve c 1 Resolve a 1 Get 1 Set b}} test oo-33.1 {TIP 380: slots - defaulting} -setup [SampleSlotSetup { set s [SampleSlot new] }] -body { list [$s x y] [$s contents] } -cleanup [SampleSlotCleanup { rename $s {} |
︙ | ︙ | |||
3907 3908 3909 3910 3911 3912 3913 | test oo-33.3 {TIP 380: slots - defaulting} -setup [SampleSlotSetup { set s [SampleSlot new] }] -body { oo::objdefine $s forward --default-operation my -set list [$s destroy; $s unknown] [$s contents] [$s ops] } -cleanup [SampleSlotCleanup { rename $s {} | | | | 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 | test oo-33.3 {TIP 380: slots - defaulting} -setup [SampleSlotSetup { set s [SampleSlot new] }] -body { oo::objdefine $s forward --default-operation my -set list [$s destroy; $s unknown] [$s contents] [$s ops] } -cleanup [SampleSlotCleanup { rename $s {} }] -result {{} unknown {1 Resolve destroy 1 Set destroy 1 Resolve unknown 1 Set unknown}} test oo-33.4 {TIP 380: slots - errors} -setup [SampleSlotSetup { set s [SampleSlot new] }] -body { # Method names beginning with "-" are special to slots $s -grill q } -returnCodes error -cleanup [SampleSlotCleanup { rename $s {} }] -result \ {unknown method "-grill": must be -append, -clear, -prepend, -remove, -set, contents or ops} test oo-34.1 {TIP 380: slots - presence} -setup { set obj [oo::object new] set result {} } -body { oo::define oo::object { ::lappend ::result [::info object class filter] |
︙ | ︙ | |||
3946 3947 3948 3949 3950 3951 3952 | } {::oo::define::filter ::oo::define::mixin ::oo::define::superclass ::oo::define::variable ::oo::objdefine::filter ::oo::objdefine::mixin ::oo::objdefine::variable} proc getMethods obj { list [lsort [info object methods $obj -all]] \ [lsort [info object methods $obj -private]] } test oo-34.3 {TIP 380: slots - presence} { getMethods oo::define::filter | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 | } {::oo::define::filter ::oo::define::mixin ::oo::define::superclass ::oo::define::variable ::oo::objdefine::filter ::oo::objdefine::mixin ::oo::objdefine::variable} proc getMethods obj { list [lsort [info object methods $obj -all]] \ [lsort [info object methods $obj -private]] } test oo-34.3 {TIP 380: slots - presence} { getMethods oo::define::filter } {{-append -clear -prepend -remove -set} {Get Set}} test oo-34.4 {TIP 380: slots - presence} { getMethods oo::define::mixin } {{-append -clear -prepend -remove -set} {--default-operation Get Resolve Set}} test oo-34.5 {TIP 380: slots - presence} { getMethods oo::define::superclass } {{-append -clear -prepend -remove -set} {--default-operation Get Resolve Set}} test oo-34.6 {TIP 380: slots - presence} { getMethods oo::define::variable } {{-append -clear -prepend -remove -set} {Get Set}} test oo-34.7 {TIP 380: slots - presence} { getMethods oo::objdefine::filter } {{-append -clear -prepend -remove -set} {Get Set}} test oo-34.8 {TIP 380: slots - presence} { getMethods oo::objdefine::mixin } {{-append -clear -prepend -remove -set} {--default-operation Get Resolve Set}} test oo-34.9 {TIP 380: slots - presence} { getMethods oo::objdefine::variable } {{-append -clear -prepend -remove -set} {Get Set}} test oo-34.10 {TIP 516: slots - resolution} -setup { oo::class create parent set result {} oo::class create 516a { superclass parent } oo::class create 516b { superclass parent } oo::class create 516c { superclass parent } namespace eval 516test { oo::class create 516a { superclass parent } oo::class create 516b { superclass parent } oo::class create 516c { superclass parent } } } -body { # Must find the right classes when making the mixin namespace eval 516test { oo::define 516a { mixin 516b 516c } } lappend result [info class mixin 516test::516a] # Must not remove class with just simple name match oo::define 516test::516a { mixin -remove 516b } lappend result [info class mixin 516test::516a] # Must remove class with resolved name match oo::define 516test::516a { mixin -remove 516test::516c } lappend result [info class mixin 516test::516a] # Must remove class with resolved name match even after renaming, but only # with the renamed name; it is a slot of classes, not strings! rename 516test::516b 516test::516d oo::define 516test::516a { mixin -remove 516test::516b } lappend result [info class mixin 516test::516a] oo::define 516test::516a { mixin -remove 516test::516d } lappend result [info class mixin 516test::516a] } -cleanup { parent destroy } -result {{::516test::516b ::516test::516c} {::516test::516b ::516test::516c} ::516test::516b ::516test::516d {}} test oo-35.1 {Bug 9d61624b3d: Empty superclass must not cause crash} -setup { oo::class create fruit { method eat {} {} } set result {} } -body { |
︙ | ︙ |
Changes to tests/set-old.test.
︙ | ︙ | |||
336 337 338 339 340 341 342 | } foo } {1 {"x" isn't an array}} test set-old-8.6 {array command} { catch {unset a} set a(22) 3 list [catch {array gorp a} msg] $msg | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | } foo } {1 {"x" isn't an array}} test set-old-8.6 {array command} { catch {unset a} set a(22) 3 list [catch {array gorp a} msg] $msg } {1 {unknown or ambiguous subcommand "gorp": must be anymore, default, donesearch, exists, for, get, names, nextelement, set, size, startsearch, statistics, or unset}} test set-old-8.7 {array command, anymore option} { catch {unset a} list [catch {array anymore a x} msg] $msg } {1 {"a" isn't an array}} test set-old-8.8 {array command, anymore option, array doesn't exist yet but has compiler-allocated procedure slot} { proc foo {x} { if {$x==1} { |
︙ | ︙ | |||
696 697 698 699 700 701 702 | }}} msg] $msg } {1 {list must have an even number of elements}} test set-old-9.1 {ids for array enumeration} { catch {unset a} set a(a) 1 list [array star a] [array star a] [array done a s-1-a; array star a] \ | | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | }}} msg] $msg } {1 {list must have an even number of elements}} test set-old-9.1 {ids for array enumeration} { catch {unset a} set a(a) 1 list [array star a] [array star a] [array done a s-1-a; array star a] \ [array done a s-2-a; array do a s-3-a; array start a] } {s-1-a s-2-a s-3-a s-1-a} test set-old-9.2 {array enumeration} { catch {unset a} set a(a) 1 set a(b) 1 set a(c) 1 set x [array startsearch a] |
︙ | ︙ |
Changes to tests/var.test.
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 | } -result 0 test var-22.2 {leak in parsedVarName} -constraints memory -body { set i 0 leaktest {lappend x($i)} } -cleanup { unset -nocomplain i x } -result 0 | | | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | } -result 0 test var-22.2 {leak in parsedVarName} -constraints memory -body { set i 0 leaktest {lappend x($i)} } -cleanup { unset -nocomplain i x } -result 0 unset -nocomplain a k v test var-23.1 {array command, for loop, too many args} -returnCodes error -body { array for {k v} c d e {} } -result {wrong # args: should be "array for {key value} arrayName script"} test var-23.2 {array command, for loop, not enough args} -returnCodes error -body { array for {k v} {} } -result {wrong # args: should be "array for {key value} arrayName script"} |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | unset -nocomplain $vn } -body { array set $vn {a 1 b 2 c 3} array for $vn $vn {} } -cleanup { unset -nocomplain $vn vn } -result {} catch {namespace delete ns} catch {unset arr} catch {unset v} catch {rename getbytes ""} catch {rename p ""} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 | unset -nocomplain $vn } -body { array set $vn {a 1 b 2 c 3} array for $vn $vn {} } -cleanup { unset -nocomplain $vn vn } -result {} test var-24.1 {array default set and get: interpreted} -setup { unset -nocomplain ary } -body { array set ary {a 3} array default set ary 7 list $ary(a) $ary(b) [info exist ary(a)] [info exist ary(b)] \ [array default get ary] } -cleanup { unset -nocomplain ary } -result {3 7 1 0 7} test var-24.2 {array default set and get: compiled} { apply {{} { array set ary {a 3} array default set ary 7 list $ary(a) $ary(b) [info exist ary(a)] [info exist ary(b)] \ [array default get ary] }} } {3 7 1 0 7} test var-24.3 {array default unset: interpreted} -setup { unset -nocomplain ary } -body { array set ary {a 3} array default set ary 7 list $ary(a) $ary(b) [array default unset ary] $ary(a) [catch {set ary(b)}] } -cleanup { unset -nocomplain ary } -result {3 7 {} 3 1} test var-24.4 {array default unset: compiled} { apply {{} { array set ary {a 3} array default set ary 7 list $ary(a) $ary(b) [array default unset ary] $ary(a) \ [catch {set ary(b)}] }} } {3 7 {} 3 1} test var-24.5 {array default exists: interpreted} -setup { unset -nocomplain ary result set result {} } -body { array set ary {a 3} lappend result [info exists ary],[array exists ary],[array default exists ary] array default set ary 7 lappend result [info exists ary],[array exists ary],[array default exists ary] array default unset ary lappend result [info exists ary],[array exists ary],[array default exists ary] unset ary lappend result [info exists ary],[array exists ary],[array default exists ary] array default set ary 11 lappend result [info exists ary],[array exists ary],[array default exists ary] } -cleanup { unset -nocomplain ary result } -result {1,1,0 1,1,1 1,1,0 0,0,0 1,1,1} test var-24.6 {array default exists: compiled} { apply {{} { array set ary {a 3} lappend result [info exists ary],[array exists ary],[array default exists ary] array default set ary 7 lappend result [info exists ary],[array exists ary],[array default exists ary] array default unset ary lappend result [info exists ary],[array exists ary],[array default exists ary] unset ary lappend result [info exists ary],[array exists ary],[array default exists ary] array default set ary 11 lappend result [info exists ary],[array exists ary],[array default exists ary] }} } {1,1,0 1,1,1 1,1,0 0,0,0 1,1,1} test var-24.7 {array default and append: interpreted} -setup { unset -nocomplain ary result set result {} } -body { array default set ary grill lappend result [array size ary] [info exist ary(x)] append ary(x) abc lappend result [array size ary] $ary(x) array default unset ary append ary(x) def append ary(y) ghi lappend result [array size ary] $ary(x) $ary(y) } -cleanup { unset -nocomplain ary result } -result {0 0 1 grillabc 2 grillabcdef ghi} test var-24.8 {array default and append: compiled} { apply {{} { array default set ary grill lappend result [array size ary] [info exist ary(x)] append ary(x) abc lappend result [array size ary] $ary(x) array default unset ary append ary(x) def append ary(y) ghi lappend result [array size ary] $ary(x) $ary(y) }} } {0 0 1 grillabc 2 grillabcdef ghi} test var-24.9 {array default and lappend: interpreted} -setup { unset -nocomplain ary result set result {} } -body { array default set ary grill lappend result [array size ary] [info exist ary(x)] lappend ary(x) abc lappend result [array size ary] $ary(x) array default unset ary lappend ary(x) def lappend ary(y) ghi lappend result [array size ary] $ary(x) $ary(y) } -cleanup { unset -nocomplain ary result } -result {0 0 1 {grill abc} 2 {grill abc def} ghi} test var-24.10 {array default and lappend: compiled} { apply {{} { array default set ary grill lappend result [array size ary] [info exist ary(x)] lappend ary(x) abc lappend result [array size ary] $ary(x) array default unset ary lappend ary(x) def lappend ary(y) ghi lappend result [array size ary] $ary(x) $ary(y) }} } {0 0 1 {grill abc} 2 {grill abc def} ghi} test var-24.11 {array default and incr: interpreted} -setup { unset -nocomplain ary result set result {} } -body { array default set ary 7 lappend result [array size ary] [info exist ary(x)] incr ary(x) 11 lappend result [array size ary] $ary(x) array default unset ary incr ary(x) incr ary(y) lappend result [array size ary] $ary(x) $ary(y) } -cleanup { unset -nocomplain ary result } -result {0 0 1 18 2 19 1} test var-24.12 {array default and incr: compiled} { apply {{} { array default set ary 7 lappend result [array size ary] [info exist ary(x)] incr ary(x) 11 lappend result [array size ary] $ary(x) array default unset ary incr ary(x) incr ary(y) lappend result [array size ary] $ary(x) $ary(y) }} } {0 0 1 18 2 19 1} test var-24.13 {array default and dict: interpreted} -setup { unset -nocomplain ary x y z } -body { array default set ary {x y} dict lappend ary(p) x z dict update ary(q) x y { set y z } dict with ary(r) { set x 123 } lsort -stride 2 -index 0 [array get ary] } -cleanup { unset -nocomplain ary x y z } -result {p {x {y z}} q {x z} r {x 123}} test var-24.14 {array default and dict: compiled} { lsort -stride 2 -index 0 [apply {{} { array default set ary {x y} dict lappend ary(p) x z dict update ary(q) x y { set y z } dict with ary(r) { set x 123 } array get ary }}] } {p {x {y z}} q {x z} r {x 123}} test var-24.15 {array default set and get: two-level} { apply {{} { array set ary {a 3} array default set ary 7 apply {{} { upvar 1 ary ary ary(c) c lappend result $ary(a) $ary(b) $c lappend result [info exist ary(a)] [info exist ary(b)] [info exist c] lappend result [array default get ary] }} }} } {3 7 7 1 0 0 7} test var-24.16 {array default set: errors} -setup { unset -nocomplain ary } -body { set ary not-an-array array default set ary 7 } -returnCodes error -cleanup { unset -nocomplain ary } -result {can't array default set "ary": variable isn't array} test var-24.17 {array default set: errors} -setup { unset -nocomplain ary } -body { array default set ary } -returnCodes error -cleanup { unset -nocomplain ary } -result * -match glob test var-24.18 {array default set: errors} -setup { unset -nocomplain ary } -body { array default set ary x y } -returnCodes error -cleanup { unset -nocomplain ary } -result * -match glob test var-24.19 {array default get: errors} -setup { unset -nocomplain ary } -body { set ary not-an-array array default get ary } -returnCodes error -cleanup { unset -nocomplain ary } -result {"ary" isn't an array} test var-24.20 {array default get: errors} -setup { unset -nocomplain ary } -body { array default get ary x y } -returnCodes error -cleanup { unset -nocomplain ary } -result * -match glob test var-24.21 {array default exists: errors} -setup { unset -nocomplain ary } -body { set ary not-an-array array default exists ary } -returnCodes error -cleanup { unset -nocomplain ary } -result {"ary" isn't an array} test var-24.22 {array default exists: errors} -setup { unset -nocomplain ary } -body { array default exists ary x } -returnCodes error -cleanup { unset -nocomplain ary } -result * -match glob test var-24.23 {array default unset: errors} -setup { unset -nocomplain ary } -body { set ary not-an-array array default unset ary } -returnCodes error -cleanup { unset -nocomplain ary } -result {"ary" isn't an array} test var-24.24 {array default unset: errors} -setup { unset -nocomplain ary } -body { array default unset ary x } -returnCodes error -cleanup { unset -nocomplain ary } -result * -match glob catch {namespace delete ns} catch {unset arr} catch {unset v} catch {rename getbytes ""} catch {rename p ""} |
︙ | ︙ |
Changes to tests/winPipe.test.
︙ | ︙ | |||
328 329 330 331 332 333 334 | "test(Dir)Check/echo(Cmd)Test Args & Batch.bat"] } lappend cmds [list $path(echoArgs2.bat)] } set broken {} foreach args $args { if {$single & 1} { | | | 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | "test(Dir)Check/echo(Cmd)Test Args & Batch.bat"] } lappend cmds [list $path(echoArgs2.bat)] } set broken {} foreach args $args { if {$single & 1} { # enclose single test-arg between 1st/3rd to be sure nothing is truncated # (e. g. to cover unexpected trim by nts-zero case, and args don't recombined): set args [list "1st" $args "3rd"] } set args [list {*}$args]; # normalized canonical list foreach cmd $cmds { set e [linsert $args 0 [file tail $path(echoArgs.tcl)]] tcltest::DebugPuts 4 " ## test exec [file extension [lindex $cmd 0]] ($cmd) for\n ## $args" |
︙ | ︙ | |||
565 566 567 568 569 570 571 | "test;\n&echo \"" "\"test;\n&echo \"" "test\";\n&echo \"" "\"test\";\n&echo \"" "\"\"test\";\n&echo \"" } test winpipe-8.6 {BuildCommandLine/parse_cmdline pass-thru: check new-line quoted in args} \ -constraints {win exec} -body { | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | "test;\n&echo \"" "\"test;\n&echo \"" "test\";\n&echo \"" "\"test\";\n&echo \"" "\"\"test\";\n&echo \"" } test winpipe-8.6 {BuildCommandLine/parse_cmdline pass-thru: check new-line quoted in args} \ -constraints {win exec} -body { # test exe only, because currently there is no proper way to escape a new-line char resp. # to supply a new-line to the batch-files within arguments (command line is truncated). _testExecArgs 8 \ [list START {*}$injectList END] \ [list "START\"" {*}$injectList END] \ [list START {*}$injectList "\"END"] \ [list "START\"" {*}$injectList "\"END"] } -result {} |
︙ | ︙ |
Changes to win/tclAppInit.c.
︙ | ︙ | |||
122 123 124 125 126 127 128 | if (*p == '\\') { *p = '/'; } } #ifdef TCL_LOCAL_MAIN_HOOK TCL_LOCAL_MAIN_HOOK(&argc, &argv); | | > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | if (*p == '\\') { *p = '/'; } } #ifdef TCL_LOCAL_MAIN_HOOK TCL_LOCAL_MAIN_HOOK(&argc, &argv); #elif !defined(_WIN32) && !defined(UNICODE) /* This doesn't work on Windows without UNICODE */ TclZipfs_AppHook(&argc, &argv); #endif Tcl_Main(argc, argv, TCL_LOCAL_APPINIT); return 0; /* Needed only to prevent compiler warning. */ } |
︙ | ︙ |
Changes to win/tclWin32Dll.c.
︙ | ︙ | |||
502 503 504 505 506 507 508 | Tcl_WinTCharToUtf( const TCHAR *string, /* Source string in Unicode. */ int len, /* Source string length in bytes, or -1 for * platform-specific string length. */ Tcl_DString *dsPtr) /* Uninitialized or free DString in which the * converted string is stored. */ { | | | | | | | | > | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 | Tcl_WinTCharToUtf( const TCHAR *string, /* Source string in Unicode. */ int len, /* Source string length in bytes, or -1 for * platform-specific string length. */ Tcl_DString *dsPtr) /* Uninitialized or free DString in which the * converted string is stored. */ { char *p; int size, i = 0; if (len > 0) { len /= 2; } size = WideCharToMultiByte(CP_UTF8, 0, string, len, 0, 0, NULL, NULL); Tcl_DStringInit(dsPtr); Tcl_DStringSetLength(dsPtr, size+8); /* Add some spare, in case of NULL-bytes */ p = (char *)Tcl_DStringValue(dsPtr); WideCharToMultiByte(CP_UTF8, 0, string, len, p, size, NULL, NULL); if (len == -1) --size; /* account for 0-byte at string end */ while (i < size) { if (!p[i]) { /* Output contains '\0'-byte, but Tcl expect two-bytes: C0 80 */ memmove(p+i+2, p+i+1, size-i-1); memcpy(p + i++, "\xC0\x80", 2); Tcl_DStringSetLength(dsPtr, ++size + 1); p = (char *)Tcl_DStringValue(dsPtr); } ++i; } Tcl_DStringSetLength(dsPtr, size); p[size] = 0; return p; } /* |
︙ | ︙ |