Compare commits

...
Author SHA1 Message Date
dkf 4907489189 merge core-8-branch 2021-04-17 12:43:15 +00:00
dkf 2a03516c32 Cleaning up bytecode issuing. 2021-04-17 12:42:42 +00:00
dkf f37db46ffe More hacking on zipfs, now detecting another malformation case and fixing an error message.
Also has (ifdef'd out) API for reading ZIP file comments.
2021-04-13 15:57:40 +00:00
dkf 204c8e3e79 merge core-8-branch 2021-04-12 19:14:48 +00:00
dkf eb6cd90a57 More bits and pieces 2021-04-12 19:10:27 +00:00
dkf 03aff519f2 Use a lot more enums and inline funcs instead of macros; behaviour is more predictable. 2021-04-07 16:47:33 +00:00
44 changed files with 3770 additions and 2880 deletions
+6 -3
View File
@@ -274,16 +274,19 @@ typedef struct ByteArray {
* array. */
unsigned int allocated; /* The amount of space actually allocated
* minus 1 byte. */
unsigned char bytes[TCLFLEXARRAY]; /* The array of bytes. The actual size of this
unsigned char bytes[TCLFLEXARRAY];
/* The array of bytes. The actual size of this
* field depends on the 'allocated' field
* above. */
} ByteArray;
#define BYTEARRAY_SIZE(len) \
(offsetof(ByteArray, bytes) + (len))
(offsetof(ByteArray, bytes) + (len))
#define GET_BYTEARRAY(irPtr) ((ByteArray *) (irPtr)->twoPtrValue.ptr1)
#define SET_BYTEARRAY(irPtr, baPtr) \
(irPtr)->twoPtrValue.ptr1 = (void *) (baPtr)
do { \
(irPtr)->twoPtrValue.ptr1 = (void *) (baPtr); \
} while (0)
int
TclIsPureByteArray(
+8 -6
View File
@@ -86,12 +86,14 @@ typedef struct {
* following values.
*/
#define SORTMODE_ASCII 0
#define SORTMODE_INTEGER 1
#define SORTMODE_REAL 2
#define SORTMODE_COMMAND 3
#define SORTMODE_DICTIONARY 4
#define SORTMODE_ASCII_NC 8
enum {
SORTMODE_ASCII = 0,
SORTMODE_INTEGER = 1,
SORTMODE_REAL = 2,
SORTMODE_COMMAND = 3,
SORTMODE_DICTIONARY = 4,
SORTMODE_ASCII_NC = 8
};
/*
* Forward declarations for procedures defined in this file:
+291 -290
View File
File diff suppressed because it is too large Load Diff
+242 -210
View File
@@ -27,6 +27,31 @@ static void CompileReturnInternal(CompileEnv *envPtr,
Tcl_Obj *returnOpts);
static int IndexTailVarIfKnown(Tcl_Interp *interp,
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
/*
* Shorthand macros for instruction issuing.
*/
#define OP(name) TclEmitOpcode(INST_##name, envPtr)
#define OP1(name,val) TclEmitInstInt1(INST_##name,(val),envPtr)
#define OP4(name,val) TclEmitInstInt4(INST_##name,(val),envPtr)
#define OP11(name,val1,val2) TclEmitInstInt11(INST_##name,(val1),(val2),envPtr)
#define OP14(name,val1,val2) TclEmitInstInt14(INST_##name,(val1),(val2),envPtr)
#define OP44(name,val1,val2) TclEmitInstInt44(INST_##name,(val1),(val2),envPtr)
#define PUSH(str) PushStringLiteral(envPtr, str)
#define JUMP4(name,var) \
(var) = CurrentOffset(envPtr);TclEmitInstInt4(INST_##name##4,0,envPtr)
#define FIXJUMP4(var) \
TclStoreInt4AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1)
#define JUMP1(name,var) \
(var) = CurrentOffset(envPtr);TclEmitInstInt1(INST_##name##1,0,envPtr)
#define FIXJUMP1(var) \
TclStoreInt1AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1)
#define LOAD(idx) \
if ((idx)<256) {OP1(LOAD_SCALAR1,(idx));} else {OP4(LOAD_SCALAR4,(idx));}
#define STORE(idx) \
if ((idx)<256) {OP1(STORE_SCALAR1,(idx));} else {OP4(STORE_SCALAR4,(idx));}
#define INVOKE(name) TclEmitInvoke(envPtr,INST_##name)
/*
*----------------------------------------------------------------------
@@ -112,7 +137,7 @@ TclCompileGlobalCmd(
* Push the namespace
*/
PushStringLiteral(envPtr, "::");
PUSH( "::");
/*
* Loop over the variables.
@@ -133,15 +158,15 @@ TclCompileGlobalCmd(
*/
CompileWord(envPtr, varTokenPtr, interp, i);
TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
OP4( NSUPVAR, localIndex);
}
/*
* Pop the namespace, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
OP( POP);
PUSH( "");
return TCL_OK;
}
@@ -163,6 +188,30 @@ TclCompileGlobalCmd(
*----------------------------------------------------------------------
*/
static inline int
IsElseToken(
const Tcl_Token *tokenPtr)
{
return (tokenPtr->size == 4) &&
(strncmp(tokenPtr->start, "else", 4) == 0);
}
static inline int
IsElseifToken(
const Tcl_Token *tokenPtr)
{
return (tokenPtr->size == 6) &&
(strncmp(tokenPtr->start, "elseif", 6) == 0);
}
static inline int
IsThenToken(
const Tcl_Token *tokenPtr)
{
return (tokenPtr->size == 4) &&
(strncmp(tokenPtr->start, "then", 4) == 0);
}
int
TclCompileIfCmd(
Tcl_Interp *interp, /* Used for error reporting. */
@@ -181,8 +230,7 @@ TclCompileIfCmd(
* determined. */
Tcl_Token *tokenPtr, *testTokenPtr;
int jumpIndex = 0; /* Avoid compiler warning. */
int jumpFalseDist, numWords, wordIdx, numBytes, j, code;
const char *word;
int jumpFalseDist, numWords, wordIdx, j, code;
int realCond = 1; /* Set to 0 for static conditions:
* "if 0 {..}" */
int boolVal; /* Value of static condition. */
@@ -220,10 +268,7 @@ TclCompileIfCmd(
* Stop looping if the token isn't "if" or "elseif".
*/
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((tokenPtr == parsePtr->tokenPtr)
|| ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
if ((tokenPtr == parsePtr->tokenPtr) || IsElseifToken(&tokenPtr[1])) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
} else {
@@ -286,16 +331,12 @@ TclCompileIfCmd(
code = TCL_ERROR;
goto done;
}
if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
code = TCL_ERROR;
goto done;
}
if (IsThenToken(&tokenPtr[1])) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
code = TCL_ERROR;
goto done;
}
}
@@ -363,14 +404,12 @@ TclCompileIfCmd(
* an "if 1 {...}" case.
*/
if ((wordIdx < numWords) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
if (wordIdx < numWords) {
/*
* There is an else clause. Skip over the optional "else" word.
*/
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
if (IsElseToken(&tokenPtr[1])) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
@@ -402,7 +441,7 @@ TclCompileIfCmd(
*/
if (compileScripts) {
PushStringLiteral(envPtr, "");
PUSH("");
}
}
@@ -525,31 +564,29 @@ TclCompileIncrCmd(
if (isScalar) { /* Simple scalar variable. */
if (localIndex >= 0) {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
TclEmitInt1(immValue, envPtr);
OP11( INCR_SCALAR1_IMM, localIndex, immValue);
} else {
TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
OP1( INCR_SCALAR1, localIndex);
}
} else {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
OP1( INCR_STK_IMM, immValue);
} else {
TclEmitOpcode( INST_INCR_STK, envPtr);
OP( INCR_STK);
}
}
} else { /* Simple array variable. */
if (localIndex >= 0) {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
TclEmitInt1(immValue, envPtr);
OP11( INCR_ARRAY1_IMM, localIndex, immValue);
} else {
TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
OP1( INCR_ARRAY1, localIndex);
}
} else {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
OP1( INCR_ARRAY_STK_IMM, immValue);
} else {
TclEmitOpcode( INST_INCR_ARRAY_STK, envPtr);
OP( INCR_ARRAY_STK);
}
}
}
@@ -624,11 +661,11 @@ TclCompileInfoCommandsCmd(
/* TODO: Just push the known value */
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_STR_LEN, envPtr);
TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr);
TclEmitInstInt4( INST_LIST, 1, envPtr);
OP( RESOLVE_COMMAND);
OP( DUP);
OP( STR_LEN);
OP1( JUMP_FALSE1, 7);
OP4( LIST, 1);
return TCL_OK;
notCompilable:
@@ -656,7 +693,7 @@ TclCompileInfoCoroutineCmd(
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_COROUTINE_NAME, envPtr);
OP( COROUTINE_NAME);
return TCL_OK;
}
@@ -693,15 +730,15 @@ TclCompileInfoExistsCmd(
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_EXIST_STK, envPtr);
OP( EXIST_STK);
} else {
TclEmitInstInt4( INST_EXIST_SCALAR, localIndex, envPtr);
OP4( EXIST_SCALAR, localIndex);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_EXIST_ARRAY_STK, envPtr);
OP( EXIST_ARRAY_STK);
} else {
TclEmitInstInt4( INST_EXIST_ARRAY, localIndex, envPtr);
OP4( EXIST_ARRAY, localIndex);
}
}
@@ -725,7 +762,7 @@ TclCompileInfoLevelCmd(
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr);
OP( INFO_LEVEL_NUM);
} else if (parsePtr->numWords != 2) {
return TCL_ERROR;
} else {
@@ -737,7 +774,7 @@ TclCompileInfoLevelCmd(
*/
CompileWord(envPtr, TokenAfter(parsePtr->tokenPtr), interp, 1);
TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr);
OP( INFO_LEVEL_ARGS);
}
return TCL_OK;
}
@@ -757,7 +794,7 @@ TclCompileInfoObjectClassCmd(
return TCL_ERROR;
}
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_TCLOO_CLASS, envPtr);
OP( TCLOO_CLASS);
return TCL_OK;
}
@@ -792,7 +829,7 @@ TclCompileInfoObjectIsACmd(
*/
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr);
OP( TCLOO_IS_OBJECT);
return TCL_OK;
}
@@ -811,7 +848,7 @@ TclCompileInfoObjectNamespaceCmd(
return TCL_ERROR;
}
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_TCLOO_NS, envPtr);
OP( TCLOO_NS);
return TCL_OK;
}
@@ -890,15 +927,15 @@ TclCompileLappendCmd(
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_STK, envPtr);
OP( LAPPEND_STK);
} else {
Emit14Inst( INST_LAPPEND_SCALAR, localIndex, envPtr);
Emit14Inst( INST_LAPPEND_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_ARRAY_STK, envPtr);
OP( LAPPEND_ARRAY_STK);
} else {
Emit14Inst( INST_LAPPEND_ARRAY, localIndex, envPtr);
Emit14Inst( INST_LAPPEND_ARRAY, localIndex, envPtr);
}
}
@@ -913,18 +950,18 @@ TclCompileLappendCmd(
CompileWord(envPtr, valueTokenPtr, interp, i);
valueTokenPtr = TokenAfter(valueTokenPtr);
}
TclEmitInstInt4( INST_LIST, numWords - 2, envPtr);
OP4( LIST, numWords - 2);
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_LIST_STK, envPtr);
OP( LAPPEND_LIST_STK);
} else {
TclEmitInstInt4(INST_LAPPEND_LIST, localIndex, envPtr);
OP4( LAPPEND_LIST, localIndex);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_LIST_ARRAY_STK, envPtr);
OP( LAPPEND_LIST_ARRAY_STK);
} else {
TclEmitInstInt4(INST_LAPPEND_LIST_ARRAY, localIndex,envPtr);
OP4( LAPPEND_LIST_ARRAY, localIndex);
}
}
return TCL_OK;
@@ -998,27 +1035,27 @@ TclCompileLassignCmd(
if (isScalar) {
if (localIndex >= 0) {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
OP( DUP);
OP4( LIST_INDEX_IMM, idx);
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
OP( POP);
} else {
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
TclEmitOpcode( INST_STORE_STK, envPtr);
TclEmitOpcode( INST_POP, envPtr);
OP4( OVER, 1);
OP4( LIST_INDEX_IMM, idx);
OP( STORE_STK);
OP( POP);
}
} else {
if (localIndex >= 0) {
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
OP4( OVER, 1);
OP4( LIST_INDEX_IMM, idx);
Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
OP( POP);
} else {
TclEmitInstInt4(INST_OVER, 2, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
TclEmitOpcode( INST_POP, envPtr);
OP4( OVER, 2);
OP4( LIST_INDEX_IMM, idx);
OP( STORE_ARRAY_STK);
OP( POP);
}
}
}
@@ -1027,8 +1064,7 @@ TclCompileLassignCmd(
* Generate code to leave the rest of the list on the stack.
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
OP44( LIST_RANGE_IMM, idx, (int) TCL_INDEX_END);
return TCL_OK;
}
@@ -1089,7 +1125,7 @@ TclCompileLindexCmd(
*/
CompileWord(envPtr, valTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
OP4( LIST_INDEX_IMM, idx);
return TCL_OK;
}
@@ -1115,9 +1151,9 @@ TclCompileLindexCmd(
*/
if (numWords == 3) {
TclEmitOpcode( INST_LIST_INDEX, envPtr);
OP( LIST_INDEX);
} else {
TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr);
OP4( LIST_INDEX_MULTI, numWords - 1);
}
return TCL_OK;
@@ -1159,7 +1195,7 @@ TclCompileListCmd(
* [list] without arguments just pushes an empty object.
*/
PushStringLiteral(envPtr, "");
PUSH("");
return TCL_OK;
}
@@ -1196,9 +1232,9 @@ TclCompileListCmd(
concat = build = 0;
for (i = 1; i < numWords; i++) {
if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD && build > 0) {
TclEmitInstInt4( INST_LIST, build, envPtr);
OP4( LIST, build);
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP( LIST_CONCAT);
}
build = 0;
concat = 1;
@@ -1206,7 +1242,7 @@ TclCompileListCmd(
CompileWord(envPtr, valueTokenPtr, interp, i);
if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP( LIST_CONCAT);
} else {
concat = 1;
}
@@ -1216,9 +1252,9 @@ TclCompileListCmd(
valueTokenPtr = TokenAfter(valueTokenPtr);
}
if (build > 0) {
TclEmitInstInt4( INST_LIST, build, envPtr);
OP4( LIST, build);
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP( LIST_CONCAT);
}
}
@@ -1230,8 +1266,7 @@ TclCompileListCmd(
*/
if (concat && numWords == 2) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
OP44( LIST_RANGE_IMM, 0, (int) TCL_INDEX_END);
}
return TCL_OK;
}
@@ -1271,7 +1306,7 @@ TclCompileLlengthCmd(
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, varTokenPtr, interp, 1);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
OP( LIST_LENGTH);
return TCL_OK;
}
@@ -1309,8 +1344,8 @@ TclCompileLrangeCmd(
return TCL_ERROR;
}
/*
* Token was an index value, and we treat all "first" indices
* before the list same as the start of the list.
* Token was an index value, and we treat all "first" indices before the
* list same as the start of the list.
*/
tokenPtr = TokenAfter(tokenPtr);
@@ -1318,9 +1353,10 @@ TclCompileLrangeCmd(
&idx2) != TCL_OK) {
return TCL_ERROR;
}
/*
* Token was an index value, and we treat all "last" indices
* after the list same as the end of the list.
* Token was an index value, and we treat all "last" indices after the
* list same as the end of the list.
*/
/*
@@ -1330,8 +1366,7 @@ TclCompileLrangeCmd(
*/
CompileWord(envPtr, listTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
OP44( LIST_RANGE_IMM, idx1, idx2);
return TCL_OK;
}
@@ -1372,11 +1407,11 @@ TclCompileLinsertCmd(
tokenPtr = TokenAfter(listTokenPtr);
/*
* NOTE: This command treats all inserts at indices before the list
* the same as inserts at the start of the list, and all inserts
* after the list the same as inserts at the end of the list. We
* make that transformation here so we can use the optimized bytecode
* as much as possible.
* NOTE: This command treats all inserts at indices before the list the
* same as inserts at the start of the list, and all inserts after the
* list the same as inserts at the end of the list. We make that
* transformation here so we can use the optimized bytecode as much as
* possible.
*/
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END,
&idx) != TCL_OK) {
@@ -1392,8 +1427,7 @@ TclCompileLinsertCmd(
CompileWord(envPtr, listTokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
OP44( LIST_RANGE_IMM, 0, (int) TCL_INDEX_END);
return TCL_OK;
}
@@ -1401,13 +1435,13 @@ TclCompileLinsertCmd(
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt4( INST_LIST, i - 3, envPtr);
OP4( LIST, i - 3);
if (idx == (int)TCL_INDEX_START) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else if (idx == (int)TCL_INDEX_END) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
if (idx == (int) TCL_INDEX_START) {
OP4( REVERSE, 2);
OP( LIST_CONCAT);
} else if (idx == (int) TCL_INDEX_END) {
OP( LIST_CONCAT);
} else {
/*
* Here we handle two ranges for idx. First when idx > 0, we
@@ -1424,14 +1458,12 @@ TclCompileLinsertCmd(
if (idx < (int)TCL_INDEX_END) {
idx++;
}
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx - 1, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP4( OVER, 1);
OP44( LIST_RANGE_IMM, 0, idx - 1);
OP4( REVERSE, 3);
OP44( LIST_RANGE_IMM, idx, (int) TCL_INDEX_END);
OP( LIST_CONCAT);
OP( LIST_CONCAT);
}
return TCL_OK;
@@ -1502,13 +1534,17 @@ TclCompileLreplaceCmd(
return TCL_ERROR;
}
/* All paths start with computing/pushing the original value. */
/*
* All paths start with computing/pushing the original value.
*/
CompileWord(envPtr, listTokenPtr, interp, 1);
/*
* Push all the replacement values next so any errors raised in
* creating them get raised first.
* Push all the replacement values next so any errors raised in creating
* them get raised first.
*/
if (parsePtr->numWords > 4) {
/* Push the replacement arguments */
tokenPtr = TokenAfter(tokenPtr);
@@ -1518,7 +1554,7 @@ TclCompileLreplaceCmd(
}
/* Make a list of them... */
TclEmitInstInt4( INST_LIST, i - 4, envPtr);
OP4( LIST, i - 4);
emptyPrefix = 0;
}
@@ -1526,45 +1562,42 @@ TclCompileLreplaceCmd(
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.
* We still do a list operation to get list-verification and
* canonicalization side effects.
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
OP44( LIST_RANGE_IMM, 0, (int) TCL_INDEX_END);
return TCL_OK;
}
if (idx1 != (int)TCL_INDEX_START) {
if (idx1 != (int) TCL_INDEX_START) {
/* Prefix may not be empty; generate bytecode to push it */
if (emptyPrefix) {
TclEmitOpcode( INST_DUP, envPtr);
OP( DUP);
} else {
TclEmitInstInt4( INST_OVER, 1, envPtr);
OP4( OVER, 1);
}
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx1 - 1, envPtr);
OP44( LIST_RANGE_IMM, 0, idx1 - 1);
if (!emptyPrefix) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP4( REVERSE, 2);
OP( LIST_CONCAT);
}
emptyPrefix = 0;
}
if (!emptyPrefix) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
OP4( REVERSE, 2);
}
if (suffixStart == (int)TCL_INDEX_NONE) {
TclEmitOpcode( INST_POP, envPtr);
if (suffixStart == (int) TCL_INDEX_NONE) {
OP( POP);
if (emptyPrefix) {
PushStringLiteral(envPtr, "");
PUSH( "");
}
} else {
/* Suffix may not be empty; generate bytecode to push it */
TclEmitInstInt4( INST_LIST_RANGE_IMM, suffixStart, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
OP44( LIST_RANGE_IMM, suffixStart, (int) TCL_INDEX_END);
if (!emptyPrefix) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
OP( LIST_CONCAT);
}
}
@@ -1672,7 +1705,7 @@ TclCompileLsetCmd(
} else {
tempDepth = parsePtr->numWords - 1;
}
TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
OP4( OVER, tempDepth);
}
/*
@@ -1685,7 +1718,7 @@ TclCompileLsetCmd(
} else {
tempDepth = parsePtr->numWords - 2;
}
TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
OP4( OVER, tempDepth);
}
/*
@@ -1694,13 +1727,13 @@ TclCompileLsetCmd(
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LOAD_STK, envPtr);
OP( LOAD_STK);
} else {
Emit14Inst( INST_LOAD_SCALAR, localIndex, envPtr);
LOAD( localIndex);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr);
OP( LOAD_ARRAY_STK);
} else {
Emit14Inst( INST_LOAD_ARRAY, localIndex, envPtr);
}
@@ -1711,9 +1744,9 @@ TclCompileLsetCmd(
*/
if (parsePtr->numWords == 4) {
TclEmitOpcode( INST_LSET_LIST, envPtr);
OP( LSET_LIST);
} else {
TclEmitInstInt4( INST_LSET_FLAT, parsePtr->numWords-1, envPtr);
OP4( LSET_FLAT, parsePtr->numWords - 1);
}
/*
@@ -1722,13 +1755,13 @@ TclCompileLsetCmd(
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_STORE_STK, envPtr);
OP( STORE_STK);
} else {
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
STORE( localIndex);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
OP( STORE_ARRAY_STK);
} else {
Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
}
@@ -1777,7 +1810,7 @@ TclCompileNamespaceCurrentCmd(
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_NS_CURRENT, envPtr);
OP(NS_CURRENT);
return TCL_OK;
}
@@ -1822,11 +1855,11 @@ TclCompileNamespaceCodeCmd(
* the value needs to be determined at runtime for safety.
*/
PushStringLiteral(envPtr, "::namespace");
PushStringLiteral(envPtr, "inscope");
TclEmitOpcode( INST_NS_CURRENT, envPtr);
PUSH( "::namespace");
PUSH( "inscope");
OP( NS_CURRENT);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST, 4, envPtr);
OP4( LIST, 4);
return TCL_OK;
}
@@ -1847,7 +1880,7 @@ TclCompileNamespaceOriginCmd(
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_ORIGIN_COMMAND, envPtr);
OP(ORIGIN_COMMAND);
return TCL_OK;
}
@@ -1868,21 +1901,21 @@ TclCompileNamespaceQualifiersCmd(
}
CompileWord(envPtr, tokenPtr, interp, 1);
PushStringLiteral(envPtr, "0");
PushStringLiteral(envPtr, "::");
TclEmitInstInt4( INST_OVER, 2, envPtr);
TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
PUSH( "0");
PUSH( "::");
OP4( OVER, 2);
OP( STR_FIND_LAST);
off = CurrentOffset(envPtr);
PushStringLiteral(envPtr, "1");
TclEmitOpcode( INST_SUB, envPtr);
TclEmitInstInt4( INST_OVER, 2, envPtr);
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitOpcode( INST_STR_INDEX, envPtr);
PushStringLiteral(envPtr, ":");
TclEmitOpcode( INST_STR_EQ, envPtr);
PUSH( "1");
OP( SUB);
OP4( OVER, 2);
OP4( OVER, 1);
OP( STR_INDEX);
PUSH( ":");
OP( STR_EQ);
off = off - CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr);
TclEmitOpcode( INST_STR_RANGE, envPtr);
OP1( JUMP_TRUE1, off);
OP( STR_RANGE);
return TCL_OK;
}
@@ -1907,18 +1940,18 @@ TclCompileNamespaceTailCmd(
*/
CompileWord(envPtr, tokenPtr, interp, 1);
PushStringLiteral(envPtr, "::");
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
TclEmitOpcode( INST_DUP, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitOpcode( INST_GE, envPtr);
PUSH( "::");
OP4( OVER, 1);
OP( STR_FIND_LAST);
OP( DUP);
PUSH( "0");
OP( GE);
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup);
PushStringLiteral(envPtr, "2");
TclEmitOpcode( INST_ADD, envPtr);
PUSH( "2");
OP( ADD);
TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127);
PushStringLiteral(envPtr, "end");
TclEmitOpcode( INST_STR_RANGE, envPtr);
PUSH( "end");
OP( STR_RANGE);
return TCL_OK;
}
@@ -1970,15 +2003,15 @@ TclCompileNamespaceUpvarCmd(
if (localIndex < 0) {
return TCL_ERROR;
}
TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
OP4( NSUPVAR, localIndex);
}
/*
* Pop the namespace, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
OP( POP);
PUSH( "");
return TCL_OK;
}
@@ -2023,7 +2056,7 @@ TclCompileNamespaceWhichCmd(
*/
CompileWord(envPtr, tokenPtr, interp, idx);
TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
OP( RESOLVE_COMMAND);
return TCL_OK;
}
@@ -2142,7 +2175,7 @@ TclCompileRegexpCmd(
* The semantics of regexp are always match on re == "".
*/
PushStringLiteral(envPtr, "1");
PUSH( "1");
return TCL_OK;
}
@@ -2172,9 +2205,9 @@ TclCompileRegexpCmd(
if (simple) {
if (exact && !nocase) {
TclEmitOpcode( INST_STR_EQ, envPtr);
OP( STR_EQ);
} else {
TclEmitInstInt1( INST_STR_MATCH, nocase, envPtr);
OP1( STR_MATCH, nocase);
}
} else {
/*
@@ -2185,7 +2218,7 @@ TclCompileRegexpCmd(
int cflags = TCL_REG_ADVANCED | (nocase ? TCL_REG_NOCASE : 0);
TclEmitInstInt1( INST_REGEXP, cflags, envPtr);
OP1( REGEXP, cflags);
}
return TCL_OK;
@@ -2352,7 +2385,7 @@ TclCompileRegsubCmd(
bytes = TclGetStringFromObj(replacementObj, &len);
PushLiteral(envPtr, bytes, len);
CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords - 2);
TclEmitOpcode( INST_STR_MAP, envPtr);
OP( STR_MAP);
done:
Tcl_DStringFree(&pattern);
@@ -2485,7 +2518,7 @@ TclCompileReturnCmd(
* No explict result argument, so default result is empty string.
*/
PushStringLiteral(envPtr, "");
PUSH( "");
}
/*
@@ -2519,7 +2552,7 @@ TclCompileReturnCmd(
*/
Tcl_DecrRefCount(returnOpts);
TclEmitOpcode(INST_DONE, envPtr);
OP( DONE);
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
@@ -2550,7 +2583,7 @@ TclCompileReturnCmd(
CompileWord(envPtr, wordTokenPtr, interp, objc);
wordTokenPtr = TokenAfter(wordTokenPtr);
}
TclEmitInstInt4(INST_LIST, numOptionWords, envPtr);
OP4( LIST, numOptionWords);
/*
* Push the result.
@@ -2559,14 +2592,14 @@ TclCompileReturnCmd(
if (explicitResult) {
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
} else {
PushStringLiteral(envPtr, "");
PUSH( "");
}
/*
* Issue the RETURN itself.
*/
TclEmitInvoke(envPtr, INST_RETURN_STK);
INVOKE( RETURN_STK);
return TCL_OK;
}
@@ -2596,8 +2629,7 @@ CompileReturnInternal(
}
TclEmitPush(TclAddLiteralObj(envPtr, returnOpts, NULL), envPtr);
TclEmitInstInt4(op, code, envPtr);
TclEmitInt4(level, envPtr);
TclEmitInstInt44(op, code, level, envPtr);
}
void
@@ -2676,7 +2708,7 @@ TclCompileUpvarCmd(
Tcl_DecrRefCount(objPtr);
if (newTypePtr != typePtr) {
if (numWords%2) {
if (numWords % 2) {
return TCL_ERROR;
}
/* TODO: Push the known value instead? */
@@ -2684,10 +2716,10 @@ TclCompileUpvarCmd(
otherTokenPtr = TokenAfter(tokenPtr);
i = 2;
} else {
if (!(numWords%2)) {
if (!(numWords % 2)) {
return TCL_ERROR;
}
PushStringLiteral(envPtr, "1");
PUSH("1");
otherTokenPtr = tokenPtr;
i = 1;
}
@@ -2710,15 +2742,15 @@ TclCompileUpvarCmd(
if (localIndex < 0) {
return TCL_ERROR;
}
TclEmitInstInt4( INST_UPVAR, localIndex, envPtr);
OP4( UPVAR, localIndex);
}
/*
* Pop the frame index, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
OP( POP);
PUSH( "");
return TCL_OK;
}
@@ -2784,7 +2816,7 @@ TclCompileVariableCmd(
* IndexTailVarIfKnown() screen. Full CompileWord()
* likely does not apply here. Push known value instead. */
CompileWord(envPtr, varTokenPtr, interp, i);
TclEmitInstInt4( INST_VARIABLE, localIndex, envPtr);
OP4( VARIABLE, localIndex);
if (i + 1 < numWords) {
/*
@@ -2792,8 +2824,8 @@ TclCompileVariableCmd(
*/
CompileWord(envPtr, valueTokenPtr, interp, i + 1);
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
STORE( localIndex);
OP( POP);
}
}
@@ -2801,7 +2833,7 @@ TclCompileVariableCmd(
* Set the result to empty
*/
PushStringLiteral(envPtr, "");
PUSH( "");
return TCL_OK;
}
@@ -2933,7 +2965,7 @@ TclCompileObjectNextCmd(
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt1( INST_TCLOO_NEXT, i, envPtr);
OP1( TCLOO_NEXT, i);
return TCL_OK;
}
@@ -2957,7 +2989,7 @@ TclCompileObjectNextToCmd(
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt1( INST_TCLOO_NEXT_CLASS, i, envPtr);
OP1( TCLOO_NEXT_CLASS, i);
return TCL_OK;
}
@@ -2970,9 +3002,9 @@ TclCompileObjectSelfCmd(
CompileEnv *envPtr) /* Holds resulting instructions. */
{
/*
* We only handle [self] and [self object] (which is the same operation).
* These are the only very common operations on [self] for which
* bytecoding is at all reasonable.
* We only handle [self], [self object] (which is the same operation) and
* [self namespace]. These are the only very common operations on [self]
* for which bytecoding is at all reasonable.
*/
if (parsePtr->numWords == 1) {
@@ -3004,7 +3036,7 @@ TclCompileObjectSelfCmd(
* This delegates the entire problem to a single opcode.
*/
TclEmitOpcode( INST_TCLOO_SELF, envPtr);
OP( TCLOO_SELF);
return TCL_OK;
compileSelfNamespace:
@@ -3017,9 +3049,9 @@ TclCompileObjectSelfCmd(
* avoids creating another opcode, so that's all good!
*/
TclEmitOpcode( INST_TCLOO_SELF, envPtr);
TclEmitOpcode( INST_POP, envPtr);
TclEmitOpcode( INST_NS_CURRENT, envPtr);
OP( TCLOO_SELF);
OP( POP);
OP( NS_CURRENT);
return TCL_OK;
}
+281 -222
View File
@@ -81,12 +81,9 @@ const AuxDataType tclJumptableInfoType = {
#define OP(name) TclEmitOpcode(INST_##name, envPtr)
#define OP1(name,val) TclEmitInstInt1(INST_##name,(val),envPtr)
#define OP4(name,val) TclEmitInstInt4(INST_##name,(val),envPtr)
#define OP14(name,val1,val2) \
TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define OP44(name,val1,val2) \
TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define PUSH(str) \
PushStringLiteral(envPtr, str)
#define OP14(name,val1,val2) TclEmitInstInt14(INST_##name,(val1),(val2),envPtr)
#define OP44(name,val1,val2) TclEmitInstInt44(INST_##name,(val1),(val2),envPtr)
#define PUSH(str) PushStringLiteral(envPtr, str)
#define JUMP4(name,var) \
(var) = CurrentOffset(envPtr);TclEmitInstInt4(INST_##name##4,0,envPtr)
#define FIXJUMP4(var) \
@@ -99,9 +96,60 @@ const AuxDataType tclJumptableInfoType = {
if ((idx)<256) {OP1(LOAD_SCALAR1,(idx));} else {OP4(LOAD_SCALAR4,(idx));}
#define STORE(idx) \
if ((idx)<256) {OP1(STORE_SCALAR1,(idx));} else {OP4(STORE_SCALAR4,(idx));}
#define INVOKE(name) \
TclEmitInvoke(envPtr,INST_##name)
#define INVOKE(name) TclEmitInvoke(envPtr,INST_##name)
/*
*----------------------------------------------------------------------
*
* IsContinuationBody, IsDefaultToken, IsFinallyToken, IsOnToken,
* IsTrapToken --
*
* Helpers for TclCompileSwitchCmd and TclCompileTryCmd to compare tokens
* to key literals.
*
* Results:
* Returns 1 if they're equal, 0 if not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static inline int
IsContinuationBody(
const Tcl_Token *tokenPtr)
{
return tokenPtr->size == 1 && tokenPtr->start[0] == '-';
}
static inline int
IsDefaultToken(
const Tcl_Token *tokenPtr)
{
return tokenPtr->size == 7 && memcmp(tokenPtr->start, "default", 7) == 0;
}
static inline int
IsFinallyToken(
const Tcl_Token *tokenPtr)
{
return tokenPtr->size == 7 && memcmp(tokenPtr->start, "finally", 7) == 0;
}
static inline int
IsOnToken(
const Tcl_Token *tokenPtr)
{
return tokenPtr->size == 2 && memcmp(tokenPtr->start, "on", 2) == 0;
}
static inline int
IsTrapToken(
const Tcl_Token *tokenPtr)
{
return tokenPtr->size == 4 && memcmp(tokenPtr->start, "trap", 4) == 0;
}
/*
*----------------------------------------------------------------------
@@ -164,33 +212,33 @@ TclCompileSetCmd(
* Emit instructions to set/get the variable.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_STK : INST_LOAD_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
localIndex, envPtr);
} else {
TclEmitInstInt4((isAssignment?
INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
localIndex, envPtr);
}
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_STK : INST_LOAD_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
localIndex, envPtr);
} else {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
localIndex, envPtr);
} else {
TclEmitInstInt4((isAssignment?
INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
localIndex, envPtr);
}
TclEmitInstInt4((isAssignment?
INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
localIndex, envPtr);
} else {
TclEmitInstInt4((isAssignment?
INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
localIndex, envPtr);
}
}
return TCL_OK;
}
@@ -229,13 +277,15 @@ TclCompileStringCatCmd(
/* Trivial case, no arg */
if (numWords<2) {
PushStringLiteral(envPtr, "");
if (numWords < 2) {
PUSH( "");
return TCL_OK;
}
/* General case: issue CONCAT1's (by chunks of 254 if needed), folding
contiguous constants along the way */
/*
* General case: issue CONCAT1's (by chunks of 254 if needed), folding
* contiguous constants along the way.
*/
numArgs = 0;
folded = NULL;
@@ -263,7 +313,7 @@ TclCompileStringCatCmd(
CompileWord(envPtr, wordTokenPtr, interp, i);
numArgs ++;
if (numArgs >= 254) { /* 254 to take care of the possible +1 of "folded" above */
TclEmitInstInt1(INST_STR_CONCAT1, numArgs, envPtr);
OP1( STR_CONCAT1, numArgs);
numArgs = 1; /* concat pushes 1 obj, the result */
}
}
@@ -279,7 +329,7 @@ TclCompileStringCatCmd(
numArgs ++;
}
if (numArgs > 1) {
TclEmitInstInt1(INST_STR_CONCAT1, numArgs, envPtr);
OP1( STR_CONCAT1, numArgs);
}
return TCL_OK;
@@ -312,7 +362,7 @@ TclCompileStringCmpCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_CMP, envPtr);
OP( STR_CMP);
return TCL_OK;
}
@@ -343,7 +393,7 @@ TclCompileStringEqualCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_EQ, envPtr);
OP( STR_EQ);
return TCL_OK;
}
@@ -374,7 +424,7 @@ TclCompileStringFirstCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
OP(STR_FIND);
OP( STR_FIND);
return TCL_OK;
}
@@ -405,7 +455,7 @@ TclCompileStringLastCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
OP(STR_FIND_LAST);
OP( STR_FIND_LAST);
return TCL_OK;
}
@@ -432,7 +482,7 @@ TclCompileStringIndexCmd(
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_INDEX, envPtr);
OP( STR_INDEX);
return TCL_OK;
}
@@ -452,20 +502,28 @@ TclCompileStringInsertCmd(
return TCL_ERROR;
}
/* Compute and push the string in which to insert */
/*
* Compute and push the string in which to insert.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
/* See what can be discovered about index at compile time */
/*
* See what can be discovered about index at compile time.
*/
tokenPtr = TokenAfter(tokenPtr);
if (TCL_OK != TclGetIndexFromToken(tokenPtr, TCL_INDEX_START,
TCL_INDEX_END, &idx)) {
/* Nothing useful knowable - cease compile; let it direct eval */
return TCL_ERROR;
}
/* Compute and push the string to be inserted */
/*
* Compute and push the string to be inserted.
*/
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
@@ -492,6 +550,17 @@ TclCompileStringInsertCmd(
return TCL_OK;
}
static inline int
GotLiteral(
const Tcl_Token *tokenPtr,
const char *word)
{
return (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD &&
tokenPtr[1].size > 1 &&
tokenPtr[1].start[0] == word[0] &&
strncmp(tokenPtr[1].start, word, tokenPtr[1].size) == 0);
}
int
TclCompileStringIsCmd(
Tcl_Interp *interp, /* Used for error reporting. */
@@ -538,12 +607,6 @@ TclCompileStringIsCmd(
}
Tcl_DecrRefCount(isClass);
#define GotLiteral(tokenPtr, word) \
((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD && \
(tokenPtr)[1].size > 1 && \
(tokenPtr)[1].start[0] == word[0] && \
strncmp((tokenPtr)[1].start, (word), (tokenPtr)[1].size) == 0)
/*
* Cannot handle the -failindex option at all, and that's the only legal
* way to have more than 4 arguments.
@@ -562,7 +625,6 @@ TclCompileStringIsCmd(
}
tokenPtr = TokenAfter(tokenPtr);
}
#undef GotLiteral
/*
* Compile the code. There are several main classes of check here.
@@ -804,12 +866,7 @@ TclCompileStringMatchCmd(
*/
if (parsePtr->numWords == 4) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
str = tokenPtr[1].start;
length = tokenPtr[1].size;
if ((length <= 1) || strncmp(str, "-nocase", length)) {
if (!GotLiteral(tokenPtr, "-nocase")) {
/*
* Fail at run time, not in compilation.
*/
@@ -843,7 +900,7 @@ TclCompileStringMatchCmd(
}
PushLiteral(envPtr, str, length);
} else {
SetLineInformation(i+1+nocase);
SetLineInformation(i + 1 + nocase);
CompileTokens(envPtr, tokenPtr, interp);
}
tokenPtr = TokenAfter(tokenPtr);
@@ -854,9 +911,9 @@ TclCompileStringMatchCmd(
*/
if (exactMatch) {
TclEmitOpcode(INST_STR_EQ, envPtr);
OP( STR_EQ);
} else {
TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
OP1( STR_MATCH, nocase);
}
return TCL_OK;
}
@@ -894,7 +951,7 @@ TclCompileStringLenCmd(
} else {
SetLineInformation(1);
CompileTokens(envPtr, tokenPtr, interp);
TclEmitOpcode(INST_STR_LEN, envPtr);
OP( STR_LEN);
}
TclDecrRefCount(objPtr);
return TCL_OK;
@@ -993,6 +1050,7 @@ TclCompileStringRangeCmd(
&idx1) != TCL_OK) {
goto nonConstantIndices;
}
/*
* Token parsed as an index expression. We treat all indices before
* the string the same as the start of the string.
@@ -1009,10 +1067,12 @@ TclCompileStringRangeCmd(
&idx2) != TCL_OK) {
goto nonConstantIndices;
}
/*
* Token parsed as an index expression. We treat all indices after
* the string the same as the end of the string.
*/
if (idx2 == (int)TCL_INDEX_NONE) {
/* [string range $s $first -1] must be empty string */
OP( POP);
@@ -1061,6 +1121,7 @@ TclCompileStringReplaceCmd(
/*
* Check for first index known and useful at compile time.
*/
tokenPtr = TokenAfter(valueTokenPtr);
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_NONE,
&first) != TCL_OK) {
@@ -1070,6 +1131,7 @@ TclCompileStringReplaceCmd(
/*
* Check for last index known and useful at compile time.
*/
tokenPtr = TokenAfter(tokenPtr);
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_NONE, TCL_INDEX_END,
&last) != TCL_OK) {
@@ -1077,26 +1139,25 @@ TclCompileStringReplaceCmd(
}
/*
* [string replace] is an odd bird. For many arguments it is
* a conventional substring replacer. However it also goes out
* of its way to become a no-op for many cases where it would be
* replacing an empty substring. Precisely, it is a no-op when
* [string replace] is an odd bird. For many arguments it is a
* conventional substring replacer. However it also goes out of its way
* to become a no-op for many cases where it would be replacing an empty
* substring. Precisely, it is a no-op when
*
* (last < first) OR
* (last < 0) OR
* (end < first)
*
* For some compile-time values we can detect these cases, and
* compile direct to bytecode implementing the no-op.
* For some compile-time values we can detect these cases, and compile
* direct to bytecode implementing the no-op.
*/
if ((last == (int)TCL_INDEX_NONE) /* Know (last < 0) */
|| (first == (int)TCL_INDEX_NONE) /* Know (first > end) */
/*
* Tricky to determine when runtime (last < first) can be
* certainly known based on the encoded values. Consider the
* cases...
* Tricky to determine when runtime (last < first) can be certainly
* known based on the encoded values. Consider the cases...
*
* (first <= TCL_INDEX_END) &&
* (last <= TCL_INDEX END) && (last < first) => ACCEPT
@@ -1125,74 +1186,72 @@ TclCompileStringReplaceCmd(
}
if (parsePtr->numWords == 5) {
/*
* When we have a string replacement, we have to take care about
* not replacing empty substrings that [string replace] promises
* not to replace
*
* The remaining index values might be suitable for conventional
* string replacement, but only if they cannot possibly meet the
* conditions described above at runtime. If there's a chance they
* might, we would have to emit bytecode to check and at that point
* we're paying more in bytecode execution time than would make
* things worthwhile. Trouble is we are very limited in
* how much we can detect that at compile time. After decoding,
* we need, first:
*
* (first <= end)
*
* The encoded indices (first <= TCL_INDEX END) and
* (first == TCL_INDEX_NONE) always meets this condition, but
* any other encoded first index has some list for which it fails.
*
* We also need, second:
*
* (last >= 0)
*
* The encoded index (last >= TCL_INDEX_START) always meet this
* condition but any other encoded last index has some list for
* which it fails.
*
* Finally we need, third:
*
* (first <= last)
*
* Considered in combination with the constraints we already have,
* we see that we can proceed when (first == TCL_INDEX_NONE).
* These also permit simplification of the prefix|replace|suffix
* construction. The other constraints, though, interfere with
* getting a guarantee that first <= last.
*/
/*
* When we have a string replacement, we have to take care about not
* replacing empty substrings that [string replace] promises not to
* replace.
*
* The remaining index values might be suitable for conventional
* string replacement, but only if they cannot possibly meet the
* conditions described above at runtime. If there's a chance they
* might, we would have to emit bytecode to check and at that point
* we're paying more in bytecode execution time than would make things
* worthwhile. Trouble is we are very limited in how much we can
* detect that at compile time. After decoding, we need, first:
*
* (first <= end)
*
* The encoded indices (first <= TCL_INDEX END) and (first ==
* TCL_INDEX_NONE) always meets this condition, but any other encoded
* first index has some list for which it fails.
*
* We also need, second:
*
* (last >= 0)
*
* The encoded index (last >= TCL_INDEX_START) always meet this
* condition but any other encoded last index has some list for which
* it fails.
*
* Finally we need, third:
*
* (first <= last)
*
* Considered in combination with the constraints we already have, we
* see that we can proceed when (first == TCL_INDEX_NONE). These also
* permit simplification of the prefix|replace|suffix construction.
* The other constraints, though, interfere with getting a guarantee
* that first <= last.
*/
if ((first == (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)) {
/* empty prefix */
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP4( REVERSE, 2);
if (last == INT_MAX) {
OP( POP); /* Pop original */
} else {
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
if ((first == (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)) {
/* empty prefix */
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP4( REVERSE, 2);
if (last == INT_MAX) {
OP( POP); /* Pop original */
} else {
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
}
return TCL_OK;
}
return TCL_OK;
}
if ((last == (int)TCL_INDEX_NONE) && (first <= (int)TCL_INDEX_END)) {
OP44( STR_RANGE_IMM, 0, first-1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP1( STR_CONCAT1, 2);
return TCL_OK;
}
if ((last == (int)TCL_INDEX_NONE) && (first <= (int)TCL_INDEX_END)) {
OP44( STR_RANGE_IMM, 0, first-1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP1( STR_CONCAT1, 2);
return TCL_OK;
}
/* FLOW THROUGH TO genericReplace */
} else {
/*
* When we have no replacement string to worry about, we may
* have more luck, because the forbidden empty string replacements
* are harmless when they are replaced by another empty string.
* When we have no replacement string to worry about, we may have more
* luck, because the forbidden empty string replacements are harmless
* when they are replaced by another empty string.
*/
if (first == (int)TCL_INDEX_START) {
@@ -1201,7 +1260,7 @@ TclCompileStringReplaceCmd(
if (last == (int)TCL_INDEX_END) {
/* empty suffix too => empty result */
OP( POP); /* Pop original */
PUSH ( "");
PUSH( "");
return TCL_OK;
}
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
@@ -1221,19 +1280,19 @@ TclCompileStringReplaceCmd(
}
}
genericReplace:
tokenPtr = TokenAfter(valueTokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
genericReplace:
tokenPtr = TokenAfter(valueTokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
} else {
PUSH( "");
}
OP( STR_REPLACE);
return TCL_OK;
CompileWord(envPtr, tokenPtr, interp, 4);
} else {
PUSH( "");
}
OP( STR_REPLACE);
return TCL_OK;
}
int
@@ -1477,12 +1536,14 @@ TclCompileSubstCmd(
}
*/
/* TODO: Figure out expansion to cover WordKnownAtCompileTime
* The difficulty is that WKACT makes a copy, and if TclSubstParse
* below parses the copy of the original source string, some deep
* parts of the compile machinery get upset. They want all pointers
* stored in Tcl_Tokens to point back to the same original string.
/*
* TODO: Figure out expansion to cover WordKnownAtCompileTime. The
* difficulty is that WKACT makes a copy, and if TclSubstParse below
* parses the copy of the original source string, some deep parts of the
* compile machinery get upset. They want all pointers stored in
* Tcl_Tokens to point back to the same original string.
*/
if (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
code = TclSubstOptions(NULL, numOpts, objv, &flags);
}
@@ -1539,16 +1600,14 @@ TclSubstCompile(
for (endTokenPtr = tokenPtr + parse.numTokens;
tokenPtr < endTokenPtr; tokenPtr = TokenAfter(tokenPtr)) {
int length, literal, catchRange, breakJump;
int length, catchRange, breakJump;
char buf[4] = "";
JumpFixup startFixup, okFixup, returnFixup, breakFixup;
JumpFixup continueFixup, otherFixup, endFixup;
switch (tokenPtr->type) {
case TCL_TOKEN_TEXT:
literal = TclRegisterLiteral(envPtr,
tokenPtr->start, tokenPtr->size, 0);
TclEmitPush(literal, envPtr);
PushLiteral(envPtr, tokenPtr->start, tokenPtr->size);
TclAdvanceLines(&bline, tokenPtr->start,
tokenPtr->start + tokenPtr->size);
count++;
@@ -1556,8 +1615,7 @@ TclSubstCompile(
case TCL_TOKEN_BS:
length = TclParseBackslash(tokenPtr->start, tokenPtr->size,
NULL, buf);
literal = TclRegisterLiteral(envPtr, buf, length, 0);
TclEmitPush(literal, envPtr);
PushLiteral(envPtr, buf, length);
count++;
continue;
case TCL_TOKEN_VARIABLE:
@@ -1604,8 +1662,7 @@ TclSubstCompile(
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &startFixup);
/* Jump to the end (all BREAKs land here) */
breakOffset = CurrentOffset(envPtr);
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
JUMP4( JUMP, breakOffset);
/* Start */
if (TclFixupForwardJumpToHere(envPtr, &startFixup, 127)) {
@@ -1616,7 +1673,7 @@ TclSubstCompile(
envPtr->line = bline;
catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, catchRange);
OP4( BEGIN_CATCH4, catchRange);
ExceptionRangeStarts(envPtr, catchRange);
switch (tokenPtr->type) {
@@ -1637,21 +1694,21 @@ TclSubstCompile(
ExceptionRangeEnds(envPtr, catchRange);
/* Substitution produced TCL_OK */
OP( END_CATCH);
OP( END_CATCH);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &okFixup);
TclAdjustStackDepth(-1, envPtr);
/* Exceptional return codes processed here */
ExceptionRangeTarget(envPtr, catchRange, catchOffset);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RESULT);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
OP( RETURN_CODE_BRANCH);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RESULT);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
OP( RETURN_CODE_BRANCH);
/* ERROR -> reraise it; NB: can't require BREAK/CONTINUE handling */
OP( RETURN_STK);
OP( NOP);
OP( RETURN_STK);
OP( NOP);
/* RETURN */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &returnFixup);
@@ -1671,14 +1728,14 @@ TclSubstCompile(
Tcl_Panic("TclCompileSubstCmd: bad break jump distance %d",
(int) (CurrentOffset(envPtr) - breakFixup.codeOffset));
}
OP( POP);
OP( POP);
OP( POP);
OP( POP);
breakJump = CurrentOffset(envPtr) - breakOffset;
if (breakJump > 127) {
OP4(JUMP4, -breakJump);
OP4( JUMP4, -breakJump);
} else {
OP1(JUMP1, -breakJump);
OP1( JUMP1, -breakJump);
}
TclAdjustStackDepth(2, envPtr);
@@ -1745,8 +1802,7 @@ TclSubstCompile(
/* Final target of the multi-jump from all BREAKs */
if (breakOffset > 0) {
TclUpdateInstInt4AtPc(INST_JUMP4, CurrentOffset(envPtr) - breakOffset,
envPtr->codeStart + breakOffset);
FIXJUMP4(breakOffset);
}
}
@@ -2043,8 +2099,7 @@ TclCompileSwitchCmd(
* illegal, but this makes the error happen at the right time).
*/
if (bodyToken[numWords-1]->size == 1 &&
bodyToken[numWords-1]->start[0] == '-') {
if (IsContinuationBody(bodyToken[numWords-1])) {
goto freeTemporaries;
}
@@ -2056,7 +2111,10 @@ TclCompileSwitchCmd(
* but it handles the most common case well enough.
*/
/* Both methods push the value to match against onto the stack. */
/*
* Both methods push the value to match against onto the stack.
*/
CompileWord(envPtr, valueTokenPtr, interp, valueIndex);
if (mode == Switch_Exact) {
@@ -2140,8 +2198,8 @@ IssueSwitchChainedTests(
foundDefault = 0;
for (i=0 ; i<numBodyTokens ; i+=2) {
nextArmFixupIndex = -1;
if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
if (i != numBodyTokens - 2 ||
!IsDefaultToken(bodyToken[numBodyTokens - 2])) {
/*
* Generate the test for the arm.
*/
@@ -2223,7 +2281,7 @@ IssueSwitchChainedTests(
* ensured earlier; the final body is never a fall-through).
*/
if (bodyToken[i+1]->size==1 && bodyToken[i+1]->start[0]=='-') {
if (IsContinuationBody(bodyToken[i + 1])) {
if (contFixIndex == -1) {
contFixIndex = fixupCount;
contFixCount = 0;
@@ -2403,8 +2461,8 @@ IssueSwitchJumpTable(
* term.
*/
if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
if (i != numBodyTokens - 2 ||
!IsDefaultToken(bodyToken[numBodyTokens - 2])) {
/*
* This is not a default clause, so insert the current location as
* a target in the jump table (assuming it isn't already there,
@@ -2423,7 +2481,8 @@ IssueSwitchJumpTable(
* point to here.
*/
Tcl_SetHashValue(hPtr, CurrentOffset(envPtr) - jumpLocation);
Tcl_SetHashValue(hPtr, (ptrdiff_t)
(CurrentOffset(envPtr) - jumpLocation));
}
Tcl_DStringFree(&buffer);
} else {
@@ -2434,8 +2493,8 @@ IssueSwitchJumpTable(
foundDefault = 1;
isNew = 1;
TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
envPtr->codeStart+jumpToDefault+1);
TclStoreInt4AtPtr(CurrentOffset(envPtr) - jumpToDefault,
envPtr->codeStart + jumpToDefault + 1);
}
/*
@@ -2446,7 +2505,7 @@ IssueSwitchJumpTable(
* will also point here, so we advance to the next clause.
*/
if (bodyToken[i+1]->size == 1 && bodyToken[i+1]->start[0] == '-') {
if (IsContinuationBody(bodyToken[i + 1])) {
mustGenerate = 1;
continue;
}
@@ -2498,7 +2557,7 @@ IssueSwitchJumpTable(
*/
if (!foundDefault) {
TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
TclStoreInt4AtPtr(CurrentOffset(envPtr) - jumpToDefault,
envPtr->codeStart+jumpToDefault+1);
PUSH("");
}
@@ -2509,8 +2568,8 @@ IssueSwitchJumpTable(
*/
for (i=0 ; i<numRealBodies ; i++) {
TclStoreInt4AtPtr(CurrentOffset(envPtr)-finalFixups[i],
envPtr->codeStart+finalFixups[i]+1);
TclStoreInt4AtPtr(CurrentOffset(envPtr) - finalFixups[i],
envPtr->codeStart + finalFixups[i] + 1);
}
/*
@@ -2669,7 +2728,7 @@ TclCompileTailcallCmd(
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords, envPtr);
OP1( TAILCALL, parsePtr->numWords);
return TCL_OK;
}
@@ -2717,9 +2776,10 @@ TclCompileThrowCmd(
codeKnown = TclWordKnownAtCompileTime(codeToken, objPtr);
/*
* First we must emit the code to substitute the arguments. This
* must come first in case substitution raises errors.
* First we must emit the code to substitute the arguments. This must
* come first in case substitution raises errors.
*/
if (!codeKnown) {
CompileWord(envPtr, codeToken, interp, 1);
PUSH( "-errorcode");
@@ -2743,6 +2803,7 @@ TclCompileThrowCmd(
/*
* Simpler bytecodes when we detect invalid arguments at compile time.
*/
if (codeKnown && !codeIsValid) {
OP( POP);
if (codeIsList) {
@@ -2755,9 +2816,9 @@ TclCompileThrowCmd(
if (!codeKnown) {
/*
* Argument validity checking has to be done by bytecode at
* run time.
* Argument validity checking has to be done by bytecode at run time.
*/
OP4( REVERSE, 3);
OP( DUP);
OP( LIST_LENGTH);
@@ -2849,8 +2910,7 @@ TclCompileTryCmd(
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedToCompile;
}
if (tokenPtr[1].size == 4
&& !strncmp(tokenPtr[1].start, "trap", 4)) {
if (IsTrapToken(&tokenPtr[1])) {
/*
* Parse the list of errorCode words to match against.
*/
@@ -2867,8 +2927,7 @@ TclCompileTryCmd(
}
Tcl_ListObjReplace(NULL, tmpObj, 0, 0, 0, NULL);
matchClauses[i] = tmpObj;
} else if (tokenPtr[1].size == 2
&& !strncmp(tokenPtr[1].start, "on", 2)) {
} else if (IsOnToken(&tokenPtr[1])) {
int code;
/*
@@ -2942,7 +3001,7 @@ TclCompileTryCmd(
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedToCompile;
}
if (tokenPtr[1].size == 1 && tokenPtr[1].start[0] == '-') {
if (IsContinuationBody(&tokenPtr[1])) {
handlerTokens[i] = NULL;
} else {
handlerTokens[i] = tokenPtr;
@@ -2963,8 +3022,8 @@ TclCompileTryCmd(
if (numWords == 0) {
finallyToken = NULL;
} else if (numWords == 2) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 7
|| strncmp(tokenPtr[1].start, "finally", 7)) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
!IsFinallyToken(&tokenPtr[1])) {
goto failedToCompile;
}
finallyToken = TokenAfter(tokenPtr);
@@ -3869,16 +3928,16 @@ TclCompileWhileCmd(
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
OP4(JUMP_TRUE4, -jumpDist);
} else {
TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
OP1(JUMP_TRUE1, -jumpDist);
}
} else {
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr);
OP4(JUMP4, -jumpDist);
} else {
TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr);
OP1(JUMP1, -jumpDist);
}
}
@@ -4167,16 +4226,16 @@ CompileComparisonOpCmd(
STORE(tmpIndex);
TclEmitOpcode(instruction, envPtr);
for (words=3 ; words<parsePtr->numWords ;) {
LOAD(tmpIndex);
LOAD( tmpIndex);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
if (++words < parsePtr->numWords) {
STORE(tmpIndex);
STORE( tmpIndex);
}
TclEmitOpcode(instruction, envPtr);
}
for (; words>3 ; words--) {
OP( BITAND);
OP( BITAND);
}
/*
@@ -4184,7 +4243,7 @@ CompileComparisonOpCmd(
* might be expensive elsewhere.
*/
OP14( UNSET_SCALAR, 0, tmpIndex);
OP14( UNSET_SCALAR, 0, tmpIndex);
}
return TCL_OK;
}
@@ -4310,7 +4369,7 @@ TclCompilePowOpCmd(
words++;
}
while (--words > 1) {
TclEmitOpcode(INST_EXPON, envPtr);
OP( EXPON);
}
return TCL_OK;
}
@@ -4510,11 +4569,11 @@ TclCompileMinusOpCmd(
CompileWord(envPtr, tokenPtr, interp, words);
}
if (words == 2) {
TclEmitOpcode(INST_UMINUS, envPtr);
OP( UMINUS);
return TCL_OK;
}
if (words == 3) {
TclEmitOpcode(INST_SUB, envPtr);
OP( SUB);
return TCL_OK;
}
@@ -4523,10 +4582,10 @@ TclCompileMinusOpCmd(
* calcuations, including roundoff errors.
*/
TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
OP4( REVERSE, words - 1);
while (--words > 1) {
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode(INST_SUB, envPtr);
OP4( REVERSE, 2);
OP( SUB);
}
return TCL_OK;
}
@@ -4551,14 +4610,14 @@ TclCompileDivOpCmd(
return TCL_ERROR;
}
if (parsePtr->numWords == 2) {
PUSH("1.0");
PUSH( "1.0");
}
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
if (words <= 3) {
TclEmitOpcode(INST_DIV, envPtr);
OP( DIV);
return TCL_OK;
}
@@ -4567,10 +4626,10 @@ TclCompileDivOpCmd(
* calcuations, including roundoff errors.
*/
TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
OP4( REVERSE, words - 1);
while (--words > 1) {
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode(INST_DIV, envPtr);
OP4( REVERSE, 2);
OP( DIV);
}
return TCL_OK;
}
+68 -72
View File
@@ -134,15 +134,16 @@ enum Marks {
* need not take the form of a bit array.
*/
#define BINARY 0x40 /* This lexeme is a binary operator. An OpNode
enum {
BINARY = 0x40, /* This lexeme is a binary operator. An OpNode
* representing it should go into the parse
* tree, and two operands should be parsed for
* it in the expression. */
#define UNARY 0x80 /* This lexeme is a unary operator. An OpNode
UNARY = 0x80, /* This lexeme is a unary operator. An OpNode
* representing it should go into the parse
* tree, and one operand should be parsed for
* it in the expression. */
#define LEAF 0xC0 /* This lexeme is a leaf operand in the parse
LEAF = 0xC0 /* This lexeme is a leaf operand in the parse
* tree. No OpNode will be placed in the tree
* for it. Either a literal value will be
* appended to the list of literals in this
@@ -150,47 +151,46 @@ enum Marks {
* be appended in a Tcl_Parse struct to
* represent those leaves that require some
* form of substitution. */
};
/* Uncategorized lexemes */
#define PLUS 1 /* Ambiguous. Resolves to UNARY_PLUS or
enum {
PLUS = 1, /* Ambiguous. Resolves to UNARY_PLUS or
* BINARY_PLUS according to context. */
#define MINUS 2 /* Ambiguous. Resolves to UNARY_MINUS or
MINUS = 2, /* Ambiguous. Resolves to UNARY_MINUS or
* BINARY_MINUS according to context. */
#define BAREWORD 3 /* Ambigous. Resolves to BOOLEAN or to
BAREWORD = 3, /* Ambigous. Resolves to BOOLEAN or to
* FUNCTION or a parse error according to
* context and value. */
#define INCOMPLETE 4 /* A parse error. Used only when the single
INCOMPLETE = 4, /* A parse error. Used only when the single
* "=" is encountered. */
#define INVALID 5 /* A parse error. Used when any punctuation
INVALID = 5, /* A parse error. Used when any punctuation
* appears that's not a supported operator. */
#define COMMENT 6 /* Comment. Lasts to end of line or end of
COMMENT = 6 /* Comment. Lasts to end of line or end of
* expression, whichever comes first. */
};
/* Leaf lexemes */
#define NUMBER (LEAF | 1)
/* For literal numbers */
#define SCRIPT (LEAF | 2)
/* Script substitution; [foo] */
#define BOOLEAN (LEAF | BAREWORD)
/* For literal booleans */
#define BRACED (LEAF | 4)
/* Braced string; {foo bar} */
#define VARIABLE (LEAF | 5)
/* Variable substitution; $x */
#define QUOTED (LEAF | 6)
/* Quoted string; "foo $bar [soom]" */
#define EMPTY (LEAF | 7)
/* Used only for an empty argument list to a
enum {
NUMBER = (LEAF | 1), /* For literal numbers */
SCRIPT = (LEAF | 2), /* Script substitution; [foo] */
BOOLEAN = (LEAF | BAREWORD),/* For literal booleans */
BRACED = (LEAF | 4), /* Braced string; {foo bar} */
VARIABLE = (LEAF | 5), /* Variable substitution; $x */
QUOTED = (LEAF | 6), /* Quoted string; "foo $bar [soom]" */
EMPTY = (LEAF | 7) /* Used only for an empty argument list to a
* function. Represents the empty string
* within parens in the expression: rand() */
};
/* Unary operator lexemes */
#define UNARY_PLUS (UNARY | PLUS)
#define UNARY_MINUS (UNARY | MINUS)
#define FUNCTION (UNARY | BAREWORD)
enum {
UNARY_PLUS = (UNARY | PLUS),
UNARY_MINUS = (UNARY | MINUS),
FUNCTION = (UNARY | BAREWORD),
/* This is a bit of "creative interpretation"
* on the part of the parser. A function call
* is parsed into the parse tree according to
@@ -206,69 +206,64 @@ enum Marks {
* include such exceptional handling in the
* code against the need we would otherwise
* have for more lexeme categories. */
#define START (UNARY | 4)
/* This lexeme isn't parsed from the
START = (UNARY | 4), /* This lexeme isn't parsed from the
* expression text at all. It represents the
* start of the expression and sits at the
* root of the parse tree where it serves as
* the start/end point of traversals. */
#define OPEN_PAREN (UNARY | 5)
/* Another bit of creative interpretation,
OPEN_PAREN = (UNARY | 5), /* Another bit of creative interpretation,
* where we treat "(" as a unary operator with
* the sub-expression between it and its
* matching ")" as its operand. See
* CLOSE_PAREN below. */
#define NOT (UNARY | 6)
#define BIT_NOT (UNARY | 7)
NOT = (UNARY | 6),
BIT_NOT = (UNARY | 7)
};
/* Binary operator lexemes */
#define BINARY_PLUS (BINARY | PLUS)
#define BINARY_MINUS (BINARY | MINUS)
#define COMMA (BINARY | 3)
/* The "," operator is a low precedence binary
enum {
BINARY_PLUS = (BINARY | PLUS),
BINARY_MINUS = (BINARY | MINUS),
COMMA = (BINARY | 3), /* The "," operator is a low precedence binary
* operator that separates the arguments in a
* function call. The additional constraint
* that this operator can only legally appear
* at the right places within a function call
* argument list are hard coded within
* ParseExpr(). */
#define MULT (BINARY | 4)
#define DIVIDE (BINARY | 5)
#define MOD (BINARY | 6)
#define LESS (BINARY | 7)
#define GREATER (BINARY | 8)
#define BIT_AND (BINARY | 9)
#define BIT_XOR (BINARY | 10)
#define BIT_OR (BINARY | 11)
#define QUESTION (BINARY | 12)
/* These two lexemes make up the */
#define COLON (BINARY | 13)
/* ternary conditional operator, $x ? $y : $z.
MULT = (BINARY | 4),
DIVIDE = (BINARY | 5),
MOD = (BINARY | 6),
LESS = (BINARY | 7),
GREATER = (BINARY | 8),
BIT_AND = (BINARY | 9),
BIT_XOR = (BINARY | 10),
BIT_OR = (BINARY | 11),
QUESTION = (BINARY | 12), /* These two lexemes make up the */
COLON = (BINARY | 13), /* ternary conditional operator, $x ? $y : $z.
* We treat them as two binary operators to
* avoid another lexeme category, and code the
* additional constraints directly in
* ParseExpr(). For instance, the right
* operand of a "?" operator must be a ":"
* operator. */
#define LEFT_SHIFT (BINARY | 14)
#define RIGHT_SHIFT (BINARY | 15)
#define LEQ (BINARY | 16)
#define GEQ (BINARY | 17)
#define EQUAL (BINARY | 18)
#define NEQ (BINARY | 19)
#define AND (BINARY | 20)
#define OR (BINARY | 21)
#define STREQ (BINARY | 22)
#define STRNEQ (BINARY | 23)
#define EXPON (BINARY | 24)
/* Unlike the other binary operators, EXPON is
LEFT_SHIFT = (BINARY | 14),
RIGHT_SHIFT = (BINARY | 15),
LEQ = (BINARY | 16),
GEQ = (BINARY | 17),
EQUAL = (BINARY | 18),
NEQ = (BINARY | 19),
AND = (BINARY | 20),
OR = (BINARY | 21),
STREQ = (BINARY | 22),
STRNEQ = (BINARY | 23),
EXPON = (BINARY | 24), /* Unlike the other binary operators, EXPON is
* right associative and this distinction is
* coded directly in ParseExpr(). */
#define IN_LIST (BINARY | 25)
#define NOT_IN_LIST (BINARY | 26)
#define CLOSE_PAREN (BINARY | 27)
/* By categorizing the CLOSE_PAREN lexeme as a
IN_LIST = (BINARY | 25),
NOT_IN_LIST = (BINARY | 26),
CLOSE_PAREN = (BINARY | 27),/* By categorizing the CLOSE_PAREN lexeme as a
* BINARY operator, the normal parsing rules
* for binary operators assure that a close
* paren will not directly follow another
@@ -283,17 +278,17 @@ enum Marks {
* parse tree. The sub-expression between
* parens becomes the single argument of the
* matching OPEN_PAREN unary operator. */
#define STR_LT (BINARY | 28)
#define STR_GT (BINARY | 29)
#define STR_LEQ (BINARY | 30)
#define STR_GEQ (BINARY | 31)
#define END (BINARY | 32)
/* This lexeme represents the end of the
STR_LT = (BINARY | 28),
STR_GT = (BINARY | 29),
STR_LEQ = (BINARY | 30),
STR_GEQ = (BINARY | 31),
END = (BINARY | 32) /* This lexeme represents the end of the
* string being parsed. Treating it as a
* binary operator follows the same logic as
* the CLOSE_PAREN lexeme and END pairs with
* START, in the same way that CLOSE_PAREN
* pairs with OPEN_PAREN. */
};
/*
* When ParseExpr() builds the parse tree it must choose which operands to
@@ -2680,9 +2675,10 @@ TclSortingOpCmd(
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
} else {
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData;
Tcl_Obj **litObjv = (Tcl_Obj **)TclStackAlloc(interp,
Tcl_Obj **litObjv = (Tcl_Obj **) TclStackAlloc(interp,
2 * (objc-2) * sizeof(Tcl_Obj *));
OpNode *nodes = (OpNode *)TclStackAlloc(interp, 2 * (objc-2) * sizeof(OpNode));
OpNode *nodes = (OpNode *)
TclStackAlloc(interp, 2 * (objc-2) * sizeof(OpNode));
unsigned char lexeme;
int i, lastAnd = 1;
Tcl_Obj *const *litObjPtrPtr = litObjv;
+800 -591
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -950,7 +950,7 @@ Tcl_DictObjPut(
TclInvalidateStringRep(dictPtr);
hPtr = CreateChainEntry(dict, keyPtr, &isNew);
dict->refCount++;
TclFreeIntRep(dictPtr)
TclFreeIntRep(dictPtr);
DictSetIntRep(dictPtr, dict);
Tcl_IncrRefCount(valuePtr);
if (!isNew) {
+3 -4
View File
@@ -53,12 +53,11 @@ static const Tcl_ObjType instNameType = {
#define InstNameGetIntRep(objPtr, inst) \
do { \
const Tcl_ObjIntRep *irPtr; \
irPtr = TclFetchIntRep((objPtr), &instNameType); \
const Tcl_ObjIntRep *irPtr = \
TclFetchIntRep((objPtr), &instNameType); \
assert(irPtr != NULL); \
(inst) = (size_t)irPtr->wideValue; \
(inst) = (size_t) irPtr->wideValue; \
} while (0)
/*
*----------------------------------------------------------------------
+21 -12
View File
@@ -116,7 +116,8 @@ typedef struct {
* entry in this array is 1, otherwise it is
* 0. */
int numSubTables; /* Length of following array. */
EscapeSubTable subTables[TCLFLEXARRAY];/* Information about each EscapeSubTable used
EscapeSubTable subTables[TCLFLEXARRAY];
/* Information about each EscapeSubTable used
* by this encoding type. The actual size is
* as large as necessary to hold all
* EscapeSubTables. */
@@ -127,10 +128,12 @@ typedef struct {
* file.
*/
#define ENCODING_SINGLEBYTE 0
#define ENCODING_DOUBLEBYTE 1
#define ENCODING_MULTIBYTE 2
#define ENCODING_ESCAPE 3
enum {
ENCODING_SINGLEBYTE = 0,
ENCODING_DOUBLEBYTE = 1,
ENCODING_MULTIBYTE = 2,
ENCODING_ESCAPE = 3
};
/*
* A list of directories in which Tcl should look for *.enc files. This list
@@ -233,7 +236,7 @@ static Tcl_EncodingConvertProc Iso88591ToUtfProc;
static const Tcl_ObjType encodingType = {
"encoding", FreeEncodingIntRep, DupEncodingIntRep, NULL, NULL
};
#define EncodingSetIntRep(objPtr, encoding) \
#define EncodingSetIntRep(objPtr, encoding) \
do { \
Tcl_ObjIntRep ir; \
ir.twoPtrValue.ptr1 = (encoding); \
@@ -241,7 +244,7 @@ static const Tcl_ObjType encodingType = {
Tcl_StoreIntRep((objPtr), &encodingType, &ir); \
} while (0)
#define EncodingGetIntRep(objPtr, encoding) \
#define EncodingGetIntRep(objPtr, encoding) \
do { \
const Tcl_ObjIntRep *irPtr; \
irPtr = TclFetchIntRep ((objPtr), &encodingType); \
@@ -510,11 +513,17 @@ FillEncodingFileMap(void)
*---------------------------------------------------------------------------
*/
/* This flags must not conflict with other TCL_ENCODING_* flags in tcl.h */
#define TCL_ENCODING_MODIFIED 0x20 /* Converting NULL bytes to 0xC0 0x80 */
/* Since TCL_ENCODING_MODIFIED is only used for utf-8 and
* TCL_ENCODING_LE is only used for utf-16/ucs-2, re-use the same value */
#define TCL_ENCODING_LE TCL_ENCODING_MODIFIED /* Little-endian encoding */
enum {
/* This flags must not conflict with other TCL_ENCODING_* flags in tcl.h */
TCL_ENCODING_MODIFIED = 0x20, /* Converting NULL bytes to 0xC0 0x80 */
/*
* Since TCL_ENCODING_MODIFIED is only used for utf-8 and TCL_ENCODING_LE
* is only used for utf-16/ucs-2, re-use the same value
*/
TCL_ENCODING_LE = TCL_ENCODING_MODIFIED /* Little-endian encoding */
};
void
TclInitEncodingSubsystem(void)
+25 -14
View File
@@ -15,6 +15,7 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#define _BUILD_TCL_EXECUTE 1
#include "tclInt.h"
#include "tclCompile.h"
#include "tclOOInt.h"
@@ -207,11 +208,16 @@ typedef struct TEBCdata {
} while (0)
/*
* These variable-access macros have to coincide with those in tclVar.c
* These variable-access inline functions have to coincide with those in
* tclVar.c
*/
#define VarHashGetValue(hPtr) \
((Var *) ((char *)hPtr - offsetof(VarInHash, entry)))
static inline Var *
VarHashGetValue(
Tcl_HashEntry *hPtr)
{
return (Var *) ((char *)hPtr - offsetof(VarInHash, entry));
}
static inline Var *
VarHashCreateVar(
@@ -228,8 +234,13 @@ VarHashCreateVar(
return VarHashGetValue(hPtr);
}
#define VarHashFindVar(tablePtr, key) \
VarHashCreateVar((tablePtr), (key), NULL)
static inline Var *
VarHashFindVar(
TclVarHashTable *tablePtr,
Tcl_Obj *key)
{
return VarHashCreateVar((tablePtr), (key), NULL);
}
/*
* The new macro for ending an instruction; note that a reasonable C-optimiser
@@ -261,7 +272,7 @@ VarHashCreateVar(
#define CHECK_STACK()
#endif
#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
do { \
TCL_CT_ASSERT((nCleanup >= 0) && (nCleanup <= 2)); \
CHECK_STACK(); \
@@ -343,16 +354,16 @@ VarHashCreateVar(
switch (*pc) { \
case INST_JUMP_FALSE1: \
NEXT_INST_V(((condition)? 2 : TclGetInt1AtPtr(pc+1)), (cleanup), 0); \
break; \
break; \
case INST_JUMP_TRUE1: \
NEXT_INST_V(((condition)? TclGetInt1AtPtr(pc+1) : 2), (cleanup), 0); \
break; \
break; \
case INST_JUMP_FALSE4: \
NEXT_INST_V(((condition)? 5 : TclGetInt4AtPtr(pc+1)), (cleanup), 0); \
break; \
break; \
case INST_JUMP_TRUE4: \
NEXT_INST_V(((condition)? TclGetInt4AtPtr(pc+1) : 5), (cleanup), 0); \
break; \
break; \
default: \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
@@ -360,12 +371,12 @@ VarHashCreateVar(
objResultPtr = TCONST((condition) > 0); \
} \
NEXT_INST_V(0, (cleanup), 1); \
break; \
break; \
} \
} while (0)
#else /* TCL_COMPILE_DEBUG */
#define JUMP_PEEPHOLE_F(condition, pcAdjustment, cleanup) \
do{ \
do { \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
@@ -374,7 +385,7 @@ VarHashCreateVar(
NEXT_INST_F((pcAdjustment), (cleanup), 1); \
} while (0)
#define JUMP_PEEPHOLE_V(condition, pcAdjustment, cleanup) \
do{ \
do { \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
@@ -998,7 +1009,7 @@ static inline int
wordSkip(
void *ptr)
{
int mask = TCL_ALLOCALIGN-1;
int mask = TCL_ALLOCALIGN - 1;
int base = PTR2INT(ptr) & mask;
return (TCL_ALLOCALIGN - base)/sizeof(Tcl_Obj *);
}
+263 -251
View File
File diff suppressed because it is too large Load Diff
+9 -6
View File
@@ -40,9 +40,9 @@ static Tcl_ExitProc FinalizeIOCmdTSD;
static Tcl_TcpAcceptProc AcceptCallbackProc;
static Tcl_ObjCmdProc ChanPendingObjCmd;
static Tcl_ObjCmdProc ChanTruncateObjCmd;
static void RegisterTcpServerInterpCleanup(
Tcl_Interp *interp,
AcceptCallback *acceptCallbackPtr);
static void RegisterTcpServerInterpCleanup(
Tcl_Interp *interp,
AcceptCallback *acceptCallbackPtr);
static Tcl_InterpDeleteProc TcpAcceptCallbacksDeleteProc;
static void TcpServerCloseProc(ClientData callbackData);
static void UnregisterTcpServerInterpCleanupProc(
@@ -1219,7 +1219,8 @@ TcpAcceptCallbacksDeleteProc(
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) {
AcceptCallback *acceptCallbackPtr = (AcceptCallback *)Tcl_GetHashValue(hPtr);
AcceptCallback *acceptCallbackPtr = (AcceptCallback *)
Tcl_GetHashValue(hPtr);
acceptCallbackPtr->interp = NULL;
}
@@ -1307,7 +1308,8 @@ UnregisterTcpServerInterpCleanupProc(
Tcl_HashTable *hTblPtr;
Tcl_HashEntry *hPtr;
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL);
hTblPtr = (Tcl_HashTable *)
Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL);
if (hTblPtr == NULL) {
return;
}
@@ -1635,7 +1637,8 @@ Tcl_SocketObjCmd(
port = TclGetString(objv[a]);
if (server) {
AcceptCallback *acceptCallbackPtr = (AcceptCallback *)ckalloc(sizeof(AcceptCallback));
AcceptCallback *acceptCallbackPtr = (AcceptCallback *)
ckalloc(sizeof(AcceptCallback));
Tcl_IncrRefCount(script);
acceptCallbackPtr->script = script;
+16 -12
View File
@@ -68,18 +68,22 @@ static int ExecuteCallback(TransformChannelData *ctrl,
* the procedure what to do with the result of the script it calls.
*/
#define TRANSMIT_DONT 0 /* No transfer to do. */
#define TRANSMIT_DOWN 1 /* Transfer to the underlying channel. */
#define TRANSMIT_SELF 2 /* Transfer into our channel. */
#define TRANSMIT_IBUF 3 /* Transfer to internal input buffer. */
#define TRANSMIT_NUM 4 /* Transfer number to 'maxRead'. */
enum {
TRANSMIT_DONT = 0, /* No transfer to do. */
TRANSMIT_DOWN = 1, /* Transfer to the underlying channel. */
TRANSMIT_SELF = 2, /* Transfer into our channel. */
TRANSMIT_IBUF = 3, /* Transfer to internal input buffer. */
TRANSMIT_NUM = 4 /* Transfer number to 'maxRead'. */
};
/*
* Codes for 'preserve' of 'ExecuteCallback'.
*/
#define P_PRESERVE 1
#define P_NO_PRESERVE 0
enum {
P_PRESERVE = 1,
P_NO_PRESERVE = 0
};
/*
* Strings for the action codes delivered to the script implementing a
@@ -969,11 +973,11 @@ TransformWideSeekProc(
if (parentWideSeekProc == NULL) {
/*
* We're transferring to narrow seeks at this point; this is a bit complex
* because we have to check whether the seek is possible first (i.e.
* whether we are losing information in truncating the bits of the
* offset). Luckily, there's a defined error for what happens when trying
* to go out of the representable range.
* We're transferring to narrow seeks at this point; this is a bit
* complex because we have to check whether the seek is possible first
* (i.e. whether we are losing information in truncating the bits of
* the offset). Luckily, there's a defined error for what happens when
* trying to go out of the representable range.
*/
#ifndef TCL_NO_DEPRECATED
+25 -27
View File
@@ -43,13 +43,13 @@ static int ReflectBlock(ClientData clientData, int mode);
static void ReflectThread(ClientData clientData, int action);
static int ReflectEventRun(Tcl_Event *ev, int flags);
static int ReflectEventDelete(Tcl_Event *ev, ClientData cd);
#endif
#endif /* TCL_THREADS */
static long long ReflectSeekWide(ClientData clientData,
long long offset, int mode, int *errorCodePtr);
#ifndef TCL_NO_DEPRECATED
static int ReflectSeek(ClientData clientData, long offset,
int mode, int *errorCodePtr);
#endif
#endif /* !TCL_NO_DEPRECATED */
static int ReflectGetOption(ClientData clientData,
Tcl_Interp *interp, const char *optionName,
Tcl_DString *dsPtr);
@@ -58,8 +58,8 @@ static int ReflectSetOption(ClientData clientData,
const char *newValue);
static int ReflectTruncate(ClientData clientData,
long long length);
static void TimerRunRead(ClientData clientData);
static void TimerRunWrite(ClientData clientData);
static void TimerRunRead(ClientData clientData);
static void TimerRunWrite(ClientData clientData);
/*
* The C layer channel type/driver definition used by the reflection.
@@ -104,33 +104,27 @@ typedef struct {
* Tcl level part of the channel. NULL here
* signals the channel is dead because the
* interpreter/thread containing its Tcl
* command is gone.
*/
* command is gone. */
#if TCL_THREADS
Tcl_ThreadId thread; /* Thread the 'interp' belongs to. == Handler thread */
Tcl_ThreadId owner; /* Thread owning the structure. == Channel thread */
Tcl_ThreadId thread; /* Thread the 'interp' belongs to.
* == Handler thread */
Tcl_ThreadId owner; /* Thread owning the structure.
* == Channel thread */
#endif
Tcl_Obj *cmd; /* Callback command prefix */
Tcl_Obj *methods; /* Methods to append to command prefix */
Tcl_Obj *name; /* Name of the channel as created */
int mode; /* Mask of R/W mode */
int interest; /* Mask of events the channel is interested
* in. */
int dead; /* Boolean signal that some operations
* should no longer be attempted. */
Tcl_TimerToken readTimer; /*
A token for the timer that is scheduled in
order to call Tcl_NotifyChannel when the
channel is readable
*/
Tcl_TimerToken writeTimer; /*
A token for the timer that is scheduled in
order to call Tcl_NotifyChannel when the
channel is writable
*/
Tcl_TimerToken readTimer; /* A token for the timer that is scheduled in
* order to call Tcl_NotifyChannel when the
* channel is readable */
Tcl_TimerToken writeTimer; /* A token for the timer that is scheduled in
* order to call Tcl_NotifyChannel when the
* channel is writable */
/*
* Note regarding the usage of timers.
@@ -696,7 +690,8 @@ TclChanCreateObjCmd(
* as the actual channel type.
*/
Tcl_ChannelType *clonePtr = (Tcl_ChannelType *)ckalloc(sizeof(Tcl_ChannelType));
Tcl_ChannelType *clonePtr = (Tcl_ChannelType *)
ckalloc(sizeof(Tcl_ChannelType));
memcpy(clonePtr, &tclRChannelType, sizeof(Tcl_ChannelType));
@@ -902,7 +897,7 @@ TclChanPostEventObjCmd(
* have gone seriously haywire.
*/
chan = (Tcl_Channel)Tcl_GetHashValue(hPtr);
chan = (Tcl_Channel) Tcl_GetHashValue(hPtr);
chanTypePtr = Tcl_GetChannelType(chan);
/*
@@ -1171,7 +1166,7 @@ static int
ReflectClose(
ClientData clientData,
Tcl_Interp *interp,
int flags)
int flags)
{
ReflectedChannel *rcPtr = (ReflectedChannel *)clientData;
int result; /* Result code for 'close' */
@@ -2590,7 +2585,8 @@ static ReflectedChannelMap *
GetReflectedChannelMap(
Tcl_Interp *interp)
{
ReflectedChannelMap *rcmPtr = (ReflectedChannelMap *)Tcl_GetAssocData(interp, RCMKEY, NULL);
ReflectedChannelMap *rcmPtr = (ReflectedChannelMap *)
Tcl_GetAssocData(interp, RCMKEY, NULL);
if (rcmPtr == NULL) {
rcmPtr = (ReflectedChannelMap *)ckalloc(sizeof(ReflectedChannelMap));
@@ -2793,7 +2789,8 @@ GetThreadReflectedChannelMap(void)
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->rcmPtr) {
tsdPtr->rcmPtr = (ReflectedChannelMap *)ckalloc(sizeof(ReflectedChannelMap));
tsdPtr->rcmPtr = (ReflectedChannelMap *)
ckalloc(sizeof(ReflectedChannelMap));
Tcl_InitHashTable(&tsdPtr->rcmPtr->map, TCL_STRING_KEYS);
Tcl_CreateThreadExitHandler(DeleteThreadReflectedChannelMap, NULL);
}
@@ -2911,7 +2908,8 @@ DeleteThreadReflectedChannelMap(
hPtr != NULL;
hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
Tcl_Channel chan = (Tcl_Channel)Tcl_GetHashValue(hPtr);
ReflectedChannel *rcPtr = (ReflectedChannel *)Tcl_GetChannelInstanceData(chan);
ReflectedChannel *rcPtr = (ReflectedChannel *)
Tcl_GetChannelInstanceData(chan);
MarkDead(rcPtr);
Tcl_DeleteHashEntry(hPtr);
+41 -41
View File
@@ -476,8 +476,10 @@ static int TransformLimit(ReflectedTransform *rtPtr,
* Operation codes for TransformFlush().
*/
#define FLUSH_WRITE 1
#define FLUSH_DISCARD 0
enum {
FLUSH_WRITE = 1,
FLUSH_DISCARD = 0
};
/*
* Main methods to plug into the 'chan' ensemble'. ==================
@@ -1113,7 +1115,6 @@ ReflectInput(
goto stop;
}
/*
* The buffer is exhausted, but the caller wants even more. We now
* have to go to the underlying channel, get more bytes and then
@@ -1149,7 +1150,6 @@ ReflectInput(
goto stop;
}
readBytes = Tcl_ReadRaw(rtPtr->parent,
(char *) Tcl_SetByteArrayLength(bufObj, toRead), toRead);
if (readBytes < 0) {
@@ -1165,11 +1165,10 @@ ReflectInput(
}
/*
* Either the down channel is not blocked (a real error)
* or it is and there are gotBytes==0 byte copied so far.
* In either case, pass up the error, so we either report
* any real error, or do not mistakenly signal EOF by
* returning 0 to the caller.
* Either the down channel is not blocked (a real error) or it is
* and there are gotBytes==0 byte copied so far. In either case,
* pass up the error, so we either report any real error, or do
* not mistakenly signal EOF by returning 0 to the caller.
*/
*errorCodePtr = Tcl_GetErrno();
@@ -1177,7 +1176,6 @@ ReflectInput(
}
if (readBytes == 0) {
/*
* Zero returned from Tcl_ReadRaw() always indicates EOF
* on the down channel.
@@ -1185,26 +1183,26 @@ ReflectInput(
rtPtr->eofPending = 1;
/*
* Now this is a bit different. The partial data waiting is
* converted and returned.
*/
if (HAS(rtPtr->methods, METH_DRAIN)) {
if (!TransformDrain(rtPtr, errorCodePtr)) {
goto error;
}
}
if (ResultLength(&rtPtr->result) == 0) {
/*
* Now this is a bit different. The partial data waiting is
* converted and returned.
* The drain delivered nothing.
*/
if (HAS(rtPtr->methods, METH_DRAIN)) {
if (!TransformDrain(rtPtr, errorCodePtr)) {
goto error;
}
}
goto stop;
}
if (ResultLength(&rtPtr->result) == 0) {
/*
* The drain delivered nothing.
*/
goto stop;
}
continue; /* at: while (toRead > 0) */
continue; /* at: while (toRead > 0) */
} /* readBytes == 0 */
/*
@@ -1261,7 +1259,7 @@ ReflectOutput(
int toWrite,
int *errorCodePtr)
{
ReflectedTransform *rtPtr = (ReflectedTransform *)clientData;
ReflectedTransform *rtPtr = (ReflectedTransform *) clientData;
/*
* The following check can be done before thread redirection, because we
@@ -1388,16 +1386,15 @@ ReflectSeekWide(
curPos = -1;
} else {
curPos = Tcl_ChannelSeekProc(parent->typePtr)(
parent->instanceData, offset, seekMode,
errorCodePtr);
parent->instanceData, offset, seekMode, errorCodePtr);
}
#else
*errorCodePtr = EINVAL;
curPos = -1;
#endif
} else {
curPos = Tcl_ChannelWideSeekProc(parent->typePtr)(parent->instanceData, offset,
seekMode, errorCodePtr);
curPos = Tcl_ChannelWideSeekProc(parent->typePtr)(parent->instanceData,
offset, seekMode, errorCodePtr);
}
if (curPos == -1) {
Tcl_SetErrno(*errorCodePtr);
@@ -1423,8 +1420,7 @@ ReflectSeek(
* routine.
*/
return ReflectSeekWide(clientData, offset, seekMode,
errorCodePtr);
return ReflectSeekWide(clientData, offset, seekMode, errorCodePtr);
}
#endif
@@ -2042,6 +2038,7 @@ InvokeTclMethod(
* This is complex and ugly, and would be completely unnecessary
* if we only added support for a TCL_FORBID_EXCEPTIONS flag.
*/
if (result != TCL_ERROR) {
Tcl_Obj *cmd = Tcl_NewListObj(cmdc, rtPtr->argv);
int cmdLen;
@@ -2114,10 +2111,12 @@ static ReflectedTransformMap *
GetReflectedTransformMap(
Tcl_Interp *interp)
{
ReflectedTransformMap *rtmPtr = (ReflectedTransformMap *)Tcl_GetAssocData(interp, RTMKEY, NULL);
ReflectedTransformMap *rtmPtr = (ReflectedTransformMap *)
Tcl_GetAssocData(interp, RTMKEY, NULL);
if (rtmPtr == NULL) {
rtmPtr = (ReflectedTransformMap *)ckalloc(sizeof(ReflectedTransformMap));
rtmPtr = (ReflectedTransformMap *)
ckalloc(sizeof(ReflectedTransformMap));
Tcl_InitHashTable(&rtmPtr->map, TCL_STRING_KEYS);
Tcl_SetAssocData(interp, RTMKEY,
(Tcl_InterpDeleteProc *) DeleteReflectedTransformMap, rtmPtr);
@@ -2280,7 +2279,8 @@ GetThreadReflectedTransformMap(void)
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->rtmPtr) {
tsdPtr->rtmPtr = (ReflectedTransformMap *)ckalloc(sizeof(ReflectedTransformMap));
tsdPtr->rtmPtr = (ReflectedTransformMap *)
ckalloc(sizeof(ReflectedTransformMap));
Tcl_InitHashTable(&tsdPtr->rtmPtr->map, TCL_STRING_KEYS);
Tcl_CreateThreadExitHandler(DeleteThreadReflectedTransformMap, NULL);
}
@@ -2415,8 +2415,8 @@ ForwardOpToOwnerThread(
* Create and initialize the event and data structures.
*/
evPtr = (ForwardingEvent *)ckalloc(sizeof(ForwardingEvent));
resultPtr = (ForwardingResult *)ckalloc(sizeof(ForwardingResult));
evPtr = (ForwardingEvent *) ckalloc(sizeof(ForwardingEvent));
resultPtr = (ForwardingResult *) ckalloc(sizeof(ForwardingResult));
evPtr->event.proc = ForwardProc;
evPtr->resultPtr = resultPtr;
@@ -2759,7 +2759,7 @@ static void
SrcExitProc(
ClientData clientData)
{
ForwardingEvent *evPtr = (ForwardingEvent *)clientData;
ForwardingEvent *evPtr = (ForwardingEvent *) clientData;
ForwardingResult *resultPtr;
ForwardParam *paramPtr;
@@ -3230,7 +3230,7 @@ TransformDrain(
} else
#endif /* TCL_THREADS */
{
if (InvokeTclMethod(rtPtr, "drain", NULL, NULL, &resObj)!=TCL_OK) {
if (InvokeTclMethod(rtPtr, "drain", NULL, NULL, &resObj) != TCL_OK) {
Tcl_SetChannelError(rtPtr->chan, resObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
*errorCodePtr = EINVAL;
@@ -3285,7 +3285,7 @@ TransformFlush(
} else
#endif /* TCL_THREADS */
{
if (InvokeTclMethod(rtPtr, "flush", NULL, NULL, &resObj)!=TCL_OK) {
if (InvokeTclMethod(rtPtr, "flush", NULL, NULL, &resObj) != TCL_OK) {
Tcl_SetChannelError(rtPtr->chan, resObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
*errorCodePtr = EINVAL;
+703 -514
View File
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -195,19 +195,19 @@ struct LimitHandler {
};
/*
* Values for the LimitHandler flags field.
* LIMIT_HANDLER_ACTIVE - Whether the handler is currently being
* processed; handlers are never to be entered reentrantly.
* LIMIT_HANDLER_DELETED - Whether the handler has been deleted. This
* should not normally be observed because when a handler is
* deleted it is also spliced out of the list of handlers, but
* even so we will be careful.
* Values for bits in the LimitHandler flags field.
*/
#define LIMIT_HANDLER_ACTIVE 0x01
#define LIMIT_HANDLER_DELETED 0x02
enum {
LIMIT_HANDLER_ACTIVE = 1, /* Whether the handler is currently being
* processed; handlers are never to be entered
* reentrantly. */
LIMIT_HANDLER_DELETED = 2 /* Whether the handler has been deleted. This
* should not normally be observed because
* when a handler is deleted it is also
* spliced out of the list of handlers, but
* even so we will be careful. */
};
/*
* Prototypes for local static functions:
+16 -18
View File
@@ -75,21 +75,19 @@ typedef struct Link {
/*
* Definitions for flag bits:
* LINK_READ_ONLY - 1 means errors should be generated if Tcl
* script attempts to write variable.
* LINK_BEING_UPDATED - 1 means that a call to Tcl_UpdateLinkedVar is
* in progress for this variable, so trace
* callbacks on the variable should be ignored.
* LINK_ALLOC_ADDR - 1 means linkPtr->addr was allocated on the
* heap.
* LINK_ALLOC_LAST - 1 means linkPtr->valueLast.p was allocated on
* the heap.
*/
#define LINK_READ_ONLY 1
#define LINK_BEING_UPDATED 2
#define LINK_ALLOC_ADDR 4
#define LINK_ALLOC_LAST 8
enum {
LINK_READ_ONLY = 1, /* Errors should be generated if Tcl script
* attempts to write variable.*/
LINK_BEING_UPDATED = 2, /* A call to Tcl_UpdateLinkedVar is in
* progress for this variable, so trace
* callbacks on the variable should be
* ignored. */
LINK_ALLOC_ADDR = 4, /* linkPtr->addr was allocated on the heap. */
LINK_ALLOC_LAST = 8 /* linkPtr->valueLast.p was allocated on the
* heap. */
};
/*
* Forward references to functions defined later in this file:
@@ -110,11 +108,11 @@ static int SetInvalidRealFromAny(Tcl_Interp *interp,
*/
static Tcl_ObjType invalidRealType = {
"invalidReal", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL /* setFromAnyProc */
"invalidReal", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL /* setFromAnyProc */
};
/*
+5 -3
View File
@@ -105,9 +105,11 @@ typedef struct {
* Tcl_NewInstanceMethod.
*/
#define TCL_OO_METHOD_PUBLIC 1
#define TCL_OO_METHOD_UNEXPORTED 0
#define TCL_OO_METHOD_PRIVATE 0x20
enum {
TCL_OO_METHOD_UNEXPORTED = 0,
TCL_OO_METHOD_PUBLIC = 1,
TCL_OO_METHOD_PRIVATE = 0x20
};
/*
* The type of some object (or class) metadata. This describes how to delete
+112 -77
View File
@@ -51,38 +51,15 @@ typedef struct {
* Extra flags used for call chain management.
*/
#define DEFINITE_PROTECTED 0x100000
#define DEFINITE_PUBLIC 0x200000
#define KNOWN_STATE (DEFINITE_PROTECTED | DEFINITE_PUBLIC)
#define SPECIAL (CONSTRUCTOR | DESTRUCTOR | FORCE_UNKNOWN)
#define BUILDING_MIXINS 0x400000
#define TRAVERSED_MIXIN 0x800000
#define OBJECT_MIXIN 0x1000000
#define MIXIN_CONSISTENT(flags) \
(((flags) & OBJECT_MIXIN) || \
!((flags) & BUILDING_MIXINS) == !((flags) & TRAVERSED_MIXIN))
/*
* Note that the flag bit PRIVATE_METHOD has a confusing name; it's just for
* Itcl's special type of private.
*/
#define IS_PUBLIC(mPtr) \
(((mPtr)->flags & PUBLIC_METHOD) != 0)
#define IS_UNEXPORTED(mPtr) \
(((mPtr)->flags & SCOPE_FLAGS) == 0)
#define IS_ITCLPRIVATE(mPtr) \
(((mPtr)->flags & PRIVATE_METHOD) != 0)
#define IS_PRIVATE(mPtr) \
(((mPtr)->flags & TRUE_PRIVATE_METHOD) != 0)
#define WANT_PUBLIC(flags) \
(((flags) & PUBLIC_METHOD) != 0)
#define WANT_UNEXPORTED(flags) \
(((flags) & (PRIVATE_METHOD | TRUE_PRIVATE_METHOD)) == 0)
#define WANT_ITCLPRIVATE(flags) \
(((flags) & PRIVATE_METHOD) != 0)
#define WANT_PRIVATE(flags) \
(((flags) & TRUE_PRIVATE_METHOD) != 0)
enum {
DEFINITE_PROTECTED = 0x100000,
DEFINITE_PUBLIC = 0x200000,
KNOWN_STATE = (DEFINITE_PROTECTED | DEFINITE_PUBLIC),
SPECIAL = (CONSTRUCTOR | DESTRUCTOR | FORCE_UNKNOWN),
BUILDING_MIXINS = 0x400000,
TRAVERSED_MIXIN = 0x800000,
OBJECT_MIXIN = 0x1000000
};
/*
* Function declarations for things defined in this file.
@@ -152,7 +129,60 @@ static const Tcl_ObjType methodNameType = {
NULL,
NULL
};
/*
* Inline functions that test flags.
*/
static inline int
MixinConsistent(
int flags)
{
return (flags & OBJECT_MIXIN) ||
(!(flags & BUILDING_MIXINS) == !(flags & TRAVERSED_MIXIN));
}
static inline int
IsPublic(
Method *mPtr)
{
return (mPtr->flags & PUBLIC_METHOD) != 0;
}
static inline int
IsUnexported(
Method *mPtr)
{
return (mPtr->flags & SCOPE_FLAGS) == 0;
}
static inline int
IsPrivate(
Method *mPtr)
{
return (mPtr->flags & TRUE_PRIVATE_METHOD) != 0;
}
static inline int
WantPublic(
int flags)
{
return (flags & PUBLIC_METHOD) != 0;
}
static inline int
WantUnexported(
int flags)
{
return (flags & (PRIVATE_METHOD | TRUE_PRIVATE_METHOD)) == 0;
}
static inline int
WantPrivate(
int flags)
{
return (flags & TRUE_PRIVATE_METHOD) != 0;
}
/*
* ----------------------------------------------------------------------
@@ -279,16 +309,16 @@ DupMethodNameRep(
Tcl_Obj *srcPtr,
Tcl_Obj *dstPtr)
{
StashCallChain(dstPtr,
(CallChain *)TclFetchIntRep(srcPtr, &methodNameType)->twoPtrValue.ptr1);
StashCallChain(dstPtr, (CallChain *)
TclFetchIntRep(srcPtr, &methodNameType)->twoPtrValue.ptr1);
}
static void
FreeMethodNameRep(
Tcl_Obj *objPtr)
{
TclOODeleteChain(
(CallChain *)TclFetchIntRep(objPtr, &methodNameType)->twoPtrValue.ptr1);
TclOODeleteChain((CallChain *)
TclFetchIntRep(objPtr, &methodNameType)->twoPtrValue.ptr1);
}
/*
@@ -465,10 +495,10 @@ TclOOGetSortedMethodList(
if (oPtr->methodsPtr) {
FOREACH_HASH(namePtr, mPtr, oPtr->methodsPtr) {
if (IS_PRIVATE(mPtr)) {
if (IsPrivate(mPtr)) {
continue;
}
if (IS_UNEXPORTED(mPtr) && !WANT_UNEXPORTED(flags)) {
if (IsUnexported(mPtr) && !WantUnexported(flags)) {
continue;
}
AddStandardMethodName(flags, namePtr, mPtr, &names);
@@ -479,9 +509,9 @@ TclOOGetSortedMethodList(
* Process method names due to private methods on the object's class.
*/
if (WANT_UNEXPORTED(flags)) {
if (WantUnexported(flags)) {
FOREACH_HASH(namePtr, mPtr, &oPtr->selfCls->classMethods) {
if (IS_UNEXPORTED(mPtr)) {
if (IsUnexported(mPtr)) {
AddStandardMethodName(flags, namePtr, mPtr, &names);
}
}
@@ -551,7 +581,7 @@ TclOOGetSortedClassMethodList(
* Process private method names if we should. [TIP 500]
*/
if (WANT_PRIVATE(flags)) {
if (WantPrivate(flags)) {
AddPrivateMethodNames(&clsPtr->classMethods, &names);
flags &= ~TRUE_PRIVATE_METHOD;
}
@@ -615,7 +645,7 @@ SortMethodNames(
strings = (const char **)ckalloc(sizeof(char *) * namesPtr->numEntries);
FOREACH_HASH(namePtr, isWanted, namesPtr) {
if (!WANT_PUBLIC(flags) || (PTR2INT(isWanted) & IN_LIST)) {
if (!WantPublic(flags) || (PTR2INT(isWanted) & IN_LIST)) {
if (PTR2INT(isWanted) & NO_IMPLEMENTATION) {
continue;
}
@@ -766,7 +796,7 @@ AddPrivateMethodNames(
Tcl_Obj *namePtr;
FOREACH_HASH(namePtr, mPtr, methodsTablePtr) {
if (IS_PRIVATE(mPtr)) {
if (IsPrivate(mPtr)) {
int isNew;
hPtr = Tcl_CreateHashEntry(namesPtr, (char *) namePtr, &isNew);
@@ -782,13 +812,13 @@ AddStandardMethodName(
Method *mPtr,
Tcl_HashTable *namesPtr)
{
if (!IS_PRIVATE(mPtr)) {
if (!IsPrivate(mPtr)) {
int isNew;
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(namesPtr, (char *) namePtr, &isNew);
if (isNew) {
int isWanted = (!WANT_PUBLIC(flags) || IS_PUBLIC(mPtr))
int isWanted = (!WantPublic(flags) || IsPublic(mPtr))
? IN_LIST : 0;
isWanted |= (mPtr->typePtr == NULL ? NO_IMPLEMENTATION : 0);
@@ -836,7 +866,7 @@ AddInstancePrivateToCallContext(
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) methodName);
if (hPtr != NULL) {
mPtr = (Method *)Tcl_GetHashValue(hPtr);
if (IS_PRIVATE(mPtr)) {
if (IsPrivate(mPtr)) {
AddMethodToCallChain(mPtr, cbPtr, NULL, NULL, flags);
donePrivate = 1;
}
@@ -886,9 +916,9 @@ AddSimpleChainToCallContext(
if (hPtr != NULL) {
mPtr = (Method *)Tcl_GetHashValue(hPtr);
if (!IS_PRIVATE(mPtr)) {
if (WANT_PUBLIC(flags)) {
if (!IS_PUBLIC(mPtr)) {
if (!IsPrivate(mPtr)) {
if (WantPublic(flags)) {
if (!IsPublic(mPtr)) {
blockedUnexported = 1;
} else {
flags |= DEFINITE_PUBLIC;
@@ -916,7 +946,7 @@ AddSimpleChainToCallContext(
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char*) methodNameObj);
if (hPtr != NULL) {
mPtr = (Method *)Tcl_GetHashValue(hPtr);
if (!IS_PRIVATE(mPtr)) {
if (!IsPrivate(mPtr)) {
AddMethodToCallChain(mPtr, cbPtr, doneFilters, filterDecl,
flags);
}
@@ -979,7 +1009,7 @@ AddMethodToCallChain(
* This is also where we enforce mixin-consistency.
*/
if (mPtr == NULL || mPtr->typePtr == NULL || !MIXIN_CONSISTENT(flags)) {
if (mPtr == NULL || mPtr->typePtr == NULL || !MixinConsistent(flags)) {
return;
}
@@ -995,8 +1025,8 @@ AddMethodToCallChain(
* should be sufficient for [incr Tcl] support though.
*/
if (!WANT_UNEXPORTED(callPtr->flags)
&& IS_UNEXPORTED(mPtr)
if (!WantUnexported(callPtr->flags)
&& IsUnexported(mPtr)
&& (mPtr->declaringClassPtr != NULL)
&& (mPtr->declaringClassPtr != cbPtr->oPtr->selfCls)) {
return;
@@ -1156,7 +1186,7 @@ TclOOGetCallContext(
if (cacheInThisObj == NULL) {
cacheInThisObj = methodNameObj;
}
if (flags&(SPECIAL|FILTER_HANDLING) || (oPtr->flags&FILTER_HANDLING)) {
if (flags & (SPECIAL|FILTER_HANDLING) || (oPtr->flags & FILTER_HANDLING)) {
hPtr = NULL;
doFilters = 0;
@@ -1190,7 +1220,7 @@ TclOOGetCallContext(
*/
const Tcl_ObjIntRep *irPtr;
const int reuseMask = (WANT_PUBLIC(flags) ? ~0 : ~PUBLIC_METHOD);
const int reuseMask = (WantPublic(flags) ? ~0 : ~PUBLIC_METHOD);
if ((irPtr = TclFetchIntRep(cacheInThisObj, &methodNameType))) {
callPtr = (CallChain *)irPtr->twoPtrValue.ptr1;
@@ -1218,7 +1248,7 @@ TclOOGetCallContext(
}
if (hPtr != NULL && Tcl_GetHashValue(hPtr) != NULL) {
callPtr = (CallChain *)Tcl_GetHashValue(hPtr);
callPtr = (CallChain *) Tcl_GetHashValue(hPtr);
if (IsStillValid(callPtr, oPtr, flags, reuseMask)) {
callPtr->refCount++;
goto returnContext;
@@ -1230,7 +1260,7 @@ TclOOGetCallContext(
doFilters = 1;
}
callPtr = (CallChain *)ckalloc(sizeof(CallChain));
callPtr = (CallChain *) ckalloc(sizeof(CallChain));
InitCallChain(callPtr, oPtr, flags);
cb.callChainPtr = callPtr;
@@ -1335,7 +1365,7 @@ TclOOGetCallContext(
if (oPtr->flags & USE_CLASS_CACHE) {
if (oPtr->selfCls->classChainCache == NULL) {
oPtr->selfCls->classChainCache =
(Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
(Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(oPtr->selfCls->classChainCache);
}
@@ -1343,7 +1373,8 @@ TclOOGetCallContext(
(char *) methodNameObj, &i);
} else {
if (oPtr->chainCache == NULL) {
oPtr->chainCache = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
oPtr->chainCache = (Tcl_HashTable *)
ckalloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(oPtr->chainCache);
}
@@ -1369,7 +1400,8 @@ TclOOGetCallContext(
}
returnContext:
contextPtr = (CallContext *)TclStackAlloc(oPtr->fPtr->interp, sizeof(CallContext));
contextPtr = (CallContext *)
TclStackAlloc(oPtr->fPtr->interp, sizeof(CallContext));
contextPtr->oPtr = oPtr;
/*
@@ -1436,9 +1468,9 @@ TclOOGetStereotypeCallChain(
hPtr = Tcl_FindHashEntry(clsPtr->classChainCache,
(char *) methodNameObj);
if (hPtr != NULL && Tcl_GetHashValue(hPtr) != NULL) {
const int reuseMask = (WANT_PUBLIC(flags) ? ~0 : ~PUBLIC_METHOD);
const int reuseMask = (WantPublic(flags) ? ~0 : ~PUBLIC_METHOD);
callPtr = (CallChain *)Tcl_GetHashValue(hPtr);
callPtr = (CallChain *) Tcl_GetHashValue(hPtr);
if (IsStillValid(callPtr, &obj, flags, reuseMask)) {
callPtr->refCount++;
return callPtr;
@@ -1450,9 +1482,9 @@ TclOOGetStereotypeCallChain(
hPtr = NULL;
}
callPtr = (CallChain *)ckalloc(sizeof(CallChain));
callPtr = (CallChain *) ckalloc(sizeof(CallChain));
memset(callPtr, 0, sizeof(CallChain));
callPtr->flags = flags & (PUBLIC_METHOD|PRIVATE_METHOD|FILTER_HANDLING);
callPtr->flags = flags & (PUBLIC_METHOD | PRIVATE_METHOD | FILTER_HANDLING);
callPtr->epoch = fPtr->epoch;
callPtr->objectCreationEpoch = fPtr->tsdPtr->nsCount;
callPtr->objectEpoch = clsPtr->thisPtr->epoch;
@@ -1505,7 +1537,8 @@ TclOOGetStereotypeCallChain(
} else {
if (hPtr == NULL) {
if (clsPtr->classChainCache == NULL) {
clsPtr->classChainCache = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
clsPtr->classChainCache = (Tcl_HashTable *)
ckalloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(clsPtr->classChainCache);
}
hPtr = Tcl_CreateHashEntry(clsPtr->classChainCache,
@@ -1568,7 +1601,7 @@ AddClassFiltersToCallContext(
* override how filters work to extend their behaviour.
*/
if (MIXIN_CONSISTENT(flags)) {
if (MixinConsistent(flags)) {
FOREACH(filterObj, clsPtr->filters) {
int isNew;
@@ -1658,7 +1691,7 @@ AddPrivatesFromClassChainToCallContext(
if (hPtr != NULL) {
Method *mPtr = (Method *)Tcl_GetHashValue(hPtr);
if (IS_PRIVATE(mPtr)) {
if (IsPrivate(mPtr)) {
AddMethodToCallChain(mPtr, cbPtr, doneFilters, filterDecl,
flags);
return 1;
@@ -1743,10 +1776,10 @@ AddSimpleClassChainToCallContext(
if (hPtr != NULL) {
Method *mPtr = (Method *)Tcl_GetHashValue(hPtr);
if (!IS_PRIVATE(mPtr)) {
if (!IsPrivate(mPtr)) {
if (!(flags & KNOWN_STATE)) {
if (flags & PUBLIC_METHOD) {
if (!IS_PUBLIC(mPtr)) {
if (!IsPublic(mPtr)) {
return privateDanger;
}
flags |= DEFINITE_PUBLIC;
@@ -1821,14 +1854,15 @@ TclOORenderCallChain(
* method (or "object" if it is declared on the instance).
*/
objv = (Tcl_Obj **)TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
objv = (Tcl_Obj **)
TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
for (i = 0 ; i < callPtr->numChain ; i++) {
struct MInvoke *miPtr = &callPtr->chain[i];
descObjs[0] =
miPtr->isFilter ? filterLiteral :
callPtr->flags & OO_UNKNOWN_METHOD ? fPtr->unknownMethodNameObj :
IS_PRIVATE(miPtr->mPtr) ? privateLiteral :
IsPrivate(miPtr->mPtr) ? privateLiteral :
methodLiteral;
descObjs[1] =
callPtr->flags & CONSTRUCTOR ? fPtr->constructorName :
@@ -2027,8 +2061,9 @@ AddSimpleClassDefineNamespaces(
static inline void
AddDefinitionNamespaceToChain(
Class *const definerCls, /* What class defines this entry. */
Tcl_Obj *const namespaceName, /* The name for this entry (or NULL, a
Class *const definerCls, /* What class defines this entry. */
Tcl_Obj *const namespaceName,
/* The name for this entry (or NULL, a
* no-op). */
DefineChain *const definePtr,
/* The define chain to add the method
@@ -2047,7 +2082,7 @@ AddDefinitionNamespaceToChain(
* mixin-consistency.
*/
if (namespaceName == NULL || !MIXIN_CONSISTENT(flags)) {
if (namespaceName == NULL || !MixinConsistent(flags)) {
return;
}
@@ -2088,12 +2123,12 @@ AddDefinitionNamespaceToChain(
if (definePtr->num == DEFINE_CHAIN_STATIC_SIZE) {
DefineEntry *staticList = definePtr->list;
definePtr->list =
(DefineEntry *)ckalloc(sizeof(DefineEntry) * definePtr->size);
definePtr->list = (DefineEntry *)
ckalloc(sizeof(DefineEntry) * definePtr->size);
memcpy(definePtr->list, staticList,
sizeof(DefineEntry) * definePtr->num);
} else {
definePtr->list = (DefineEntry *)ckrealloc(definePtr->list,
definePtr->list = (DefineEntry *) ckrealloc(definePtr->list,
sizeof(DefineEntry) * definePtr->size);
}
}
+34 -28
View File
@@ -103,16 +103,19 @@ typedef struct ProcedureMethod {
/*
* Flags for use in a ProcedureMethod.
*
* When the USE_DECLARER_NS flag is set, the method will use the namespace of
* the object or class that declared it (or the clone of it, if it was from
* such that the implementation of the method came to the particular use)
* instead of the namespace of the object on which the method was invoked.
* This flag must be distinct from all others that are associated with
* methods.
*/
#define USE_DECLARER_NS 0x80
enum {
USE_DECLARER_NS = 0x80 /* When the USE_DECLARER_NS flag is set, the
* method will use the namespace of the object
* or class that declared it (or the clone of
* it, if it was from such that the
* implementation of the method came to the
* particular use) instead of the namespace of
* the object on which the method was invoked.
* This flag must be distinct from all others
* that are associated with methods. */
};
/*
* Forwarded methods have the following extra information.
@@ -213,36 +216,38 @@ typedef struct Object {
* command. */
} Object;
#define OBJECT_DESTRUCTING 1 /* Indicates that an object is being or has
* been destroyed */
#define DESTRUCTOR_CALLED 2 /* Indicates that evaluation of destructor script for the
object has began */
#define OO_UNUSED_4 4 /* No longer used. */
#define ROOT_OBJECT 0x1000 /* Flag to say that this object is the root of
enum {
OBJECT_DESTRUCTING = 1, /* Indicates that an object is being or has
* been destroyed */
DESTRUCTOR_CALLED = 2, /* Indicates that evaluation of destructor
* script for the object has began */
OO_UNUSED_4 = 4, /* No longer used. */
ROOT_OBJECT = 0x1000, /* Flag to say that this object is the root of
* the class hierarchy and should be treated
* specially during teardown. */
#define FILTER_HANDLING 0x2000 /* Flag set when the object is processing a
FILTER_HANDLING = 0x2000, /* Flag set when the object is processing a
* filter; when set, filters are *not*
* processed on the object, preventing nasty
* recursive filtering problems. */
#define USE_CLASS_CACHE 0x4000 /* Flag set to say that the object is a pure
USE_CLASS_CACHE = 0x4000, /* Flag set to say that the object is a pure
* instance of the class, and has had nothing
* added that changes the dispatch chain (i.e.
* no methods, mixins, or filters. */
#define ROOT_CLASS 0x8000 /* Flag to say that this object is the root
ROOT_CLASS = 0x8000, /* Flag to say that this object is the root
* class of classes, and should be treated
* specially during teardown (and in a few
* other spots). */
#define FORCE_UNKNOWN 0x10000 /* States that we are *really* looking up the
FORCE_UNKNOWN = 0x10000, /* States that we are *really* looking up the
* unknown method handler at that point. */
#define HAS_PRIVATE_METHODS 0x20000
HAS_PRIVATE_METHODS = 0x20000,
/* Object/class has (or had) private methods,
* and so shouldn't be cached so
* aggressively. */
#define DONT_DELETE 0x40000 /* Inhibit deletion of this object. Used
DONT_DELETE = 0x40000 /* Inhibit deletion of this object. Used
* during fundamental object type mutation to
* make sure that the object actually survives
* to the end of the operation. */
};
/*
* And the definition of a class. Note that every class also has an associated
@@ -418,17 +423,18 @@ typedef struct CallContext {
* Bits for the 'flags' field of the call chain.
*/
#define PUBLIC_METHOD 0x01 /* This is a public (exported) method. */
#define PRIVATE_METHOD 0x02 /* This is a private (class's direct instances
enum {
PUBLIC_METHOD = 0x01, /* This is a public (exported) method. */
PRIVATE_METHOD = 0x02, /* This is a private (class's direct instances
* only) method. Supports itcl. */
#define OO_UNKNOWN_METHOD 0x04 /* This is an unknown method. */
#define CONSTRUCTOR 0x08 /* This is a constructor. */
#define DESTRUCTOR 0x10 /* This is a destructor. */
#define TRUE_PRIVATE_METHOD 0x20
/* This is a private method only accessible
OO_UNKNOWN_METHOD = 0x04, /* This is an unknown method. */
CONSTRUCTOR = 0x08, /* This is a constructor. */
DESTRUCTOR = 0x10, /* This is a destructor. */
TRUE_PRIVATE_METHOD = 0x20, /* This is a private method only accessible
* from other methods defined on this class
* or instance. [TIP #500] */
#define SCOPE_FLAGS (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
SCOPE_FLAGS = (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
};
/*
* Structure containing definition information about basic class methods.
+208 -195
View File
@@ -165,19 +165,19 @@ static PendingObjData pendingObjData;
static __thread PendingObjData pendingObjData;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = &pendingObjData
#else
#else /* TCL_THREADS && !defined(HAVE_FAST_TSD) */
static Tcl_ThreadDataKey pendingObjDataKey;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = \
(PendingObjData *)Tcl_GetThreadData(&pendingObjDataKey, sizeof(PendingObjData))
PendingObjData *const contextPtr = (PendingObjData *) \
Tcl_GetThreadData(&pendingObjDataKey, sizeof(PendingObjData))
#endif
/*
* Macros to pack/unpack a bignum's fields in a Tcl_Obj internal rep
* Macro to pack a bignum's fields in a Tcl_Obj internal rep
*/
#define PACK_BIGNUM(bignum, objPtr) \
if ((bignum).used > 0x7FFF) { \
if ((bignum).used > 0x7FFF) { \
mp_int *temp = (mp_int *)ckalloc(sizeof(mp_int)); \
*temp = bignum; \
(objPtr)->internalRep.twoPtrValue.ptr1 = temp; \
@@ -185,9 +185,28 @@ static Tcl_ThreadDataKey pendingObjDataKey;
} else if (((bignum).alloc <= 0x7FFF) || (mp_shrink(&(bignum))) == MP_OKAY) { \
(objPtr)->internalRep.twoPtrValue.ptr1 = (void *)(bignum).dp; \
(objPtr)->internalRep.twoPtrValue.ptr2 = INT2PTR(((bignum).sign << 30) \
| ((bignum).alloc << 15) | ((bignum).used)); \
| ((bignum).alloc << 15) | ((bignum).used)); \
}
/*
* Standard way to report a failure to parse something as an integer. This
* would probably be an exception throw if this was C++, but it isn't...
*/
static inline int
NotAnInteger(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
}
/*
* Prototypes for functions defined later in this file:
*/
@@ -234,7 +253,7 @@ static const Tcl_ObjType oldBooleanType = {
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
TclSetBooleanFromAny /* setFromAnyProc */
TclSetBooleanFromAny /* setFromAnyProc */
};
#endif
const Tcl_ObjType tclBooleanType = {
@@ -242,7 +261,7 @@ const Tcl_ObjType tclBooleanType = {
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
TclSetBooleanFromAny /* setFromAnyProc */
TclSetBooleanFromAny /* setFromAnyProc */
};
const Tcl_ObjType tclDoubleType = {
"double", /* name */
@@ -255,7 +274,8 @@ const Tcl_ObjType tclIntType = {
#if defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8 || defined(TCL_WIDE_INT_IS_LONG)
"int", /* name */
#else
"wideInt", /* name, keeping maximum compatibility with Tcl 8.6 on 32-bit platforms*/
"wideInt", /* name, keeping maximum compatibility with
* Tcl 8.6 on 32-bit platforms*/
#endif
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
@@ -336,7 +356,7 @@ typedef struct ResolvedCmdName {
* reference (not the namespace that contains
* the referenced command). NULL if the name
* is fully qualified.*/
unsigned long refNsId; /* refNsPtr's unique namespace id. Used to
unsigned long refNsId; /* refNsPtr's unique namespace id. Used to
* verify that refNsPtr is still valid (e.g.,
* it's possible that the cmd's containing
* namespace was deleted and a new one created
@@ -402,7 +422,7 @@ TclInitObjSubsystem(void)
Tcl_RegisterObjType(&oldIntType);
#endif
Tcl_RegisterObjType(&oldBooleanType);
#endif
#endif /* !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 */
#ifdef TCL_COMPILE_STATS
Tcl_MutexLock(&tclObjMutex);
@@ -416,7 +436,7 @@ TclInitObjSubsystem(void)
}
}
Tcl_MutexUnlock(&tclObjMutex);
#endif
#endif /* TCL_COMPILE_STATS */
}
/*
@@ -567,7 +587,8 @@ TclContinuationsEnter(
ThreadSpecificData *tsdPtr = TclGetContLineTable();
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(tsdPtr->lineCLPtr, objPtr, &newEntry);
ContLineLoc *clLocPtr = (ContLineLoc *)ckalloc(offsetof(ContLineLoc, loc) + (num + 1) *sizeof(int));
ContLineLoc *clLocPtr = (ContLineLoc *)
ckalloc(offsetof(ContLineLoc, loc) + (num + 1) *sizeof(int));
if (!newEntry) {
/*
@@ -1028,7 +1049,7 @@ TclDbDumpActiveObjects(
TCL_UNUSED(FILE *))
{
}
#endif
#endif /* TCL_THREADS && defined(TCL_MEM_DEBUG) */
/*
*----------------------------------------------------------------------
@@ -1326,7 +1347,7 @@ TclFreeObj(
Tcl_DeleteHashEntry(hPtr);
}
}
# endif
#endif /* TCL_THREADS */
/*
* Check for a double free of the same value. This is slightly tricky
@@ -1553,24 +1574,27 @@ TclObjBeingDeleted(
*----------------------------------------------------------------------
*/
#define SetDuplicateObj(dupPtr, objPtr) \
{ \
const Tcl_ObjType *typePtr = (objPtr)->typePtr; \
const char *bytes = (objPtr)->bytes; \
if (bytes) { \
TclInitStringRep((dupPtr), bytes, (objPtr)->length); \
} else { \
(dupPtr)->bytes = NULL; \
} \
if (typePtr) { \
if (typePtr->dupIntRepProc) { \
typePtr->dupIntRepProc((objPtr), (dupPtr)); \
} else { \
(dupPtr)->internalRep = (objPtr)->internalRep; \
(dupPtr)->typePtr = typePtr; \
} \
} \
static inline void
SetDuplicateObj(
Tcl_Obj *dupPtr,
Tcl_Obj *objPtr)
{
const Tcl_ObjType *typePtr = objPtr->typePtr;
const char *bytes = objPtr->bytes;
if (bytes) {
TclInitStringRep(dupPtr, bytes, objPtr->length);
} else {
dupPtr->bytes = NULL;
}
if (typePtr) {
if (typePtr->dupIntRepProc) {
typePtr->dupIntRepProc(objPtr, dupPtr);
} else {
dupPtr->internalRep = objPtr->internalRep;
dupPtr->typePtr = typePtr;
}
}
}
Tcl_Obj *
Tcl_DuplicateObj(
@@ -1620,7 +1644,7 @@ TclSetDuplicateObj(
#undef Tcl_GetString
char *
Tcl_GetString(
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
* be returned. */
{
if (objPtr->bytes == NULL) {
@@ -1677,9 +1701,9 @@ Tcl_GetString(
#undef Tcl_GetStringFromObj
char *
Tcl_GetStringFromObj(
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
* be returned. */
int *lengthPtr) /* If non-NULL, the location where the string
int *lengthPtr) /* If non-NULL, the location where the string
* rep's byte array length should * be stored.
* If NULL, no length is stored. */
{
@@ -1717,9 +1741,9 @@ Tcl_GetStringFromObj(
#undef TclGetStringFromObj
char *
TclGetStringFromObj(
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
* be returned. */
size_t *lengthPtr) /* If non-NULL, the location where the string
size_t *lengthPtr) /* If non-NULL, the location where the string
* rep's byte array length should * be stored.
* If NULL, no length is stored. */
{
@@ -1757,42 +1781,40 @@ TclGetStringFromObj(
}
return objPtr->bytes;
}
/*
*----------------------------------------------------------------------
*
* Tcl_InitStringRep --
*
* This function is called in several configurations to provide all
* the tools needed to set an object's string representation. The
* function is determined by the arguments.
* This function is called in several configurations to provide all the
* tools needed to set an object's string representation. The function is
* determined by the arguments.
*
* (objPtr->bytes != NULL && bytes != NULL) || (numBytes < 0)
* Invalid call -- panic!
*
* objPtr->bytes == NULL && bytes == NULL && numBytes >= 0
* Allocation only - allocate space for (numBytes+1) chars.
* store in objPtr->bytes and return. Also sets
* objPtr->length to 0 and objPtr->bytes[0] to NUL.
* Allocation only - allocate space for (numBytes+1) chars. Store in
* objPtr->bytes and return. Also sets objPtr->length to 0 and
* objPtr->bytes[0] to NUL.
*
* objPtr->bytes == NULL && bytes != NULL && numBytes >= 0
* Allocate and copy. bytes is assumed to point to chars to
* copy into the string rep. objPtr->length = numBytes. Allocate
* array of (numBytes + 1) chars. store in objPtr->bytes. Copy
* numBytes chars from bytes to objPtr->bytes; Set
* objPtr->bytes[numBytes] to NUL and return objPtr->bytes.
* Caller must guarantee there are numBytes chars at bytes to
* be copied.
* Allocate and copy. bytes is assumed to point to chars to copy into
* the string rep. objPtr->length = numBytes. Allocate array of
* (numBytes + 1) chars. store in objPtr->bytes. Copy numBytes chars
* from bytes to objPtr->bytes; Set objPtr->bytes[numBytes] to NUL
* and return objPtr->bytes. Caller must guarantee there are
* numBytes chars at bytes to be copied.
*
* objPtr->bytes != NULL && bytes == NULL && numBytes >= 0
* Truncate. Set objPtr->length to numBytes and
* objPr->bytes[numBytes] to NUL. Caller has to guarantee
* that a prior allocating call allocated enough bytes for
* this to be valid. Return objPtr->bytes.
* objPr->bytes[numBytes] to NUL. Caller has to guarantee that a
* prior allocating call allocated enough bytes for this to be
* valid. Return objPtr->bytes.
*
* Caller is expected to ascertain that the bytes copied into
* the string rep make up complete valid UTF-8 characters.
* Caller is expected to ascertain that the bytes copied into the string
* rep make up complete valid UTF-8 characters.
*
* Results:
* A pointer to the string rep of objPtr.
@@ -1805,7 +1827,7 @@ TclGetStringFromObj(
char *
Tcl_InitStringRep(
Tcl_Obj *objPtr, /* Object whose string rep is to be set */
Tcl_Obj *objPtr, /* Object whose string rep is to be set */
const char *bytes,
unsigned int numBytes)
{
@@ -1817,7 +1839,9 @@ Tcl_InitStringRep(
/* Allocate */
if (objPtr->bytes == NULL) {
/* Allocate only as empty - extend later if bytes copied */
/*
* Allocate only as empty - extend later if bytes copied.
*/
objPtr->length = 0;
if (numBytes) {
objPtr->bytes = (char *)attemptckalloc(numBytes + 1);
@@ -1864,7 +1888,7 @@ Tcl_InitStringRep(
void
Tcl_InvalidateStringRep(
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
* be freed. */
{
TclInvalidateStringRep(objPtr);
@@ -1884,7 +1908,7 @@ Tcl_InvalidateStringRep(
int
Tcl_HasStringRep(
Tcl_Obj *objPtr) /* Object to test */
Tcl_Obj *objPtr) /* Object to test */
{
return TclHasStringRep(objPtr);
}
@@ -1939,12 +1963,12 @@ Tcl_StoreIntRep(
* representation matching a requested type, if any.
*
* Results:
* A read-only pointer to the associated Tcl_ObjIntRep, or
* NULL if no such internal representation exists.
* A read-only pointer to the associated Tcl_ObjIntRep, or NULL if no
* such internal representation exists.
*
* Side effects:
* Calls the freeIntRepProc of the current Tcl_ObjType, if any.
* Sets the internalRep and typePtr fields to the submitted values.
* Calls the freeIntRepProc of the current Tcl_ObjType, if any. Sets the
* internalRep and typePtr fields to the submitted values.
*
*----------------------------------------------------------------------
*/
@@ -1968,8 +1992,8 @@ Tcl_FetchIntRep(
* None.
*
* Side effects:
* Calls the freeIntRepProc of the current Tcl_ObjType, if any.
* Sets typePtr field to NULL.
* Calls the freeIntRepProc of the current Tcl_ObjType, if any. Sets
* typePtr field to NULL.
*
*----------------------------------------------------------------------
*/
@@ -1987,9 +2011,9 @@ Tcl_FreeIntRep(
* Tcl_NewBooleanObj --
*
* This function is normally called when not debugging: i.e., when
* TCL_MEM_DEBUG is not defined. It creates a new Tcl_Obj and
* initializes it from the argument boolean value. A nonzero "boolValue"
* is coerced to 1.
* TCL_MEM_DEBUG is not defined. It creates a new Tcl_Obj and initializes
* it from the argument boolean value. A nonzero "boolValue" is coerced
* to 1.
*
* When TCL_MEM_DEBUG is defined, this function just returns the result
* of calling the debugging version Tcl_DbNewLongObj.
@@ -2009,7 +2033,7 @@ Tcl_FreeIntRep(
Tcl_Obj *
Tcl_NewBooleanObj(
int boolValue) /* Boolean used to initialize new object. */
int boolValue) /* Boolean used to initialize new object. */
{
return Tcl_DbNewWideIntObj(boolValue!=0, "unknown", 0);
}
@@ -2018,7 +2042,7 @@ Tcl_NewBooleanObj(
Tcl_Obj *
Tcl_NewBooleanObj(
int boolValue) /* Boolean used to initialize new object. */
int boolValue) /* Boolean used to initialize new object. */
{
Tcl_Obj *objPtr;
@@ -2059,7 +2083,7 @@ Tcl_NewBooleanObj(
Tcl_Obj *
Tcl_DbNewBooleanObj(
int boolValue, /* Boolean used to initialize new object. */
int boolValue, /* Boolean used to initialize new object. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
@@ -2109,8 +2133,8 @@ Tcl_DbNewBooleanObj(
#undef Tcl_SetBooleanObj
void
Tcl_SetBooleanObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
int boolValue) /* Boolean used to set object's value. */
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
int boolValue) /* Boolean used to set object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetBooleanObj");
@@ -2142,8 +2166,8 @@ Tcl_SetBooleanObj(
int
Tcl_GetBooleanFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get boolean. */
int *boolPtr) /* Place to store resulting boolean. */
Tcl_Obj *objPtr, /* The object from which to get boolean. */
int *boolPtr) /* Place to store resulting boolean. */
{
do {
if (objPtr->typePtr == &tclIntType) {
@@ -2208,7 +2232,7 @@ Tcl_GetBooleanFromObj(
int
TclSetBooleanFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
Tcl_Obj *objPtr) /* The object to convert. */
{
/*
* For some "pure" numeric Tcl_ObjTypes (no string rep), we can determine
@@ -2444,7 +2468,7 @@ Tcl_NewDoubleObj(
Tcl_Obj *
Tcl_DbNewDoubleObj(
double dblValue, /* Double used to initialize the object. */
double dblValue, /* Double used to initialize the object. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
@@ -2465,7 +2489,7 @@ Tcl_DbNewDoubleObj(
Tcl_Obj *
Tcl_DbNewDoubleObj(
double dblValue, /* Double used to initialize the object. */
double dblValue, /* Double used to initialize the object. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
@@ -2493,8 +2517,8 @@ Tcl_DbNewDoubleObj(
void
Tcl_SetDoubleObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
double dblValue) /* Double used to set the object's value. */
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
double dblValue) /* Double used to set the object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetDoubleObj");
@@ -2526,8 +2550,8 @@ Tcl_SetDoubleObj(
int
Tcl_GetDoubleFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a double. */
double *dblPtr) /* Place to store resulting double. */
Tcl_Obj *objPtr, /* The object from which to get a double. */
double *dblPtr) /* Place to store resulting double. */
{
do {
if (objPtr->typePtr == &tclDoubleType) {
@@ -2610,7 +2634,7 @@ SetDoubleFromAny(
static void
UpdateStringOfDouble(
Tcl_Obj *objPtr) /* Double obj with string rep to update. */
Tcl_Obj *objPtr) /* Double obj with string rep to update. */
{
char *dst = Tcl_InitStringRep(objPtr, NULL, TCL_DOUBLE_SPACE);
@@ -2656,7 +2680,7 @@ UpdateStringOfDouble(
Tcl_Obj *
Tcl_NewIntObj(
int intValue) /* Int used to initialize the new object. */
int intValue) /* Int used to initialize the new object. */
{
return Tcl_DbNewWideIntObj((long)intValue, "unknown", 0);
}
@@ -2665,7 +2689,7 @@ Tcl_NewIntObj(
Tcl_Obj *
Tcl_NewIntObj(
int intValue) /* Int used to initialize the new object. */
int intValue) /* Int used to initialize the new object. */
{
Tcl_Obj *objPtr;
@@ -2696,8 +2720,8 @@ Tcl_NewIntObj(
#undef Tcl_SetIntObj
void
Tcl_SetIntObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
int intValue) /* Integer used to set object's value. */
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
int intValue) /* Integer used to set object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetIntObj");
@@ -2736,8 +2760,8 @@ Tcl_SetIntObj(
int
Tcl_GetIntFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a int. */
int *intPtr) /* Place to store resulting int. */
Tcl_Obj *objPtr, /* The object from which to get a int. */
int *intPtr) /* Place to store resulting int. */
{
#if (LONG_MAX == INT_MAX)
return TclGetLongFromObj(interp, objPtr, (long *) intPtr);
@@ -2808,7 +2832,7 @@ SetIntFromAny(
static void
UpdateStringOfInt(
Tcl_Obj *objPtr) /* Int object whose string rep to update. */
Tcl_Obj *objPtr) /* Int object whose string rep to update. */
{
char *dst = Tcl_InitStringRep( objPtr, NULL, TCL_INTEGER_SPACE);
@@ -2820,7 +2844,7 @@ UpdateStringOfInt(
#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9 && !defined(TCL_WIDE_INT_IS_LONG)
static void
UpdateStringOfOldInt(
Tcl_Obj *objPtr) /* Int object whose string rep to update. */
Tcl_Obj *objPtr) /* Int object whose string rep to update. */
{
char *dst = Tcl_InitStringRep( objPtr, NULL, TCL_INTEGER_SPACE);
@@ -2866,8 +2890,8 @@ UpdateStringOfOldInt(
Tcl_Obj *
Tcl_NewLongObj(
long longValue) /* Long integer used to initialize the
* new object. */
long longValue) /* Long integer used to initialize the new
* object. */
{
return Tcl_DbNewWideIntObj(longValue, "unknown", 0);
}
@@ -2876,8 +2900,8 @@ Tcl_NewLongObj(
Tcl_Obj *
Tcl_NewLongObj(
long longValue) /* Long integer used to initialize the
* new object. */
long longValue) /* Long integer used to initialize the new
* object. */
{
Tcl_Obj *objPtr;
@@ -2925,7 +2949,7 @@ Tcl_NewLongObj(
Tcl_Obj *
Tcl_DbNewLongObj(
long longValue, /* Long integer used to initialize the new
long longValue, /* Long integer used to initialize the new
* object. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
@@ -2947,7 +2971,7 @@ Tcl_DbNewLongObj(
Tcl_Obj *
Tcl_DbNewLongObj(
long longValue, /* Long integer used to initialize the new
long longValue, /* Long integer used to initialize the new
* object. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
@@ -2979,8 +3003,8 @@ Tcl_DbNewLongObj(
#undef Tcl_SetLongObj
void
Tcl_SetLongObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
long longValue) /* Long integer used to initialize the
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
long longValue) /* Long integer used to initialize the
* object's value. */
{
if (Tcl_IsShared(objPtr)) {
@@ -3015,8 +3039,8 @@ Tcl_SetLongObj(
int
Tcl_GetLongFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a long. */
long *longPtr) /* Place to store resulting long. */
Tcl_Obj *objPtr, /* The object from which to get a long. */
long *longPtr) /* Place to store resulting long. */
{
do {
#ifdef TCL_WIDE_INT_IS_LONG
@@ -3043,15 +3067,9 @@ Tcl_GetLongFromObj(
}
goto tooLarge;
}
#endif
#endif /* TCL_WIDE_INT_IS_LONG */
if (objPtr->typePtr == &tclDoubleType) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
return NotAnInteger(interp, objPtr);
}
if (objPtr->typePtr == &tclBignumType) {
/*
@@ -3061,7 +3079,6 @@ Tcl_GetLongFromObj(
* values in the unsigned long range will fit in a long.
*/
{
mp_int big;
unsigned long scratch, value = 0;
unsigned char *bytes = (unsigned char *) &scratch;
@@ -3070,7 +3087,7 @@ Tcl_GetLongFromObj(
TclUnpackBignum(objPtr, big);
if (mp_to_ubin(&big, bytes, sizeof(long), &numBytes) == MP_OKAY) {
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
value = (value << CHAR_BIT) | *bytes++;
}
if (big.sign) {
if (value <= 1 + (unsigned long)LONG_MAX) {
@@ -3084,21 +3101,20 @@ Tcl_GetLongFromObj(
}
}
}
}
#ifndef TCL_WIDE_INT_IS_LONG
tooLarge:
#endif
if (interp != NULL) {
const char *s = "integer value too large to represent";
Tcl_Obj *msg = Tcl_NewStringObj(s, -1);
Tcl_SetObjResult(interp, msg);
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, NULL);
}
return TCL_ERROR;
goto tooLarge;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
TCL_PARSE_INTEGER_ONLY) == TCL_OK);
return TCL_ERROR;
tooLarge:
if (interp != NULL) {
const char *s = "integer value too large to represent";
Tcl_Obj *msg = Tcl_NewStringObj(s, -1);
Tcl_SetObjResult(interp, msg);
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, NULL);
}
return TCL_ERROR;
}
@@ -3240,7 +3256,7 @@ Tcl_DbNewWideIntObj(
void
Tcl_SetWideIntObj(
Tcl_Obj *objPtr, /* Object w. internal rep to init. */
Tcl_Obj *objPtr, /* Object w. internal rep to init. */
Tcl_WideInt wideValue)
/* Wide integer used to initialize the
* object's value. */
@@ -3276,7 +3292,7 @@ Tcl_SetWideIntObj(
int
Tcl_GetWideIntFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* Object from which to get a wide int. */
Tcl_Obj *objPtr, /* Object from which to get a wide int. */
Tcl_WideInt *wideIntPtr)
/* Place to store resulting long. */
{
@@ -3286,13 +3302,7 @@ Tcl_GetWideIntFromObj(
return TCL_OK;
}
if (objPtr->typePtr == &tclDoubleType) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
return NotAnInteger(interp, objPtr);
}
if (objPtr->typePtr == &tclBignumType) {
/*
@@ -3323,17 +3333,20 @@ Tcl_GetWideIntFromObj(
}
}
}
if (interp != NULL) {
const char *s = "integer value too large to represent";
Tcl_Obj *msg = Tcl_NewStringObj(s, -1);
Tcl_SetObjResult(interp, msg);
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, NULL);
}
return TCL_ERROR;
goto tooLarge;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
TCL_PARSE_INTEGER_ONLY) == TCL_OK);
return TCL_ERROR;
tooLarge:
if (interp != NULL) {
const char *s = "integer value too large to represent";
Tcl_Obj *msg = Tcl_NewStringObj(s, -1);
Tcl_SetObjResult(interp, msg);
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, NULL);
}
return TCL_ERROR;
}
@@ -3371,13 +3384,7 @@ TclGetWideBitsFromObj(
return TCL_OK;
}
if (objPtr->typePtr == &tclDoubleType) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
return NotAnInteger(interp, objPtr);
}
if (objPtr->typePtr == &tclBignumType) {
mp_int big;
@@ -3403,7 +3410,7 @@ TclGetWideBitsFromObj(
return TCL_OK;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
TCL_PARSE_INTEGER_ONLY) == TCL_OK);
return TCL_ERROR;
}
@@ -3643,11 +3650,13 @@ GetBignumFromObj(
objPtr->internalRep.twoPtrValue.ptr1 = NULL;
objPtr->internalRep.twoPtrValue.ptr2 = NULL;
objPtr->typePtr = NULL;
/*
* TODO: If objPtr has a string rep, this leaves
* it undisturbed. Not clear that's proper. Pure
* bignum values are converted to empty string.
* TODO: If objPtr has a string rep, this leaves it
* undisturbed. Not clear that's proper. Pure bignum values
* are converted to empty string.
*/
if (objPtr->bytes == NULL) {
TclInitStringRep(objPtr, NULL, 0);
}
@@ -3662,16 +3671,10 @@ GetBignumFromObj(
return TCL_OK;
}
if (objPtr->typePtr == &tclDoubleType) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected integer but got \"%s\"",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
}
return TCL_ERROR;
return NotAnInteger(interp, objPtr);
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
TCL_PARSE_INTEGER_ONLY) == TCL_OK);
return TCL_ERROR;
}
@@ -3909,7 +3912,8 @@ TclGetNumberFromObj(
#undef Tcl_IncrRefCount
void
Tcl_IncrRefCount(
Tcl_Obj *objPtr) /* The object we are registering a reference to. */
Tcl_Obj *objPtr) /* The object we are registering a reference
* to. */
{
++(objPtr)->refCount;
}
@@ -3930,7 +3934,8 @@ Tcl_IncrRefCount(
#undef Tcl_DecrRefCount
void
Tcl_DecrRefCount(
Tcl_Obj *objPtr) /* The object we are releasing a reference to. */
Tcl_Obj *objPtr) /* The object we are releasing a reference
* to. */
{
if (objPtr->refCount-- <= 1) {
TclFreeObj(objPtr);
@@ -3953,7 +3958,7 @@ Tcl_DecrRefCount(
#undef Tcl_IsShared
int
Tcl_IsShared(
Tcl_Obj *objPtr) /* The object to test for being shared. */
Tcl_Obj *objPtr) /* The object to test for being shared. */
{
return ((objPtr)->refCount > 1);
}
@@ -3982,7 +3987,7 @@ Tcl_IsShared(
#ifdef TCL_MEM_DEBUG
void
Tcl_DbIncrRefCount(
Tcl_Obj *objPtr, /* The object we are registering a reference
Tcl_Obj *objPtr, /* The object we are registering a reference
* to. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
@@ -4055,7 +4060,7 @@ Tcl_DbIncrRefCount(
#ifdef TCL_MEM_DEBUG
void
Tcl_DbDecrRefCount(
Tcl_Obj *objPtr, /* The object we are releasing a reference
Tcl_Obj *objPtr, /* The object we are releasing a reference
* to. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
@@ -4098,7 +4103,7 @@ Tcl_DbDecrRefCount(
#else /* !TCL_MEM_DEBUG */
void
Tcl_DbDecrRefCount(
Tcl_Obj *objPtr, /* The object we are releasing a reference
Tcl_Obj *objPtr, /* The object we are releasing a reference
* to. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
@@ -4132,7 +4137,7 @@ Tcl_DbDecrRefCount(
int
Tcl_DbIsShared(
Tcl_Obj *objPtr, /* The object to test for being shared. */
Tcl_Obj *objPtr, /* The object to test for being shared. */
#ifdef TCL_MEM_DEBUG
const char *file, /* The name of the source file calling this
* function; used for debugging. */
@@ -4279,7 +4284,9 @@ TclCompareObjKeys(
* If the object pointers are the same then they match.
* OPT: this comparison was moved to the caller
if (objPtr1 == objPtr2) return 1;
if (objPtr1 == objPtr2) {
return 1;
}
*/
/*
@@ -4430,7 +4437,7 @@ Tcl_Command
Tcl_GetCommandFromObj(
Tcl_Interp *interp, /* The interpreter in which to resolve the
* command and to report errors. */
Tcl_Obj *objPtr) /* The object containing the command's name.
Tcl_Obj *objPtr) /* The object containing the command's name.
* If the name starts with "::", will be
* looked up in global namespace. Else, looked
* up first in the current namespace, then in
@@ -4479,9 +4486,10 @@ Tcl_GetCommandFromObj(
/*
* OK, must create a new internal representation (or fail) as any cache we
* had is invalid one way or another.
*
* See [07d13d99b0a9] why we cannot call SetCmdNameFromAny() directly here.
*/
/* See [07d13d99b0a9] why we cannot call SetCmdNameFromAny() directly here. */
if (tclCmdNameType.setFromAnyProc(interp, objPtr) != TCL_OK) {
return NULL;
}
@@ -4531,7 +4539,10 @@ SetCmdNameObj(
cmdPtr->refCount++;
fillPtr->cmdEpoch = cmdPtr->cmdEpoch;
/* NOTE: relying on NULL termination here. */
/*
* NOTE: relying on NULL termination here.
*/
if ((name[0] == ':') && (name[1] == ':')) {
/*
* Fully qualified names always resolve to same thing. No need
@@ -4546,6 +4557,7 @@ SetCmdNameObj(
* Record current state of current namespace as the resolution
* context of this command name lookup.
*/
Namespace *currNsPtr = iPtr->varFramePtr->nsPtr;
fillPtr->refNsPtr = currNsPtr;
@@ -4566,7 +4578,7 @@ void
TclSetCmdNameObj(
Tcl_Interp *interp, /* Points to interpreter containing command
* that should be cached in objPtr. */
Tcl_Obj *objPtr, /* Points to Tcl object to be changed to a
Tcl_Obj *objPtr, /* Points to Tcl object to be changed to a
* CmdName object. */
Command *cmdPtr) /* Points to Command structure that the
* CmdName object should refer to. */
@@ -4606,28 +4618,28 @@ TclSetCmdNameObj(
static void
FreeCmdNameInternalRep(
Tcl_Obj *objPtr) /* CmdName object with internal
Tcl_Obj *objPtr) /* CmdName object with internal
* representation to free. */
{
ResolvedCmdName *resPtr = (ResolvedCmdName *)objPtr->internalRep.twoPtrValue.ptr1;
ResolvedCmdName *resPtr = (ResolvedCmdName *)
objPtr->internalRep.twoPtrValue.ptr1;
/*
* Decrement the reference count of the ResolvedCmdName structure. If
* there are no more uses, free the ResolvedCmdName structure.
*/
/*
* Decrement the reference count of the ResolvedCmdName structure. If
* there are no more uses, free the ResolvedCmdName structure.
*/
if (resPtr->refCount-- <= 1) {
/*
* Now free the cached command, unless it is still in its hash
* table or if there are other references to it from other cmdName
* objects.
*/
if (resPtr->refCount-- <= 1) {
/*
* Now free the cached command, unless it is still in its hash table
* or if there are other references to it from other cmdName objects.
*/
Command *cmdPtr = resPtr->cmdPtr;
Command *cmdPtr = resPtr->cmdPtr;
TclCleanupCommandMacro(cmdPtr);
ckfree(resPtr);
}
TclCleanupCommandMacro(cmdPtr);
ckfree(resPtr);
}
objPtr->typePtr = NULL;
}
@@ -4654,9 +4666,10 @@ FreeCmdNameInternalRep(
static void
DupCmdNameInternalRep(
Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
Tcl_Obj *copyPtr) /* Object with internal rep to set. */
Tcl_Obj *copyPtr) /* Object with internal rep to set. */
{
ResolvedCmdName *resPtr = (ResolvedCmdName *)srcPtr->internalRep.twoPtrValue.ptr1;
ResolvedCmdName *resPtr = (ResolvedCmdName *)
srcPtr->internalRep.twoPtrValue.ptr1;
copyPtr->internalRep.twoPtrValue.ptr1 = resPtr;
copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
@@ -4688,7 +4701,7 @@ DupCmdNameInternalRep(
static int
SetCmdNameFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
Tcl_Obj *objPtr) /* The object to convert. */
{
const char *name;
Command *cmdPtr;
@@ -4722,8 +4735,8 @@ SetCmdNameFromAny(
resPtr = (ResolvedCmdName *)objPtr->internalRep.twoPtrValue.ptr1;
if ((objPtr->typePtr == &tclCmdNameType) && (resPtr->refCount == 1)) {
/*
* Re-use existing ResolvedCmdName struct when possible.
* Cleanup the old fields that need it.
* Re-use existing ResolvedCmdName struct when possible. Cleanup the
* old fields that need it.
*/
Command *oldCmdPtr = resPtr->cmdPtr;
+24 -14
View File
@@ -119,7 +119,7 @@ const char tclCharTypeTable[] = {
* Prototypes for local functions defined in this file:
*/
static int CommandComplete(const char *script, int numBytes);
static int CommandComplete(const char *script, int numBytes);
static int ParseComment(const char *src, int numBytes,
Tcl_Parse *parsePtr);
static int ParseTokens(const char *src, int numBytes, int mask,
@@ -197,7 +197,7 @@ Tcl_ParseCommand(
* NULL, then no error message is provided. */
const char *start, /* First character of string containing one or
* more Tcl commands. */
int numBytes, /* Total number of bytes in string. If < 0,
int numBytes, /* Total number of bytes in string. If < 0,
* the script consists of all bytes up to the
* first null character. */
int nested, /* Non-zero means this is a nested command:
@@ -209,7 +209,7 @@ Tcl_ParseCommand(
* the parsed command; any previous
* information in the structure is ignored. */
{
const char *src; /* Points to current character in the
const char *src; /* Points to current character in the
* command. */
char type; /* Result returned by CHAR_TYPE(*src). */
Tcl_Token *tokenPtr; /* Pointer to token being filled in. */
@@ -786,7 +786,8 @@ TclParseBackslash(
* of bytes scanned should be written. */
char *dst) /* NULL, or points to buffer where the UTF-8
* encoding of the backslash sequence is to be
* written. At most 4 bytes will be written there. */
* written. At most 4 bytes will be written
* there. */
{
const char *p = src+1;
int unichar;
@@ -870,10 +871,14 @@ TclParseBackslash(
result = 'u';
} else if (((result & 0xFC00) == 0xD800) && (count == 6)
&& (p[5] == '\\') && (p[6] == 'u') && (numBytes >= 10)) {
/* If high surrogate is immediately followed by a low surrogate
* escape, combine them into one character. */
/*
* If high surrogate is immediately followed by a low surrogate
* escape, combine them into one character.
*/
int low;
int count2 = ParseHex(p+7, 4, &low);
if ((count2 == 4) && ((low & 0xFC00) == 0xDC00)) {
result = ((result & 0x3FF)<<10 | (low & 0x3FF)) + 0x10000;
count += count2 + 2;
@@ -888,7 +893,9 @@ TclParseBackslash(
*/
result = 'U';
} else if ((result | 0x7FF) == 0xDFFF) {
/* Upper or lower surrogate, not allowed in this syntax. */
/*
* Upper or lower surrogate, not allowed in this syntax.
*/
result = 0xFFFD;
}
break;
@@ -954,7 +961,10 @@ TclParseBackslash(
}
count = Tcl_UniCharToUtf(result, dst);
if ((result >= 0xD800) && (count < 3)) {
/* Special case for handling high surrogates. */
/*
* Special case for handling high surrogates.
*/
count += Tcl_UniCharToUtf(-1, dst + count);
}
return count;
@@ -981,7 +991,7 @@ TclParseBackslash(
static int
ParseComment(
const char *src, /* First character to parse. */
int numBytes, /* Max number of bytes to scan. */
int numBytes, /* Max number of bytes to scan. */
Tcl_Parse *parsePtr) /* Information about parse in progress.
* Updated if parsing indicates an incomplete
* command. */
@@ -1053,8 +1063,8 @@ ParseComment(
static int
ParseTokens(
const char *src, /* First character to parse. */
int numBytes, /* Max number of bytes to scan. */
const char *src, /* First character to parse. */
int numBytes, /* Max number of bytes to scan. */
int mask, /* Specifies when to stop parsing. The parse
* stops at the first unquoted character whose
* CHAR_TYPE contains any of the bits in
@@ -1524,7 +1534,7 @@ Tcl_ParseVarName(
const char *
Tcl_ParseVar(
Tcl_Interp *interp, /* Context for looking up variable. */
const char *start, /* Start of variable substitution. First
const char *start, /* Start of variable substitution. First
* character must be "$". */
const char **termPtr) /* If non-NULL, points to word to fill in with
* character just after last one in the
@@ -1609,7 +1619,7 @@ Tcl_ParseBraces(
* NULL, then no error message is provided. */
const char *start, /* Start of string enclosed in braces. The
* first character must be {'. */
int numBytes, /* Total number of bytes in string. If < 0,
int numBytes, /* Total number of bytes in string. If < 0,
* the string consists of all bytes up to the
* first null character. */
Tcl_Parse *parsePtr,
@@ -1810,7 +1820,7 @@ Tcl_ParseQuotedString(
* NULL, then no error message is provided. */
const char *start, /* Start of the quoted string. The first
* character must be '"'. */
int numBytes, /* Total number of bytes in string. If < 0,
int numBytes, /* Total number of bytes in string. If < 0,
* the string consists of all bytes up to the
* first null character. */
Tcl_Parse *parsePtr,
+10 -8
View File
@@ -3,14 +3,16 @@
* source files can make use of the parsing table in tclParse.c
*/
#define TYPE_NORMAL 0
#define TYPE_SPACE 0x1
#define TYPE_COMMAND_END 0x2
#define TYPE_SUBS 0x4
#define TYPE_QUOTE 0x8
#define TYPE_CLOSE_PAREN 0x10
#define TYPE_CLOSE_BRACK 0x20
#define TYPE_BRACE 0x40
enum {
TYPE_NORMAL = 0,
TYPE_SPACE = 0x1,
TYPE_COMMAND_END = 0x2,
TYPE_SUBS = 0x4,
TYPE_QUOTE = 0x8,
TYPE_CLOSE_PAREN = 0x10,
TYPE_CLOSE_BRACK = 0x20,
TYPE_BRACE = 0x40
};
#define CHAR_TYPE(c) tclCharTypeTable[(unsigned char)(c)]
+41 -26
View File
@@ -77,23 +77,36 @@ typedef struct FsPath {
* Flag values for FsPath->flags.
*/
#define TCLPATH_APPENDED 1
#define TCLPATH_NEEDNORM 4
enum {
TCLPATH_APPENDED = 1,
TCLPATH_NEEDNORM = 4
};
/*
* Define some macros to give us convenient access to path-object specific
* fields.
* Define some inline functions to give us convenient fast access to
* path-object specific fields.
*/
#define PATHOBJ(pathPtr) ((FsPath *) (TclFetchIntRep((pathPtr), &fsPathType)->twoPtrValue.ptr1))
#define SETPATHOBJ(pathPtr,fsPathPtr) \
do { \
Tcl_ObjIntRep ir; \
ir.twoPtrValue.ptr1 = (void *) (fsPathPtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreIntRep((pathPtr), &fsPathType, &ir); \
} while (0)
#define PATHFLAGS(pathPtr) (PATHOBJ(pathPtr)->flags)
static inline FsPath *
PATHOBJ(
Tcl_Obj *pathPtr)
{
return (FsPath *) TclFetchIntRep(pathPtr, &fsPathType)->twoPtrValue.ptr1;
}
static inline void
SETPATHOBJ(
Tcl_Obj *pathPtr,
FsPath *fsPathPtr)
{
Tcl_ObjIntRep ir;
ir.twoPtrValue.ptr1 = (void *) fsPathPtr;
ir.twoPtrValue.ptr2 = NULL;
Tcl_StoreIntRep(pathPtr, &fsPathType, &ir);
}
#define PATHFLAGS(pathPtr) (PATHOBJ(pathPtr)->flags)
/*
*---------------------------------------------------------------------------
@@ -143,17 +156,17 @@ TclFSNormalizeAbsolutePath(
dirSep = TclGetString(pathPtr);
if (tclPlatform == TCL_PLATFORM_WINDOWS) {
if ( (dirSep[0] == '/' || dirSep[0] == '\\')
&& (dirSep[1] == '/' || dirSep[1] == '\\')
&& (dirSep[2] == '?')
&& (dirSep[3] == '/' || dirSep[3] == '\\')) {
if ( (dirSep[0] == '/' || dirSep[0] == '\\') &&
(dirSep[1] == '/' || dirSep[1] == '\\') &&
(dirSep[2] == '?') &&
(dirSep[3] == '/' || dirSep[3] == '\\')) {
/* NT extended path */
dirSep += 4;
if ( (dirSep[0] == 'U' || dirSep[0] == 'u')
&& (dirSep[1] == 'N' || dirSep[1] == 'n')
&& (dirSep[2] == 'C' || dirSep[2] == 'c')
&& (dirSep[3] == '/' || dirSep[3] == '\\')) {
if ( (dirSep[0] == 'U' || dirSep[0] == 'u') &&
(dirSep[1] == 'N' || dirSep[1] == 'n') &&
(dirSep[2] == 'C' || dirSep[2] == 'c') &&
(dirSep[3] == '/' || dirSep[3] == '\\')) {
/* NT extended UNC path */
dirSep += 4;
}
@@ -161,8 +174,8 @@ TclFSNormalizeAbsolutePath(
if (dirSep[0] != 0 && dirSep[1] == ':' &&
(dirSep[2] == '/' || dirSep[2] == '\\')) {
/* Do nothing */
} else if ((dirSep[0] == '/' || dirSep[0] == '\\')
&& (dirSep[1] == '/' || dirSep[1] == '\\')) {
} else if ((dirSep[0] == '/' || dirSep[0] == '\\') &&
(dirSep[1] == '/' || dirSep[1] == '\\')) {
/*
* UNC style path, where we must skip over the first separator,
* since the first two segments are actually inseparable.
@@ -932,7 +945,7 @@ TclJoinPath(
}
}
assert ( res == NULL );
assert (res == NULL);
for (i = 0; i < elements; i++) {
int driveNameLength, strEltLen, length;
@@ -1107,7 +1120,7 @@ TclJoinPath(
Tcl_SetObjLength(res, length);
}
}
assert ( res != NULL );
assert (res != NULL);
return res;
}
@@ -1760,7 +1773,9 @@ Tcl_FSGetNormalizedPath(
TclFSNormalizeToUniquePath(interp, copy, cwdLen);
}
/* Now we need to construct the new path object. */
/*
* Now we need to construct the new path object.
*/
if (pathType == TCL_PATH_RELATIVE) {
Tcl_Obj *origDir = fsPathPtr->cwdPtr;
+22 -17
View File
@@ -16,13 +16,14 @@
* Flag values used by Tcl_ScanObjCmd.
*/
#define SCAN_NOSKIP 0x1 /* Don't skip blanks. */
#define SCAN_SUPPRESS 0x2 /* Suppress assignment. */
#define SCAN_UNSIGNED 0x4 /* Read an unsigned value. */
#define SCAN_WIDTH 0x8 /* A width value was supplied. */
#define SCAN_LONGER 0x400 /* Asked for a wide value. */
#define SCAN_BIG 0x800 /* Asked for a bignum value. */
enum {
SCAN_NOSKIP = 0x1, /* Don't skip blanks. */
SCAN_SUPPRESS = 0x2, /* Suppress assignment. */
SCAN_UNSIGNED = 0x4, /* Read an unsigned value. */
SCAN_WIDTH = 0x8, /* A width value was supplied. */
SCAN_LONGER = 0x400, /* Asked for a wide value. */
SCAN_BIG = 0x800 /* Asked for a bignum value. */
};
/*
* The following structure contains the information associated with a
@@ -104,9 +105,10 @@ BuildCharSet(
end += TclUtfToUniChar(end, &ch);
}
cset->chars = (Tcl_UniChar *)ckalloc(sizeof(Tcl_UniChar) * (end - format - 1));
cset->chars = (Tcl_UniChar *)
ckalloc(sizeof(Tcl_UniChar) * (end - format - 1));
if (nranges > 0) {
cset->ranges = (Range *)ckalloc(sizeof(Range) * nranges);
cset->ranges = (Range *) ckalloc(sizeof(Range) * nranges);
} else {
cset->ranges = NULL;
}
@@ -262,7 +264,7 @@ ValidateFormat(
char *end;
Tcl_UniChar ch = 0;
int objIndex, xpgSize, nspace = numVars;
int *nassign = (int *)TclStackAlloc(interp, nspace * sizeof(int));
int *nassign = (int *) TclStackAlloc(interp, nspace * sizeof(int));
Tcl_Obj *errorMsg; /* Place to build an error messages. Note that
* these are messy operations because we do
* not want to use the formatting engine;
@@ -479,7 +481,7 @@ ValidateFormat(
} else {
nspace += 16; /* formerly STATIC_LIST_SIZE */
}
nassign = (int *)TclStackRealloc(interp, nassign,
nassign = (int *) TclStackRealloc(interp, nassign,
nspace * sizeof(int));
for (i = value; i < nspace; i++) {
nassign[i] = 0;
@@ -588,7 +590,7 @@ Tcl_ScanObjCmd(
}
format = Tcl_GetString(objv[2]);
numVars = objc-3;
numVars = objc - 3;
/*
* Check for errors in the format string.
@@ -603,7 +605,7 @@ Tcl_ScanObjCmd(
*/
if (totalVars > 0) {
objs = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * totalVars);
objs = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * totalVars);
for (i = 0; i < totalVars; i++) {
objs[i] = NULL;
}
@@ -890,13 +892,15 @@ Tcl_ScanObjCmd(
/*
* Scan an unsigned or signed integer.
*/
TclNewIntObj(objPtr, 0);
Tcl_IncrRefCount(objPtr);
if (width == 0) {
width = ~0;
}
if (TCL_OK != TclParseNumber(NULL, objPtr, NULL, string, width,
&end, TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_UNDERSCORE | parseFlag)) {
&end, TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_UNDERSCORE |
parseFlag)) {
Tcl_DecrRefCount(objPtr);
if (width < 0) {
if (*end == '\0') {
@@ -979,7 +983,7 @@ Tcl_ScanObjCmd(
}
#else
Tcl_SetWideIntObj(objPtr, (unsigned long)value);
#endif
#endif /* TCL_WIDE_INT_IS_LONG */
} else {
TclSetIntObj(objPtr, value);
}
@@ -998,7 +1002,8 @@ Tcl_ScanObjCmd(
width = ~0;
}
if (TCL_OK != TclParseNumber(NULL, objPtr, NULL, string, width,
&end, TCL_PARSE_DECIMAL_ONLY | TCL_PARSE_NO_WHITESPACE | TCL_PARSE_NO_UNDERSCORE)) {
&end, TCL_PARSE_DECIMAL_ONLY | TCL_PARSE_NO_WHITESPACE |
TCL_PARSE_NO_UNDERSCORE)) {
Tcl_DecrRefCount(objPtr);
if (width < 0) {
if (*end == '\0') {
@@ -1022,7 +1027,7 @@ Tcl_ScanObjCmd(
if (irPtr) {
dvalue = irPtr->doubleValue;
} else
#endif
#endif /* ACCEPT_NAN */
{
Tcl_DecrRefCount(objPtr);
goto done;
+17 -16
View File
@@ -68,25 +68,26 @@ typedef struct {
* TCL_TRACE_ENTER_DURING_EXEC == 4 * TCL_TRACE_ENTER_EXEC and that
* TCL_TRACE_LEAVE_DURING_EXEC == 4 * TCL_TRACE_LEAVE_EXEC.
*
* TCL_TRACE_ENTER_DURING_EXEC - Trace each command inside the command
* currently being traced, before execution.
* TCL_TRACE_LEAVE_DURING_EXEC - Trace each command inside the command
* currently being traced, after execution.
* TCL_TRACE_ANY_EXEC - OR'd combination of all EXEC flags.
* TCL_TRACE_EXEC_IN_PROGRESS - The callback function on this trace is
* currently executing. Therefore we don't let
* further traces execute.
* TCL_TRACE_EXEC_DIRECT - This execution trace is triggered directly
* by the command being traced, not because of
* an internal trace.
* The flag 'TCL_TRACE_DESTROYED' may also be used in command execution traces.
*/
#define TCL_TRACE_ENTER_DURING_EXEC 4
#define TCL_TRACE_LEAVE_DURING_EXEC 8
#define TCL_TRACE_ANY_EXEC 15
#define TCL_TRACE_EXEC_IN_PROGRESS 0x10
#define TCL_TRACE_EXEC_DIRECT 0x20
enum {
TCL_TRACE_ENTER_DURING_EXEC = 4,
/* Trace each command inside the command
* currently being traced, before execution.*/
TCL_TRACE_LEAVE_DURING_EXEC = 8,
/* Trace each command inside the command
* currently being traced, after execution. */
TCL_TRACE_ANY_EXEC = 15, /* OR'd combination of all EXEC flags. */
TCL_TRACE_EXEC_IN_PROGRESS = 0x10,
/* The callback function on this trace is
* currently executing. Therefore we don't let
* further traces execute. */
TCL_TRACE_EXEC_DIRECT = 0x20
/* This execution trace is triggered directly
* by the command being traced, not because of
* an internal trace. */
};
/*
* Forward declarations for functions defined in this file:
+7 -5
View File
@@ -88,11 +88,13 @@ static ProcessGlobalValue executableName = {
*/
#define COMPAT 1
#define CONVERT_NONE 0
#define CONVERT_BRACE 2
#define CONVERT_ESCAPE 4
#define CONVERT_MASK (CONVERT_BRACE | CONVERT_ESCAPE)
#define CONVERT_ANY 16
enum {
CONVERT_NONE = 0,
CONVERT_BRACE = 2,
CONVERT_ESCAPE = 4,
CONVERT_MASK = (CONVERT_BRACE | CONVERT_ESCAPE),
CONVERT_ANY = 16
};
/*
* The following key is used by Tcl_PrintDouble and TclPrecTraceProc to
+258 -71
View File
@@ -21,8 +21,14 @@
#ifndef _WIN32
#include <sys/mman.h>
#include <sys/stat.h>
#endif /* _WIN32*/
#ifndef EXPOSE_ZIP_COMMENTS
/* Tcl API for ZIP comments is disabled for now */
#define EXPOSE_ZIP_COMMENTS 0
#endif /* !EXPOSE_ZIP_COMMENTS */
#ifndef MAP_FILE
#define MAP_FILE 0
#endif /* !MAP_FILE */
@@ -30,7 +36,7 @@
#define crc32tab crc_table[0]
#ifndef TBLS
#define TBLS 1
#endif
#endif /* !TBLS */
#ifdef HAVE_ZLIB
#include "zlib.h"
@@ -57,60 +63,121 @@
/*
* Local header of ZIP archive member (at very beginning of each member).
*
* We'd use structs, except we must work in little-endian even on big-endian
* architectures. There isn't a way to tell a known compiler to do that for
* us. Also, they're not necessarily aligned, which would be bonus fun.
*/
#if 0
struct LocalHeader {
uint32_t signature; /* == ZIP_LOCAL_HEADER_SIG */
uint16_t version;
uint16_t flags;
uint16_t compMethod;
uint16_t modTime;
uint16_t modDate;
uint32_t crc32;
uint32_t compLen;
uint32_t uncompLen;
uint32_t pathLen;
uint16_t extraLen;
};
#endif
#define ZIP_LOCAL_HEADER_SIG 0x04034b50
#define ZIP_LOCAL_HEADER_LEN 30
#define ZIP_LOCAL_SIG_OFFS 0
#define ZIP_LOCAL_VERSION_OFFS 4
#define ZIP_LOCAL_FLAGS_OFFS 6
#define ZIP_LOCAL_COMPMETH_OFFS 8
#define ZIP_LOCAL_MTIME_OFFS 10
#define ZIP_LOCAL_MDATE_OFFS 12
#define ZIP_LOCAL_CRC32_OFFS 14
#define ZIP_LOCAL_COMPLEN_OFFS 18
#define ZIP_LOCAL_UNCOMPLEN_OFFS 22
#define ZIP_LOCAL_PATHLEN_OFFS 26
#define ZIP_LOCAL_EXTRALEN_OFFS 28
enum {
ZIP_LOCAL_SIG_OFFS = 0,
ZIP_LOCAL_VERSION_OFFS = 4,
ZIP_LOCAL_FLAGS_OFFS = 6,
ZIP_LOCAL_COMPMETH_OFFS = 8,
ZIP_LOCAL_MTIME_OFFS = 10,
ZIP_LOCAL_MDATE_OFFS = 12,
ZIP_LOCAL_CRC32_OFFS = 14,
ZIP_LOCAL_COMPLEN_OFFS = 18,
ZIP_LOCAL_UNCOMPLEN_OFFS = 22,
ZIP_LOCAL_PATHLEN_OFFS = 26,
ZIP_LOCAL_EXTRALEN_OFFS = 28
};
/*
* Central header of ZIP archive member at end of ZIP file.
*/
#if 0
struct CentralHeader {
uint32_t signature; /* == ZIP_CENTRAL_HEADER_SIG */
uint16_t versionMade;
uint16_t version;
uint16_t flags;
uint16_t compMethod;
uint16_t modTime;
uint16_t modDate;
uint32_t crc32;
uint32_t compLen;
uint32_t uncompLen;
uint16_t pathLen;
uint16_t extraLen;
uint16_t commentLen;
uint16_t diskFile;
uint16_t internalAttributes;/* Don't use; always set to 0 */
uint32_t externalAttributes;
uint32_t localHeaderOffset;
};
#endif
#define ZIP_CENTRAL_HEADER_SIG 0x02014b50
#define ZIP_CENTRAL_HEADER_LEN 46
#define ZIP_CENTRAL_SIG_OFFS 0
#define ZIP_CENTRAL_VERSIONMADE_OFFS 4
#define ZIP_CENTRAL_VERSION_OFFS 6
#define ZIP_CENTRAL_FLAGS_OFFS 8
#define ZIP_CENTRAL_COMPMETH_OFFS 10
#define ZIP_CENTRAL_MTIME_OFFS 12
#define ZIP_CENTRAL_MDATE_OFFS 14
#define ZIP_CENTRAL_CRC32_OFFS 16
#define ZIP_CENTRAL_COMPLEN_OFFS 20
#define ZIP_CENTRAL_UNCOMPLEN_OFFS 24
#define ZIP_CENTRAL_PATHLEN_OFFS 28
#define ZIP_CENTRAL_EXTRALEN_OFFS 30
#define ZIP_CENTRAL_FCOMMENTLEN_OFFS 32
#define ZIP_CENTRAL_DISKFILE_OFFS 34
#define ZIP_CENTRAL_IATTR_OFFS 36
#define ZIP_CENTRAL_EATTR_OFFS 38
#define ZIP_CENTRAL_LOCALHDR_OFFS 42
enum {
ZIP_CENTRAL_SIG_OFFS = 0,
ZIP_CENTRAL_VERSIONMADE_OFFS = 4,
ZIP_CENTRAL_VERSION_OFFS = 6,
ZIP_CENTRAL_FLAGS_OFFS = 8,
ZIP_CENTRAL_COMPMETH_OFFS = 10,
ZIP_CENTRAL_MTIME_OFFS = 12,
ZIP_CENTRAL_MDATE_OFFS = 14,
ZIP_CENTRAL_CRC32_OFFS = 16,
ZIP_CENTRAL_COMPLEN_OFFS = 20,
ZIP_CENTRAL_UNCOMPLEN_OFFS = 24,
ZIP_CENTRAL_PATHLEN_OFFS = 28,
ZIP_CENTRAL_EXTRALEN_OFFS = 30,
ZIP_CENTRAL_FCOMMENTLEN_OFFS = 32,
ZIP_CENTRAL_DISKFILE_OFFS = 34,
ZIP_CENTRAL_IATTR_OFFS = 36,
ZIP_CENTRAL_EATTR_OFFS = 38,
ZIP_CENTRAL_LOCALHDR_OFFS = 42
};
/*
* Central end signature at very end of ZIP file.
*/
#if 0
struct CentralEnd {
uint32_t signature; /* == ZIP_CENTRAL_END_SIG */
uint16_t diskNumber;
uint16_t directoryDisk;
uint16_t numEntries;
uint16_t totalNumEntries;
uint32_t dirSize;
uint32_t dirLen;
uint16_t commentLen;
};
#endif
#define ZIP_CENTRAL_END_SIG 0x06054b50
#define ZIP_CENTRAL_END_LEN 22
#define ZIP_CENTRAL_END_SIG_OFFS 0
#define ZIP_CENTRAL_DISKNO_OFFS 4
#define ZIP_CENTRAL_DISKDIR_OFFS 6
#define ZIP_CENTRAL_ENTS_OFFS 8
#define ZIP_CENTRAL_TOTALENTS_OFFS 10
#define ZIP_CENTRAL_DIRSIZE_OFFS 12
#define ZIP_CENTRAL_DIRSTART_OFFS 16
#define ZIP_CENTRAL_COMMENTLEN_OFFS 20
enum {
ZIP_CENTRAL_END_SIG_OFFS = 0,
ZIP_CENTRAL_DISKNO_OFFS = 4,
ZIP_CENTRAL_DISKDIR_OFFS = 6,
ZIP_CENTRAL_ENTS_OFFS = 8,
ZIP_CENTRAL_TOTALENTS_OFFS = 10,
ZIP_CENTRAL_DIRSIZE_OFFS = 12,
ZIP_CENTRAL_DIRSTART_OFFS = 16,
ZIP_CENTRAL_COMMENTLEN_OFFS = 20
};
#define ZIP_MIN_VERSION 20
#define ZIP_COMPMETH_STORED 0
@@ -152,15 +219,6 @@
} \
} while (0)
/*
* Windows drive letters.
*/
#ifdef _WIN32
static const char drvletters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
#endif /* _WIN32 */
/*
* Mutex to protect localtime(3) when no reentrant version available.
*/
@@ -191,6 +249,8 @@ typedef struct ZipFile {
size_t baseOffset; /* Archive start */
size_t passOffset; /* Password start */
size_t directoryOffset; /* Archive directory start */
char *comment; /* Already converted archive-level comment, if
* present. NULL if absent. */
unsigned char passBuf[264]; /* Password buffer */
size_t numOpen; /* Number of open files on archive */
struct ZipEntry *entries; /* List of files in archive */
@@ -204,7 +264,6 @@ typedef struct ZipFile {
/*
* In-core description of file contained in mounted ZIP archive.
* ZIP_ATTR_
*/
typedef struct ZipEntry {
@@ -220,6 +279,8 @@ typedef struct ZipEntry {
int timestamp; /* Modification time */
int isEncrypted; /* True if data is encrypted */
unsigned char *data; /* File data if written */
char *comment; /* Already converted file-level comment, if
* present. NULL if absent. */
struct ZipEntry *next; /* Next file in the same archive */
struct ZipEntry *tnext; /* Next top-level dir in archive */
} ZipEntry;
@@ -831,6 +892,12 @@ CanonicalPath(
int haveZipfsPath = 1;
#ifdef _WIN32
/*
* Windows drive letters.
*/
static const char drvletters[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (tail[0] != '\0' && strchr(drvletters, tail[0]) && tail[1] == ':') {
tail += 2;
haveZipfsPath = 0;
@@ -1113,6 +1180,10 @@ ZipFSCloseArchive(
Tcl_Interp *interp, /* Current interpreter. */
ZipFile *zf)
{
if (zf->comment) {
ckfree(zf->comment);
zf->comment = NULL;
}
if (zf->nameLength) {
ckfree(zf->name);
}
@@ -1185,6 +1256,7 @@ ZipFSFindTOC(
const unsigned char *p, *q;
const unsigned char *start = zf->data;
const unsigned char *end = zf->data + zf->length;
int comlen;
/*
* Scan backwards from the end of the file for the signature. This is
@@ -1233,6 +1305,28 @@ ZipFSFindTOC(
goto error;
}
/*
* Is there a comment?
*/
comlen = ZipReadShort(start, end, p + ZIP_CENTRAL_COMMENTLEN_OFFS);
if (comlen) {
Tcl_DString ds;
const char *c;
if (p + ZIP_CENTRAL_END_LEN + comlen > end) {
ZIPFS_ERROR(interp, "bad zip comment");
ZIPFS_ERROR_CODE(interp, "BAD_COMMENT");
goto error;
}
Tcl_DStringInit(&ds);
c = DecodeZipEntryText(p + ZIP_CENTRAL_END_LEN, comlen, &ds);
comlen = Tcl_DStringLength(&ds) + 1;
zf->comment = ckalloc(comlen);
memcpy(zf->comment, c, comlen);
Tcl_DStringFree(&ds);
}
/*
* Where does the central directory start?
*/
@@ -1258,7 +1352,7 @@ ZipFSFindTOC(
zf->directoryOffset = p - zf->data;
q = p;
for (i = 0; i < zf->numFiles; i++) {
int pathlen, comlen, extra;
int pathlen, extra;
if (q + ZIP_CENTRAL_HEADER_LEN > end) {
ZIPFS_ERROR(interp, "wrong header length");
@@ -1345,6 +1439,7 @@ ZipFSOpenArchive(
zf->numFiles = 0;
zf->baseOffset = zf->passOffset = 0;
zf->ptrToFree = NULL;
zf->comment = NULL;
zf->passBuf[0] = 0;
/*
@@ -1432,34 +1527,48 @@ ZipMapArchive(
ZipFile *zf, /* The archive descriptor structure. */
void *handle) /* The OS handle to the open archive. */
{
#ifdef _WIN32
HANDLE hFile = (HANDLE) handle;
int readSuccessful;
/*
* Determine the file size.
*/
#ifdef _WIN32
HANDLE hFile = (HANDLE) handle;
# ifdef _WIN64
readSuccessful = GetFileSizeEx(hFile, (PLARGE_INTEGER) &zf->length) != 0;
# else /* !_WIN64 */
zf->length = GetFileSize(hFile, 0);
readSuccessful = (zf->length != (size_t) INVALID_FILE_SIZE);
# endif /* _WIN64 */
if (!readSuccessful || (zf->length < ZIP_CENTRAL_END_LEN)) {
#else /* !_WIN32 */
int fd = PTR2INT(handle);
struct stat st;
readSuccessful = (fstat(fd, &st) == 0);
zf->length = st.st_size;
#endif /* _WIN32 */
if (!readSuccessful) {
ZIPFS_POSIX_ERROR(interp, "invalid file size");
return TCL_ERROR;
}
if (zf->length < ZIP_CENTRAL_END_LEN) {
ZIPFS_ERROR(interp, "illegal file size");
ZIPFS_ERROR_CODE(interp, "FILE_SIZE");
return TCL_ERROR;
}
/*
* Map the file.
*/
#ifdef _WIN32
zf->mountHandle = CreateFileMappingW(hFile, 0, PAGE_READONLY, 0,
zf->length, 0);
if (zf->mountHandle == INVALID_HANDLE_VALUE) {
ZIPFS_POSIX_ERROR(interp, "file mapping failed");
return TCL_ERROR;
goto badMap;
}
zf->data = (unsigned char *)
MapViewOfFile(zf->mountHandle, FILE_MAP_READ, 0, 0, zf->length);
@@ -1468,19 +1577,6 @@ ZipMapArchive(
return TCL_ERROR;
}
#else /* !_WIN32 */
int fd = PTR2INT(handle);
/*
* Determine the file size.
*/
zf->length = lseek(fd, 0, SEEK_END);
if (zf->length == ERROR_LENGTH || zf->length < ZIP_CENTRAL_END_LEN) {
ZIPFS_POSIX_ERROR(interp, "invalid file size");
return TCL_ERROR;
}
lseek(fd, 0, SEEK_SET);
zf->data = (unsigned char *)
mmap(0, zf->length, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
if (zf->data == MAP_FAILED) {
@@ -1551,7 +1647,7 @@ ZipFSCatalogFilesystem(
ZipFile *zf;
ZipEntry *z;
Tcl_HashEntry *hPtr;
Tcl_DString ds, dsm, fpBuf;
Tcl_DString ds, dsm, dsc, fpBuf;
unsigned char *q;
/*
@@ -1616,6 +1712,7 @@ ZipFSCatalogFilesystem(
*/
*zf = *zf0;
zf0->comment = NULL; /* Ownership transferred to zf */
zf->mountPoint = (char *) Tcl_GetHashKey(&ZipFS.zipHash, hPtr);
Tcl_CreateExitHandler(ZipfsExitHandler, zf);
zf->mountPointLen = strlen(zf->mountPoint);
@@ -1659,7 +1756,7 @@ ZipFSCatalogFilesystem(
int extra, isdir = 0, dosTime, dosDate, nbcompr;
size_t offs, pathlen, comlen;
unsigned char *lq, *gq = NULL;
char *fullpath, *path;
char *fullpath, *path, *comment = NULL;
pathlen = ZipReadShort(start, end, q + ZIP_CENTRAL_PATHLEN_OFFS);
comlen = ZipReadShort(start, end, q + ZIP_CENTRAL_FCOMMENTLEN_OFFS);
@@ -1673,6 +1770,10 @@ ZipFSCatalogFilesystem(
if ((strcmp(path, ".") == 0) || (strcmp(path, "..") == 0)) {
goto nextent;
}
if (comlen) {
comment = DecodeZipEntryText(
q + ZIP_CENTRAL_HEADER_LEN + pathlen, comlen, &dsc);
}
lq = zf->data + zf->baseOffset
+ ZipReadInt(start, end, q + ZIP_CENTRAL_LOCALHDR_OFFS);
if ((lq < start) || (lq + ZIP_LOCAL_HEADER_LEN > end)) {
@@ -1731,6 +1832,12 @@ ZipFSCatalogFilesystem(
z = AllocateZipEntry();
z->depth = CountSlashes(fullpath);
z->zipFilePtr = zf;
if (comment) {
int clen = strlen(comment) + 1;
z->comment = ckalloc(clen);
memcpy(z->comment, comment, clen);
Tcl_DStringFree(&dsc);
}
z->isDirectory = isdir;
z->isEncrypted =
(ZipReadShort(start, end, lq + ZIP_LOCAL_FLAGS_OFFS) & 1)
@@ -2179,6 +2286,9 @@ TclZipfs_Unmount(
if (hPtr) {
Tcl_DeleteHashEntry(hPtr);
}
if (z->comment) {
ckfree(z->comment);
}
if (z->data) {
ckfree(z->data);
}
@@ -2359,8 +2469,10 @@ ZipFSUnmountObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *zipObj;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "zipfile");
Tcl_WrongNumArgs(interp, 1, objv, "mountpoint");
return TCL_ERROR;
}
return TclZipfs_Unmount(interp, Tcl_GetString(objv[1]));
@@ -3063,7 +3175,7 @@ ZipFSMkZipOrImg(
int isMounted = 0;
const char *imgName;
// TODO: normalize the origin file name
/* TODO: normalize the origin file name */
imgName = (originFile != NULL) ? Tcl_GetString(originFile) :
Tcl_GetNameOfExecutable();
if (pwlen) {
@@ -3967,6 +4079,71 @@ ZipFSTclLibraryObjCmd(
return TCL_OK;
}
/*
*-------------------------------------------------------------------------
*
* ZipFSCommentObjCmd --
*
* This procedure is invoked to process the [zipfs comment] command. It
* returns the ZIP-level comment of a mounted ZIP, if there is one.
* Errors on no such mount. Does nothing in a safe interp.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
#if EXPOSE_ZIP_COMMENTS
static int
ZipFSCommentObjCmd(
TCL_UNUSED(ClientData),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result = TCL_OK;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "mountPoint");
return TCL_ERROR;
}
if (!Tcl_IsSafe(interp)) {
Tcl_DString ds;
Tcl_Obj *mountPoint;
ZipFile *zf;
mountPoint = Tcl_FSGetNormalizedPath(interp, objv[1]);
if (!mountPoint) {
return TCL_ERROR;
}
Tcl_DStringInit(&ds);
ReadLock();
if (!ZipFS.initialized) {
goto noMount;
}
zf = ZipFSLookupZip(Tcl_GetString(mountPoint));
if (!zf) {
noMount:
ZIPFS_ERROR(interp, "no such mounted zip");
ZIPFS_ERROR_CODE(interp, "NO_ZIP");
result = TCL_ERROR;
goto done;
}
if (zf->comment) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(zf->comment, -1));
}
done:
Unlock();
Tcl_DStringFree(&ds);
}
return result;
}
#endif /* EXPOSE_ZIP_COMMENTS */
/*
*-------------------------------------------------------------------------
*
@@ -5321,7 +5498,8 @@ enum ZipFileAttrs {
ZIP_ATTR_MOUNT,
ZIP_ATTR_ARCHIVE,
ZIP_ATTR_PERMISSIONS,
ZIP_ATTR_CRC
ZIP_ATTR_CRC,
ZIP_ATTR_COMMENT
};
static const char *const *
@@ -5341,6 +5519,9 @@ ZipFSFileAttrStringsProc(
"-archive",
"-permissions",
"-crc",
#if EXPOSE_ZIP_COMMENTS
"-comment",
#endif /* EXPOSE_ZIP_COMMENTS */
NULL,
};
@@ -5414,6 +5595,9 @@ ZipFSFileAttrsGetProc(
case ZIP_ATTR_CRC:
TclNewIntObj(*objPtrRef, z->crc32);
break;
case ZIP_ATTR_COMMENT:
*objPtrRef = Tcl_NewStringObj(z->zipFilePtr->comment, -1);
break;
default:
ZIPFS_ERROR(interp, "unknown attribute");
ZIPFS_ERROR_CODE(interp, "FILE_ATTR");
@@ -5627,6 +5811,9 @@ TclZipfs_Init(
{"mount_data", ZipFSMountBufferObjCmd, NULL, NULL, NULL, 1},
{"unmount", ZipFSUnmountObjCmd, NULL, NULL, NULL, 1},
{"mkkey", ZipFSMkKeyObjCmd, NULL, NULL, NULL, 1},
#if EXPOSE_ZIP_COMMENTS
{"comment", ZipFSCommentObjCmd, NULL, NULL, NULL, 1},
#endif /* EXPOSE_ZIP_COMMENTS */
{"exists", ZipFSExistsObjCmd, NULL, NULL, NULL, 0},
{"info", ZipFSInfoObjCmd, NULL, NULL, NULL, 0},
{"list", ZipFSListObjCmd, NULL, NULL, NULL, 0},
+7 -5
View File
@@ -140,11 +140,13 @@ typedef struct {
* STREAM_DONE - Flag to signal stream end up to transform input.
*/
#define ASYNC 0x01
#define IN_HEADER 0x02
#define OUT_HEADER 0x04
#define STREAM_DECOMPRESS 0x08
#define STREAM_DONE 0x10
enum {
ASYNC = 0x01,
IN_HEADER = 0x02,
OUT_HEADER = 0x04,
STREAM_DECOMPRESS = 0x08,
STREAM_DONE = 0x10
};
/*
* Size of buffers allocated by default, and the range it can be set to. The
+11 -8
View File
@@ -32,9 +32,12 @@ extern int copyfile(const char *from, const char *to,
#else /* HAVE_COPYFILE_H */
int copyfile(const char *from, const char *to,
void *state, uint32_t flags);
#define COPYFILE_ACL (1<<0)
#define COPYFILE_XATTR (1<<2)
#define COPYFILE_NOFOLLOW_SRC (1<<18)
enum {
COPYFILE_ACL = (1<<0),
COPYFILE_XATTR = (1<<2),
COPYFILE_NOFOLLOW_SRC = (1<<18)
};
#if defined(HAVE_WEAK_IMPORT) && (MAC_OS_X_VERSION_MIN_REQUIRED < 1040)
/* Support for weakly importing copyfile. */
#define WEAK_IMPORT_COPYFILE
@@ -84,11 +87,11 @@ static int SetOSTypeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void UpdateStringOfOSType(Tcl_Obj *objPtr);
static const Tcl_ObjType tclOSTypeType = {
"osType", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfOSType, /* updateStringProc */
SetOSTypeFromAny /* setFromAnyProc */
"osType", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfOSType, /* updateStringProc */
SetOSTypeFromAny /* setFromAnyProc */
};
enum {
+39 -3
View File
@@ -96,7 +96,7 @@ test zipfs-1.3 {zipfs errors} -constraints zipfs -returnCodes error -body {
} -result {wrong # args: should be "zipfs mount ?mountpoint? ?zipfile? ?password?"}
test zipfs-1.4 {zipfs errors} -constraints zipfs -returnCodes error -body {
zipfs unmount a b c d e f
} -result {wrong # args: should be "zipfs unmount zipfile"}
} -result {wrong # args: should be "zipfs unmount mountpoint"}
test zipfs-1.5 {zipfs errors} -constraints zipfs -returnCodes error -body {
zipfs mkkey a b c d e f
} -result {wrong # args: should be "zipfs mkkey password"}
@@ -380,6 +380,36 @@ test zipfs-4.5 {zipfs lmkimg: making image from mounted} -constraints zipfs -set
removeFile $targetImage
removeFile $addFile
} -result {//zipfs://ziptest/test/add.tcl //zipfs://ziptest/test/ok.tcl}
if 0 {
test zipfs-4.6 {zipfs lmkimg: making image with comment} -constraints zipfs -setup {
set baseImage [makeFile "return sourceWorking\n\x1A" base_image.tcl]
set targetImage [makeFile "" target_image.tcl]
set addFile [makeFile "return mountWorking" add.data]
file delete $midImage $targetImage
proc addComment {zipfile commentData} {
set len [binary format s [string length $commentData]]
set f [open $zipfile r+b]
try {
chan seek $f -2 end
puts -nonewline $f $len$commentData
} finally {
close $f
}
}
} -body {
zipfs lmkimg $targetImage [list $addFile test/ok.tcl] {} $baseImage
addComment $targetImage "gorp"
zipfs mount ziptest $targetImage
list [glob -directory //zipfs://ziptest/test *.tcl] \
[zipfs comment //zipfs://ziptest/]
} -cleanup {
zipfs unmount ziptest
removeFile $baseImage
removeFile $midImage
removeFile $targetImage
removeFile $addFile
} -result {//zipfs://ziptest/test/ok.tcl gorp}
}
test zipfs-5.1 {zipfs mount_data: short data} -constraints zipfs -body {
zipfs mount_data gorp {}
@@ -390,10 +420,16 @@ test zipfs-5.2 {zipfs mount_data: short data} -constraints zipfs -body {
test zipfs-5.3 {zipfs mount_data: short data} -constraints zipfs -body {
set data PK\x03\x04.....................................
append data PK\x01\x02.....................................
append data PK\x05\x06.....................................
append data PK\x05\x06................\x01\x00...................
zipfs mount_data gorp $data
} -returnCodes error -result {bad zip data}
test zipfs-5.4 {zipfs mount_data: bad arg count} -constraints zipfs -body {
test zipfs-5.4 {zipfs mount_data: short data} -constraints zipfs -body {
set data PK\x03\x04.....................................
append data PK\x01\x02.....................................
append data PK\x05\x06................\x00\x01...................
zipfs mount_data gorp $data
} -returnCodes error -result {bad zip comment}
test zipfs-5.5 {zipfs mount_data: bad arg count} -constraints zipfs -body {
zipfs mount_data gorp {} foobar
} -returnCodes error -result {wrong # args: should be "zipfs mount_data ?mountpoint? ?data?"}
+9 -9
View File
@@ -173,17 +173,17 @@ static pthread_cond_t notifierCV = PTHREAD_COND_INITIALIZER;
/*
* The pollState bits:
*
* POLL_WANT is set by each thread before it waits on its condition variable.
* It is checked by the notifier before it does select.
*
* POLL_DONE is set by the notifier if it goes into select after seeing
* POLL_WANT. The idea is to ensure it tries a select with the same bits
* the initial thread had set.
*/
#define POLL_WANT 0x1
#define POLL_DONE 0x2
enum {
POLL_WANT = 0x1, /* Set by each thread before it waits on its
* condition variable. It is checked by the
* notifier before it does select. */
POLL_DONE = 0x2 /* Set by the notifier if it goes into select
* after seeing POLL_WANT. The idea is to
* ensure it tries a select with the same bits
* the initial thread had set. */
};
/*
* This is the thread ID of the notifier thread that does select.
+5 -3
View File
@@ -57,9 +57,11 @@
* TraverseUnixTree() calls the traverseProc()
*/
#define DOTREE_PRED 1 /* pre-order directory */
#define DOTREE_POSTD 2 /* post-order directory */
#define DOTREE_F 3 /* regular file */
enum {
DOTREE_PRED = 1, /* pre-order directory */
DOTREE_POSTD = 2, /* post-order directory */
DOTREE_F = 3, /* regular file */
};
/*
* Fallback temporary file location the temporary file generation code. Can be
+14 -11
View File
@@ -66,7 +66,7 @@ struct TcpState {
Tcl_TcpAcceptProc *acceptProc;
/* Proc to call on accept. */
void *acceptProcData; /* The data for the accept proc. */
void *acceptProcData; /* The data for the accept proc. */
/*
* Only needed for client sockets
@@ -87,22 +87,25 @@ struct TcpState {
* structure.
*/
#define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */
#define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */
#define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to
* process an async connect. This
* flag indicates that reentry is
* still pending */
#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
enum {
TCP_NONBLOCKING = (1<<0), /* Socket with non-blocking I/O */
TCP_ASYNC_CONNECT = (1<<1), /* Async connect in progress. */
TCP_ASYNC_PENDING = (1<<4), /* TcpConnect was called to process an async
* connect. This flag indicates that reentry
* is still pending */
TCP_ASYNC_FAILED = (1<<5) /* An async connect finally failed */
};
/*
* These bits may be ORed together into the "testFlags" field of a TcpState
* structure.
*/
#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not
* automatically continue connection
* process. */
enum {
TCP_ASYNC_TEST_MODE = (1<<0)/* Async testing activated. Do not
* automatically continue connection
* process. */
};
/*
* The following defines the maximum length of the listen queue. This is the
+9 -5
View File
@@ -17,12 +17,16 @@
* State flags used in the info structures below.
*/
#define FILE_PENDING (1<<0) /* Message is pending in the queue. */
#define FILE_ASYNC (1<<1) /* Channel is non-blocking. */
#define FILE_APPEND (1<<2) /* File is in append mode. */
enum {
FILE_PENDING = (1<<0), /* Message is pending in the queue. */
FILE_ASYNC = (1<<1), /* Channel is non-blocking. */
FILE_APPEND = (1<<2) /* File is in append mode. */
};
#define FILE_TYPE_SERIAL (FILE_TYPE_PIPE+1)
#define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)
enum {
FILE_TYPE_SERIAL = (FILE_TYPE_PIPE + 1),
FILE_TYPE_CONSOLE = (FILE_TYPE_PIPE + 2)
};
/*
* The following structure contains per-instance data for a file based
+20 -13
View File
@@ -31,18 +31,22 @@ TCL_DECLARE_MUTEX(consoleMutex)
* Bit masks used in the flags field of the ConsoleInfo structure below.
*/
#define CONSOLE_PENDING (1<<0) /* Message is pending in the queue. */
#define CONSOLE_ASYNC (1<<1) /* Channel is non-blocking. */
#define CONSOLE_READ_OPS (1<<4) /* Channel supports read-related ops. */
#define CONSOLE_RESET (1<<5) /* Console mode needs to be reset. */
enum {
CONSOLE_PENDING = (1<<0), /* Message is pending in the queue. */
CONSOLE_ASYNC = (1<<1), /* Channel is non-blocking. */
CONSOLE_READ_OPS = (1<<4), /* Channel supports read-related ops. */
CONSOLE_RESET = (1<<5) /* Console mode needs to be reset. */
};
/*
* Bit masks used in the sharedFlags field of the ConsoleInfo structure below.
*/
#define CONSOLE_EOF (1<<2) /* Console has reached EOF. */
#define CONSOLE_BUFFERED (1<<3) /* Data was read into a buffer by the reader
* thread. */
enum {
CONSOLE_EOF = (1<<2), /* Console has reached EOF. */
CONSOLE_BUFFERED = (1<<3) /* Data was read into a buffer by the reader
* thread. */
};
#define CONSOLE_BUFFER_SIZE (8*1024)
@@ -229,9 +233,10 @@ ReadConsoleBytes(
* will run and take whatever action it deems appropriate.
*/
do {
result = ReadConsoleW(hConsole, lpBuffer, nbytes / sizeof(WCHAR), &ntchars,
NULL);
} while (result && ntchars == 0 && GetLastError() == ERROR_OPERATION_ABORTED);
result = ReadConsoleW(hConsole, lpBuffer, nbytes / sizeof(WCHAR),
&ntchars, NULL);
} while (result && ntchars == 0 &&
GetLastError() == ERROR_OPERATION_ABORTED);
if (nbytesread != NULL) {
*nbytesread = ntchars * sizeof(WCHAR);
}
@@ -755,8 +760,9 @@ ConsoleOutputProc(
*errorCode = 0;
/* avoid blocking if pipe-thread exited */
timeout = (infoPtr->flags & CONSOLE_ASYNC) || !TclPipeThreadIsAlive(&threadInfo->TI)
|| TclInExit() || TclInThreadExit() ? 0 : INFINITE;
timeout = (infoPtr->flags & CONSOLE_ASYNC) ||
!TclPipeThreadIsAlive(&threadInfo->TI) || TclInExit() ||
TclInThreadExit() ? 0 : INFINITE;
if (WaitForSingleObject(threadInfo->readyEvent, timeout) == WAIT_TIMEOUT) {
/*
* The writer thread is blocked waiting for a write to complete and
@@ -1037,7 +1043,8 @@ WaitForRead(
/* avoid blocking if pipe-thread exited */
timeout = (!blocking || !TclPipeThreadIsAlive(&threadInfo->TI)
|| TclInExit() || TclInThreadExit()) ? 0 : INFINITE;
if (WaitForSingleObject(threadInfo->readyEvent, timeout) == WAIT_TIMEOUT) {
if (WaitForSingleObject(threadInfo->readyEvent,
timeout) == WAIT_TIMEOUT) {
/*
* The reader thread is blocked waiting for data and the channel
* is in non-blocking mode.
+27 -13
View File
@@ -84,9 +84,11 @@ static int ddeIsServer = 0;
#define TCL_DDE_SERVICE_NAME L"TclEval"
#define TCL_DDE_EXECUTE_RESULT L"$TCLEVAL$EXECUTE$RESULT"
#define DDE_FLAG_ASYNC 1
#define DDE_FLAG_BINARY 2
#define DDE_FLAG_FORCE 4
enum {
DDE_FLAG_ASYNC = 1,
DDE_FLAG_BINARY = 2,
DDE_FLAG_FORCE = 4
};
TCL_DECLARE_MUTEX(ddeMutex)
@@ -390,10 +392,13 @@ DdeSetServerName(
lastSuffix = suffix;
if (suffix > 1) {
if (suffix == 2) {
Tcl_DStringAppend(&dString, (char *)name, wcslen(name) * sizeof(WCHAR));
Tcl_DStringAppend(&dString, (char *)L" #", 2 * sizeof(WCHAR));
Tcl_DStringAppend(&dString, (char *)name,
wcslen(name) * sizeof(WCHAR));
Tcl_DStringAppend(&dString, (char *)L" #",
2 * sizeof(WCHAR));
offset = Tcl_DStringLength(&dString);
Tcl_DStringSetLength(&dString, offset + sizeof(WCHAR) * TCL_INTEGER_SPACE);
Tcl_DStringSetLength(&dString,
offset + sizeof(WCHAR) * TCL_INTEGER_SPACE);
actualName = (WCHAR *) Tcl_DStringValue(&dString);
}
_snwprintf((WCHAR *) (Tcl_DStringValue(&dString) + offset),
@@ -1147,12 +1152,14 @@ DdeServicesOnAck(
GlobalGetAtomNameW(service, sz, 255);
Tcl_DStringInit(&dString);
Tcl_WCharToUtfDString(sz, wcslen(sz), &dString);
Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
Tcl_ListObjAppendElement(NULL, matchPtr,
Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
Tcl_DStringFree(&dString);
GlobalGetAtomNameW(topic, sz, 255);
Tcl_DStringInit(&dString);
Tcl_WCharToUtfDString(sz, wcslen(sz), &dString);
Tcl_ListObjAppendElement(NULL, matchPtr, Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
Tcl_ListObjAppendElement(NULL, matchPtr,
Tcl_NewStringObj(Tcl_DStringValue(&dString), -1));
Tcl_DStringFree(&dString);
/*
@@ -1578,15 +1585,19 @@ DdeObjCmd(
}
ddeData = DdeCreateDataHandle(ddeInstance, (BYTE *) dataString,
(DWORD) dataLength, 0, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, 0);
(DWORD) dataLength, 0, 0,
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, 0);
if (ddeData != NULL) {
if (flags & DDE_FLAG_ASYNC) {
DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, hConv, 0,
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT,
XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult);
DdeAbandonTransaction(ddeInstance, hConv, ddeResult);
} else {
ddeReturn = DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF,
hConv, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, 30000, NULL);
hConv, 0,
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT,
XTYP_EXECUTE, 30000, NULL);
if (ddeReturn == 0) {
SetDdeError(interp);
result = TCL_ERROR;
@@ -1630,7 +1641,8 @@ DdeObjCmd(
CP_WINUNICODE);
if (ddeItem != NULL) {
ddeData = DdeClientTransaction(NULL, 0, hConv, ddeItem,
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_REQUEST, 5000, NULL);
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT,
XTYP_REQUEST, 5000, NULL);
if (ddeData == NULL) {
SetDdeError(interp);
result = TCL_ERROR;
@@ -1710,7 +1722,9 @@ DdeObjCmd(
CP_WINUNICODE);
if (ddeItem != NULL) {
ddeData = DdeClientTransaction(dataString, (DWORD) length,
hConv, ddeItem, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_POKE, 5000, NULL);
hConv, ddeItem,
(flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT,
XTYP_POKE, 5000, NULL);
if (ddeData == NULL) {
SetDdeError(interp);
result = TCL_ERROR;
+6 -4
View File
@@ -17,10 +17,12 @@
* TraverseWinTree() calls the traverseProc()
*/
#define DOTREE_PRED 1 /* pre-order directory */
#define DOTREE_POSTD 2 /* post-order directory */
#define DOTREE_F 3 /* regular file */
#define DOTREE_LINK 4 /* symbolic link */
enum {
DOTREE_PRED = 1, /* pre-order directory */
DOTREE_POSTD = 2, /* post-order directory */
DOTREE_F = 3, /* regular file */
DOTREE_LINK = 4, /* symbolic link */
};
/*
* Callbacks for file attributes code.
+14 -8
View File
@@ -32,10 +32,12 @@ TCL_DECLARE_MUTEX(pipeMutex)
* under windows. There is special case code for the various types.
*/
#define APPL_NONE 0
#define APPL_DOS 1
#define APPL_WIN3X 2
#define APPL_WIN32 3
enum {
APPL_NONE = 0,
APPL_DOS = 1,
APPL_WIN3X = 2,
APPL_WIN32 = 3
};
/*
* The following constants and structures are used to encapsulate the state of
@@ -71,15 +73,19 @@ static ProcInfo *procList;
* Bit masks used in the flags field of the PipeInfo structure below.
*/
#define PIPE_PENDING (1<<0) /* Message is pending in the queue. */
#define PIPE_ASYNC (1<<1) /* Channel is non-blocking. */
enum {
PIPE_PENDING = (1<<0), /* Message is pending in the queue. */
PIPE_ASYNC = (1<<1) /* Channel is non-blocking. */
};
/*
* Bit masks used in the sharedFlags field of the PipeInfo structure below.
*/
#define PIPE_EOF (1<<2) /* Pipe has reached EOF. */
#define PIPE_EXTRABYTE (1<<3) /* The reader thread has consumed one byte. */
enum {
PIPE_EOF = (1<<2), /* Pipe has reached EOF. */
PIPE_EXTRABYTE = (1<<3) /* The reader thread has consumed one byte. */
};
/*
* TODO: It appears the whole EXTRABYTE machinery is in place to support
+14 -7
View File
@@ -33,24 +33,31 @@ TCL_DECLARE_MUTEX(serialMutex)
* Bit masks used in the flags field of the SerialInfo structure below.
*/
#define SERIAL_PENDING (1<<0) /* Message is pending in the queue. */
#define SERIAL_ASYNC (1<<1) /* Channel is non-blocking. */
enum {
SERIAL_PENDING = (1<<0), /* Message is pending in the queue. */
SERIAL_ASYNC = (1<<1) /* Channel is non-blocking. */
};
/*
* Bit masks used in the sharedFlags field of the SerialInfo structure below.
*/
#define SERIAL_EOF (1<<2) /* Serial has reached EOF. */
#define SERIAL_ERROR (1<<4)
enum {
SERIAL_EOF = (1<<2), /* Serial has reached EOF. */
SERIAL_ERROR = (1<<4)
};
/*
* Bit masks used for noting whether to drain or discard output on close. They
* are disjoint from each other; at most one may be set at a time.
*/
#define SERIAL_CLOSE_DRAIN (1<<6) /* Drain all output on close. */
#define SERIAL_CLOSE_DISCARD (1<<7) /* Discard all output on close. */
#define SERIAL_CLOSE_MASK (3<<6) /* Both two bits above. */
enum {
SERIAL_CLOSE_DRAIN = (1<<6),/* Drain all output on close. */
SERIAL_CLOSE_DISCARD = (1<<7),
/* Discard all output on close. */
SERIAL_CLOSE_MASK = (3<<6) /* Both two bits above. */
};
/*
* Default time to block between checking status on the serial port.
+15 -14
View File
@@ -174,26 +174,27 @@ struct TcpState {
* structure.
*/
#define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */
#define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */
#define SOCKET_EOF (1<<2) /* A zero read happened on the
* socket. */
#define SOCKET_PENDING (1<<3) /* A message has been sent for this
* socket */
#define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to
* process an async connect. This
* flag indicates that reentry is
* still pending */
#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
enum {
TCP_NONBLOCKING = (1<<0), /* Socket with non-blocking I/O */
TCP_ASYNC_CONNECT = (1<<1), /* Async connect in progress. */
SOCKET_EOF = (1<<2), /* A zero read happened on the socket. */
SOCKET_PENDING = (1<<3), /* A message has been sent for this socket */
TCP_ASYNC_PENDING = (1<<4), /* TcpConnect was called to process an async
* connect. This flag indicates that reentry
* is still pending */
TCP_ASYNC_FAILED = (1<<5) /* An async connect finally failed */
};
/*
* These bits may be ORed together into the "testFlags" field of a TcpState
* structure.
*/
#define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not
* automatically continue connection
* process */
enum {
TCP_ASYNC_TEST_MODE = (1<<0)/* Async testing activated. Do not
* automatically continue connection
* process */
};
/*
* The following structure is what is added to the Tcl event queue when a
+12 -12
View File
@@ -79,10 +79,10 @@ static CRITICAL_SECTION joinLock;
#if TCL_THREADS
typedef struct ThreadSpecificData {
HANDLE condEvent; /* Per-thread condition event */
HANDLE condEvent; /* Per-thread condition event */
struct ThreadSpecificData *nextPtr; /* Queue pointers */
struct ThreadSpecificData *prevPtr;
int flags; /* See flags below */
int flags; /* See flags below */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -90,15 +90,14 @@ static Tcl_ThreadDataKey dataKey;
/*
* State bits for the thread.
* WIN_THREAD_UNINIT Uninitialized. Must be zero because of the way
* ThreadSpecificData is created.
* WIN_THREAD_RUNNING Running, not waiting.
* WIN_THREAD_BLOCKED Waiting, or trying to wait.
*/
#define WIN_THREAD_UNINIT 0x0
#define WIN_THREAD_RUNNING 0x1
#define WIN_THREAD_BLOCKED 0x2
enum {
WIN_THREAD_UNINIT = 0x0, /* Uninitialized. Must be zero because of the
* way ThreadSpecificData is created. */
WIN_THREAD_RUNNING = 0x1, /* Running, not waiting. */
WIN_THREAD_BLOCKED = 0x2 /* Waiting, or trying to wait. */
};
/*
* The per condition queue pointers and the Mutex used to serialize access to
@@ -108,8 +107,8 @@ static Tcl_ThreadDataKey dataKey;
typedef struct {
CRITICAL_SECTION condLock; /* Lock to serialize queuing on the
* condition. */
struct ThreadSpecificData *firstPtr; /* Queue pointers */
struct ThreadSpecificData *lastPtr;
ThreadSpecificData *firstPtr; /* Queue pointers */
ThreadSpecificData *lastPtr;
} WinCondition;
/*
@@ -131,7 +130,8 @@ typedef struct {
*/
typedef struct {
LPTHREAD_START_ROUTINE lpStartAddress; /* Original startup routine */
LPTHREAD_START_ROUTINE lpStartAddress;
/* Original startup routine */
LPVOID lpParameter; /* Original startup data */
unsigned int fpControl; /* Floating point control word from the
* main thread */