1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
|
*** ./tcl.decls.orig Sat Apr 10 17:50:50 1999
--- ./tcl.decls Mon Apr 19 19:58:16 1999
***************
*** 967,977 ****
void Tcl_InitMemory(Tcl_Interp *interp)
}
# Reserved for future use (8.0.x vs. 8.1)
- # declare 281 generic {
- # }
- # declare 282 generic {
- # }
# declare 283 generic {
# }
# declare 284 generic {
--- 967,996 ----
void Tcl_InitMemory(Tcl_Interp *interp)
}
+ # Andreas Kupries <andreas_kupries@users.sourceforge.net>, 03/21/1999
+ # "Trf-Patch for filtering channels"
+ #
+ # C-Level API for (un)stacking of channels. This allows the introduction
+ # of filtering channels with relatively little changes to the core.
+ # This patch was created in cooperation with Jan Nijtmans <nijtmans@wxs.nl>
+ # and is therefore part of his plus-patches too.
+ #
+ # It would have been possible to place the following definitions according
+ # to the alphabetical order used elsewhere in this file, but I decided
+ # against that to ease the maintenance of the patch across new tcl versions
+ # (patch usually has no problems to integrate the patch file for the last
+ # version into the new one).
+
+ declare 281 generic {
+ Tcl_Channel Tcl_ReplaceChannel(Tcl_Interp *interp, \
+ Tcl_ChannelType *typePtr, ClientData instanceData, \
+ int mask, Tcl_Channel prevChan)
+ }
+ declare 282 generic {
+ void Tcl_UndoReplaceChannel(Tcl_Interp *interp, Tcl_Channel chan)
+ }
+
# Reserved for future use (8.0.x vs. 8.1)
# declare 283 generic {
# }
# declare 284 generic {
*** ./tclDecls.h.orig Sat Apr 10 17:50:50 1999
--- ./tclDecls.h Mon Apr 19 19:58:16 1999
***************
*** 875,882 ****
int * patchLevel, int * type));
/* 280 */
EXTERN void Tcl_InitMemory _ANSI_ARGS_((Tcl_Interp * interp));
! /* Slot 281 is reserved */
! /* Slot 282 is reserved */
/* Slot 283 is reserved */
/* Slot 284 is reserved */
/* Slot 285 is reserved */
--- 875,888 ----
int * patchLevel, int * type));
/* 280 */
EXTERN void Tcl_InitMemory _ANSI_ARGS_((Tcl_Interp * interp));
! /* 281 */
! EXTERN Tcl_Channel Tcl_ReplaceChannel _ANSI_ARGS_((Tcl_Interp * interp,
! Tcl_ChannelType * typePtr,
! ClientData instanceData, int mask,
! Tcl_Channel prevChan));
! /* 282 */
! EXTERN void Tcl_UndoReplaceChannel _ANSI_ARGS_((
! Tcl_Interp * interp, Tcl_Channel chan));
/* Slot 283 is reserved */
/* Slot 284 is reserved */
/* Slot 285 is reserved */
***************
*** 1434,1441 ****
void (*tcl_PanicVA) _ANSI_ARGS_((char * format, va_list argList)); /* 278 */
void (*tcl_GetVersion) _ANSI_ARGS_((int * major, int * minor, int * patchLevel, int * type)); /* 279 */
void (*tcl_InitMemory) _ANSI_ARGS_((Tcl_Interp * interp)); /* 280 */
! void *reserved281;
! void *reserved282;
void *reserved283;
void *reserved284;
void *reserved285;
--- 1440,1447 ----
void (*tcl_PanicVA) _ANSI_ARGS_((char * format, va_list argList)); /* 278 */
void (*tcl_GetVersion) _ANSI_ARGS_((int * major, int * minor, int * patchLevel, int * type)); /* 279 */
void (*tcl_InitMemory) _ANSI_ARGS_((Tcl_Interp * interp)); /* 280 */
! Tcl_Channel (*tcl_ReplaceChannel) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_ChannelType * typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan)); /* 281 */
! void (*tcl_UndoReplaceChannel) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Channel chan)); /* 282 */
void *reserved283;
void *reserved284;
void *reserved285;
***************
*** 2657,2664 ****
#define Tcl_InitMemory \
(tclStubsPtr->tcl_InitMemory) /* 280 */
#endif
! /* Slot 281 is reserved */
! /* Slot 282 is reserved */
/* Slot 283 is reserved */
/* Slot 284 is reserved */
/* Slot 285 is reserved */
--- 2663,2676 ----
#define Tcl_InitMemory \
(tclStubsPtr->tcl_InitMemory) /* 280 */
#endif
! #ifndef Tcl_ReplaceChannel
! #define Tcl_ReplaceChannel \
! (tclStubsPtr->tcl_ReplaceChannel) /* 281 */
! #endif
! #ifndef Tcl_UndoReplaceChannel
! #define Tcl_UndoReplaceChannel \
! (tclStubsPtr->tcl_UndoReplaceChannel) /* 282 */
! #endif
/* Slot 283 is reserved */
/* Slot 284 is reserved */
/* Slot 285 is reserved */
*** ./tclIO.c.orig Sat Apr 10 17:50:52 1999
--- ./tclIO.c Mon Apr 19 19:58:16 1999
***************
*** 202,207 ****
--- 202,229 ----
int bufSize; /* What size buffers to allocate? */
Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */
CopyState *csPtr; /* State of background copy, or NULL. */
+
+ /* Andreas Kupries <andreas_kupries@users.sourceforge.net>, 12/13/1998
+ * "Trf-Patch for filtering channels"
+ *
+ * The single change to the internal datastructures of the core. Every
+ * channel now maintains a reference to the channel he is stacked upon.
+ * This reference is NULL for normal channels. Only the two exported
+ * procedures (Tcl_ReplaceChannel and Tcl_UndoReplaceChannel, see at the
+ * end of 'tcl.h') use this field in a non-trivial way.
+ *
+ * Of the existing procedures the only following are affected by this
+ * change:
+ *
+ * - Tcl_RegisterChannel
+ * - Tcl_CreateChannel
+ * - CloseChannel
+ *
+ * The why is explained at the changed locations.
+ */
+
+ struct Channel* supercedes; /* Refers to channel this one was stacked upon */
+
} Channel;
/*
***************
*** 1038,1044 ****
if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) {
return;
}
! panic("Tcl_RegisterChannel: duplicate channel names");
}
Tcl_SetHashValue(hPtr, (ClientData) chanPtr);
}
--- 1060,1080 ----
if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) {
return;
}
!
! /* Andreas Kupries <andreas_kupries@users.sourceforge.net>, 12/13/1998
! * "Trf-Patch for filtering channels"
! *
! * This is the change to 'Tcl_RegisterChannel'.
! *
! * Explanation:
! * The moment a channel is stacked upon another he
! * takes the identity of the channel he supercedes,
! * i.e. he gets the *same* name. Because of this we
! * cannot check for duplicate names anymore, they
! * have to be allowed now.
! */
!
! /* panic("Tcl_RegisterChannel: duplicate channel names"); */
}
Tcl_SetHashValue(hPtr, (ClientData) chanPtr);
}
***************
*** 1297,1302 ****
--- 1333,1352 ----
chanPtr->timer = NULL;
chanPtr->csPtr = NULL;
+ /* Andreas Kupries <andreas_kupries@users.sourceforge.net>, 12/13/1998
+ * "Trf-Patch for filtering channels"
+ *
+ * This is the change to 'Tcl_CreateChannel'.
+ *
+ * Explanation:
+ * It is of course necessary to initialize the new field
+ * in the Channel structure. The chosen value indicates
+ * that the created channel is a normal one, and not
+ * stacked upon another.
+ */
+
+ chanPtr->supercedes = (Channel*) NULL;
+
chanPtr->outputStage = NULL;
if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) {
chanPtr->outputStage = (char *)
***************
*** 1330,1335 ****
--- 1380,1622 ----
return (Tcl_Channel) chanPtr;
}
+ /* Andreas Kupries <andreas_kupries@users.sourceforge.net>, 12/13/1998
+ * "Trf-Patch for filtering channels"
+ *
+ * The following two procedures are the new, exported ones. They
+ * - create a channel stacked upon an existing one and
+ * - pop a stacked channel off, thus revealing the superceded one.
+ *
+ * Please read the following completely.
+ */
+
+ /*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ReplaceChannel --
+ *
+ * Replaces an entry in the hash table for a Tcl_Channel
+ * record. The replacement is a new channel with same name,
+ * it supercedes the replaced channel. Input and output of
+ * the superceded channel is now going through the newly
+ * created channel and allows the arbitrary filtering/manipulation
+ * of the dataflow.
+ *
+ * Results:
+ * Returns the new Tcl_Channel.
+ *
+ * Side effects:
+ * See above.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ Tcl_Channel
+ Tcl_ReplaceChannel(interp, typePtr, instanceData, mask, prevChan)
+ Tcl_Interp* interp; /* The interpreter we are working in */
+ Tcl_ChannelType *typePtr; /* The channel type record for the new
+ * channel. */
+ ClientData instanceData; /* Instance specific data for the new
+ * channel. */
+ int mask; /* TCL_READABLE & TCL_WRITABLE to indicate
+ * if the channel is readable, writable. */
+ Tcl_Channel prevChan; /* The channel structure to replace */
+ {
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ Channel *chanPtr, *pt, *prevPt;
+
+ /*
+ * Find the given channel in the list of all channels, compute enough
+ * information to allow easy removal after the conditions are met.
+ */
+
+ prevPt = (Channel*) NULL;
+ pt = (Channel*) tsdPtr->firstChanPtr;
+
+ while (pt != (Channel *) prevChan) {
+ prevPt = pt;
+ pt = pt->nextChanPtr;
+ }
+
+ /*
+ * 'pt == prevChan' now
+ */
+
+ if (!pt) {
+ return (Tcl_Channel) NULL;
+ }
+
+ /*
+ * Here we check if the given "mask" matches the "flags"
+ * of the already existing channel.
+ *
+ * | - | R | W | RW |
+ * --+---+---+---+----+ <=> 0 != (chan->mask & prevChan->mask)
+ * - | | | | |
+ * R | | + | | + | The superceding channel is allowed to
+ * W | | | + | + | restrict the capabilities of the
+ * RW| | + | + | + | superceded one !
+ * --+---+---+---+----+
+ */
+
+ if ((mask & Tcl_GetChannelMode (prevChan)) == 0) {
+ return (Tcl_Channel) NULL;
+ }
+
+
+ chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel));
+ chanPtr->flags = mask;
+
+ /*
+ * Set the channel up initially in no Input translation mode and
+ * no Output translation mode.
+ */
+
+ chanPtr->inputTranslation = TCL_TRANSLATE_LF;
+ chanPtr->outputTranslation = TCL_TRANSLATE_LF;
+ chanPtr->inEofChar = 0;
+ chanPtr->outEofChar = 0;
+
+ chanPtr->unreportedError = 0;
+ chanPtr->instanceData = instanceData;
+ chanPtr->typePtr = typePtr;
+ chanPtr->refCount = 0;
+ chanPtr->closeCbPtr = (CloseCallback *) NULL;
+ chanPtr->curOutPtr = (ChannelBuffer *) NULL;
+ chanPtr->outQueueHead = (ChannelBuffer *) NULL;
+ chanPtr->outQueueTail = (ChannelBuffer *) NULL;
+ chanPtr->saveInBufPtr = (ChannelBuffer *) NULL;
+ chanPtr->inQueueHead = (ChannelBuffer *) NULL;
+ chanPtr->inQueueTail = (ChannelBuffer *) NULL;
+ chanPtr->chPtr = (ChannelHandler *) NULL;
+ chanPtr->interestMask = 0;
+ chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL;
+ chanPtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE;
+ chanPtr->timer = NULL;
+ chanPtr->csPtr = NULL;
+
+ /* 06/12/1998: New for Tcl 8.1
+ *
+ * Take over the encoding from the superceded channel, so that it will be
+ * executed in the future despite the replacement, and at the proper time
+ * (*after* / *before* our transformation, depending on the direction of
+ * the dataflow).
+ *
+ * *Important*
+ * The I/O functionality of the filtering channel has to use 'Tcl_Read' to
+ * get at the underlying information. This will circumvent the de/encoder
+ * stage [*] in the superceded channel and removes the need to trouble
+ * ourselves with 'ByteArray's too.
+ *
+ * [*] I'm talking about the conversion between UNICODE and other
+ * representations, like ASCII.
+ */
+
+ chanPtr->encoding=Tcl_GetEncoding(interp,Tcl_GetEncodingName(pt->encoding));
+ chanPtr->inputEncodingState = pt->inputEncodingState;
+ chanPtr->inputEncodingFlags = pt->inputEncodingFlags;
+ chanPtr->outputEncodingState = pt->outputEncodingState;
+ chanPtr->outputEncodingFlags = pt->outputEncodingFlags;
+
+ chanPtr->outputStage = NULL;
+
+ if ((chanPtr->encoding != NULL) && (chanPtr->flags & TCL_WRITABLE)) {
+ chanPtr->outputStage = (char *)
+ ckalloc((unsigned) (chanPtr->bufSize + 2));
+ }
+
+ chanPtr->supercedes = (Channel*) prevChan;
+
+ chanPtr->channelName = (char *) ckalloc (strlen(pt->channelName)+1);
+ strcpy (chanPtr->channelName, pt->channelName);
+
+ if (prevPt) {
+ prevPt->nextChanPtr = chanPtr;
+ } else {
+ tsdPtr->firstChanPtr = chanPtr;
+ }
+
+ chanPtr->nextChanPtr = pt->nextChanPtr;
+
+ Tcl_RegisterChannel (interp, (Tcl_Channel) chanPtr);
+
+ /*
+ * The superceded channel is effectively unregistered
+ */
+
+ /*chanPtr->supercedes->refCount --;*/
+
+ return (Tcl_Channel) chanPtr;
+ }
+
+ /*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_UndoReplaceChannel --
+ *
+ * Unstacks an entry in the hash table for a Tcl_Channel
+ * record. This is the reverse to 'Tcl_ReplaceChannel'.
+ * The old, superceded channel is uncovered and re-registered
+ * in the appropriate datastructures.
+ *
+ * Results:
+ * Returns the old Tcl_Channel, i.e. the one which was stacked over.
+ *
+ * Side effects:
+ * See above.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ void
+ Tcl_UndoReplaceChannel (interp, chan)
+ Tcl_Interp* interp; /* The interpreter we are working in */
+ Tcl_Channel chan; /* The channel to unstack */
+ {
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ Channel* chanPtr = (Channel*) chan;
+
+ if (chanPtr->supercedes != (Channel*) NULL) {
+ Tcl_HashTable *hTblPtr; /* Hash table of channels. */
+ Tcl_HashEntry *hPtr; /* Search variable. */
+ int new; /* Is the hash entry new or does it exist? */
+
+ /*
+ * Insert the channel we were stacked upon back into
+ * the list of open channels. Place it back into the hashtable too.
+ * Correct 'refCount', as this actually unregisters 'chan'.
+ */
+
+ chanPtr->supercedes->nextChanPtr = tsdPtr->firstChanPtr;
+ tsdPtr->firstChanPtr = chanPtr->supercedes;
+
+ hTblPtr = GetChannelTable (interp);
+ hPtr = Tcl_CreateHashEntry (hTblPtr, chanPtr->channelName, &new);
+
+ Tcl_SetHashValue(hPtr, (ClientData) chanPtr->supercedes);
+ chanPtr->refCount --;
+
+ /*
+ * The superceded channel is effectively registered again
+ */
+
+ /*chanPtr->supercedes->refCount ++;*/
+ }
+
+ /*
+ * Disconnect the channels, then do a regular close upon the
+ * stacked one, the filtering channel. This may cause flushing
+ * of data into the superceded channel (if the filtering channel
+ * ('chan') remembered its parent in itself).
+ */
+
+ chanPtr->supercedes = NULL;
+
+ if (chanPtr->refCount == 0) {
+ Tcl_Close (interp, chan);
+ }
+ }
+
/*
*----------------------------------------------------------------------
*
***************
*** 2003,2008 ****
--- 2290,2330 ----
if (errorCode != 0) {
Tcl_SetErrno(errorCode);
}
+ }
+
+ /* Andreas Kupries <andreas_kupries@users.sourceforge.net>, 12/13/1998
+ * "Trf-Patch for filtering channels"
+ *
+ * This is the change to 'CloseChannel'.
+ *
+ * Explanation
+ * Closing a filtering channel closes the one it
+ * superceded too. This basically ripples through
+ * the whole chain of filters until it reaches
+ * the underlying normal channel.
+ *
+ * This is done by reintegrating the superceded
+ * channel into the (thread) global list of open
+ * channels and then invoking a regular close.
+ * There is no need to handle the complexities of
+ * this process by ourselves.
+ *
+ * *Note*
+ * This has to be done after the call to the
+ * 'closeProc' of the filtering channel to allow
+ * that one the flushing of internal buffers into
+ * the underlying channel.
+ */
+
+ if (chanPtr->supercedes != (Channel*) NULL) {
+ /* Insert the channel we were stacked upon back into
+ * the list of open channels, then do a regular close.
+ */
+
+ chanPtr->supercedes->nextChanPtr = tsdPtr->firstChanPtr;
+ tsdPtr->firstChanPtr = chanPtr->supercedes;
+ chanPtr->supercedes->refCount --; /* is deregistered */
+ Tcl_Close (interp, (Tcl_Channel) chanPtr->supercedes);
}
/*
*** ./tclStubInit.c.orig Sat Apr 10 17:50:52 1999
--- ./tclStubInit.c Mon Apr 19 19:58:16 1999
***************
*** 350,357 ****
Tcl_PanicVA, /* 278 */
Tcl_GetVersion, /* 279 */
Tcl_InitMemory, /* 280 */
! NULL, /* 281 */
! NULL, /* 282 */
NULL, /* 283 */
NULL, /* 284 */
NULL, /* 285 */
--- 350,357 ----
Tcl_PanicVA, /* 278 */
Tcl_GetVersion, /* 279 */
Tcl_InitMemory, /* 280 */
! Tcl_ReplaceChannel, /* 281 */
! Tcl_UndoReplaceChannel, /* 282 */
NULL, /* 283 */
NULL, /* 284 */
NULL, /* 285 */
*** ./tclStubs.c.orig Sat Apr 10 17:50:52 1999
--- ./tclStubs.c Mon Apr 19 19:58:16 1999
***************
*** 3263,3267 ****
--- 3263,3288 ----
(tclStubsPtr->tcl_ServiceModeHook)(mode);
}
+ /* Slot 345 */
+ Tcl_Channel
+ Tcl_ReplaceChannel(interp, typePtr, instanceData, mask, prevChan)
+ Tcl_Interp * interp;
+ Tcl_ChannelType * typePtr;
+ ClientData instanceData;
+ int mask;
+ Tcl_Channel prevChan;
+ {
+ return (tclStubsPtr->tcl_ReplaceChannel)(interp, typePtr, instanceData, mask, prevChan);
+ }
+
+ /* Slot 346 */
+ void
+ Tcl_UndoReplaceChannel(interp, chan)
+ Tcl_Interp * interp;
+ Tcl_Channel chan;
+ {
+ (tclStubsPtr->tcl_UndoReplaceChannel)(interp, chan);
+ }
+
/* !END!: Do not edit above this line. */
|