1 /*
2 * registry.c --
3 *
4 * Implements the C level procedures handling the registry
5 *
6 *
7 * Copyright (c) 1996-1999 Andreas Kupries (andreas_kupries@users.sourceforge.net)
8 * All rights reserved.
9 *
10 * Permission is hereby granted, without written agreement and without
11 * license or royalty fees, to use, copy, modify, and distribute this
12 * software and its documentation for any purpose, provided that the
13 * above copyright notice and the following two paragraphs appear in
14 * all copies of this software.
15 *
16 * IN NO EVENT SHALL I LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
17 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
18 * SOFTWARE AND ITS DOCUMENTATION, EVEN IF I HAVE BEEN ADVISED OF THE
19 * POSSIBILITY OF SUCH DAMAGE.
20 *
21 * I SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
24 * I HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
25 * ENHANCEMENTS, OR MODIFICATIONS.
26 *
27 * CVS: $Id: registry.c,v 1.58 2009/05/07 05:30:35 andreas_kupries Exp $
28 */
29
30 #include "transformInt.h"
31
32 /*
33 * Code used to associate the registry with an interpreter.
34 */
35
36 #define ASSOC "binTrf"
37
38 #ifdef TRF_DEBUG
39 int n = 0;
40 #endif
41
42 /*
43 * Possible values for 'flags' field in control structure.
44 */
45 #define CHANNEL_ASYNC (1<<0) /* non-blocking mode */
46
47 /*
48 * Number of milliseconds to wait before firing an event to flush
49 * out information waiting in buffers (fileevent support).
50 *
51 * Relevant for only Tcl 8.0 and beyond.
52 */
53
54 #define TRF_DELAY (5)
55
56 /*
57 * Structures used by an attached transformation procedure
58 *
59 * => Information stored for a single direction of the channel.
60 * => Information required by a result buffer.
61 * => Information stored for the complete channel.
62 */
63
64 typedef struct _DirectionInfo_ {
65 Trf_ControlBlock control; /* control block of transformation */
66 Trf_Vectors* vectors; /* vectors used during the transformation */
67 } DirectionInfo;
68
69
70 /*
71 * Definition of the structure containing the information about the
72 * internal input buffer.
73 */
74
75 typedef struct _SeekState_ SeekState;
76
77 typedef struct _ResultBuffer_ {
78 unsigned char* buf; /* Reference to the buffer area */
79 int allocated; /* Allocated size of the buffer area */
80 int used; /* Number of bytes in the buffer, <= allocated */
81
82 SeekState* seekState;
83 } ResultBuffer;
84
85
86 typedef struct _SeekConfig_ {
87
88 int overideAllowed; /* Boolean flag. If set the user may overide the
89 * standard policy with his own choice */
90 Trf_SeekInformation natural; /* Natural seek policy, copied from the
91 * transform definition */
92 Trf_SeekInformation chosen; /* Seek policy chosen from natural policy
93 * and the underlying channels; */
94 int identity; /* Flag, set if 'identity' was forced by the
95 * user. */
96 } SeekConfig;
97
98
99 struct _SeekState_ {
100 /* -- Integrity conditions --
101 *
102 * BufStartLoc == BufEndLoc implies ResultLength(&result) == 0.
103 * BufStartLoc == BufEndLoc implies UpLoc == BufStart.
104 *
105 * UP_CONVERT (DownLoc - AheadOffset) == BufEndLoc
106 *
107 * UpXLoc % seekState.used.numBytesTransform == 0
108 * <=> Transform may seek only in multiples of its input tuples.
109 *
110 * (DownLoc - AheadOffset) % seekState.used.numBytesDown == 0
111 * <=> Downstream channel operates in multiples of the transformation
112 * output tuples, except for possible offsets because of read ahead.
113 *
114 * UP_CONVERT (DownZero) == 0
115 *
116 * -- Integrity conditions --
117 */
118
119 Trf_SeekInformation used; /* Seek policy currently in effect, might
120 * be chosen by user */
121 int allowed; /* Flag. Set for seekable transforms. Derived
122 * from the contents of 'used'. */
123
124 int upLoc; /* Current location of file pointer in the
125 * transformed stream. */
126 int upBufStartLoc; /* Same as above, for start of read buffer (result) */
127 int upBufEndLoc; /* See above, for the character after the end of the
128 * buffer. */
129 int downLoc; /* Current location of the file pointer in the channel
130 * downstream. */
131 int downZero; /* location downstream equivalent to UpLoc == 0 */
132 int aheadOffset; /* #Bytes DownLoc is after the down location of
133 * BufEnd. Values > 0 indicate incomplete data in the
134 * transform buffer itself. */
135 int changed; /* Flag, set if seeking occured with 'identity' set */
136 };
137
138
139 /** XXX change definition for 8.2, at compile time */
140
141 typedef struct _TrfTransformationInstance_ {
142 #ifdef USE_TCL_STUBS
143 int patchVariant; /* See transformInt.h, Trf_Registry */
144 #endif
145
146 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com> */
147
148 Tcl_Channel self; /* Our own channel handle */
149 Tcl_Channel parent; /* The channel we are stacked upon. Relevant
150 * only for values PATCH_ORIG and PATCH_832 of
151 * 'patchVariant', see above. */
152
153 int readIsFlushed; /* flag to note wether in.flushProc was called or not */
154
155 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com> */
156
157 int flags; /* currently CHANNEL_ASYNC or zero */
158 int watchMask; /* current TrfWatch mask */
159
160 int mode; /* mode of parent channel,
161 * OR'ed combination of
162 * TCL_READABLE, TCL_WRITABLE */
163
164 /* Tcl_Transformation standard; data required for all transformation
165 * instances.
166 */
167 DirectionInfo in; /* information for transformation of read data */
168 DirectionInfo out; /* information for transformation of written data */
169 ClientData clientData; /* copy from entry->trfType->clientData */
170
171 /*
172 * internal result buffer used during transformations of incoming data.
173 * Stores results waiting for retrieval too, i.e. state information
174 * carried from call to call.
175 */
176
177 ResultBuffer result;
178
179 /* Number of bytes written during a down transformation.
180 */
181
182 int lastWritten;
183
184 /* Number of bytes stored during an up transformation
185 */
186
187 int lastStored;
188
189
190 /* Timer for automatic push out of information sitting in various channel
191 * buffers. Used by the fileevent support. See 'ChannelHandler'.
192 */
193
194 Tcl_TimerToken timer;
195
196 /* Information about the chosen and used seek policy and wether the user
197 * is allowed to change it. Runtime configuration.
198 */
199
200 SeekConfig seekCfg;
201
202 /* More seek information, runtime state.
203 */
204
205 SeekState seekState;
206
207 #ifdef TRF_STREAM_DEBUG
208 char* name; /* Name of transformation command */
209 unsigned long inCounter; /* Number of bytes read from below */
210 unsigned long outCounter; /* Number of bytes stored in 'result' */
211 #endif
212
213 } TrfTransformationInstance;
214
215 #ifdef TRF_STREAM_DEBUG
216 #define STREAM_IN(trans,blen,buf) {int i; for (i=0;i<(blen);i++,(trans)->inCounter++) {printf ("%p:%s:in_\t%d\t%02x\n", (trans), (trans)->name, (trans)->inCounter, 0xff & ((buf) [i]));}}
217 #define STREAM_OUT(trans,blen,buf) {int i; for (i=0;i<(blen);i++,(trans)->outCounter++) {printf ("%p:%s:out\t%d\t%02x\n", (trans), (trans)->name, (trans)->outCounter, 0xff & ((buf) [i]));}}
218 #else
219 #define STREAM_IN(t,bl,b)
220 #define STREAM_OUT(t,bl,b)
221 #endif
222
223
224 #define INCREMENT (512)
225 #define READ_CHUNK_SIZE 4096
226
227
228 #define TRF_UP_CONVERT(trans,k) \
229 (((k) / trans->seekState.used.numBytesDown) * trans->seekState.used.numBytesTransform)
230
231 #define TRF_DOWN_CONVERT(trans,k) \
232 (((k) / trans->seekState.used.numBytesTransform) * trans->seekState.used.numBytesDown)
233
234 #define TRF_IS_UNSEEKABLE(si) \
235 (((si).numBytesTransform == 0) || ((si).numBytesDown == 0))
236
237 #define TRF_SET_UNSEEKABLE(si) \
238 {(si).numBytesTransform = 0 ; (si).numBytesDown = 0;}
239
240
241
242 /*
243 * forward declarations of all internally used procedures.
244 */
245
246 static Tcl_ChannelType*
247 AllocChannelType _ANSI_ARGS_ ((int* sizePtr));
248
249 static Tcl_ChannelType*
250 InitializeChannelType _ANSI_ARGS_ ((CONST char* name, int patchVariant));
251
252
253 static int
254 TrfUnregister _ANSI_ARGS_ ((Tcl_Interp* interp,
255 Trf_RegistryEntry* entry));
256
257 static void
258 TrfDeleteRegistry _ANSI_ARGS_ ((ClientData clientData, Tcl_Interp *interp));
259
260 static int
261 TrfExecuteObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp* interp,
262 int objc, struct Tcl_Obj* CONST objv []));
263
264 static void
265 TrfDeleteCmd _ANSI_ARGS_((ClientData clientData));
266
267 #if 0
268 static int
269 TrfInfoObjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp* interp,
270 int objc, struct Tcl_Obj* CONST objv []));
271 #endif
272 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
273 */
274 static int
275 TrfBlock _ANSI_ARGS_ ((ClientData instanceData, int mode));
276
277 static int
278 TrfClose _ANSI_ARGS_ ((ClientData instanceData, Tcl_Interp* interp));
279
280 static int
281 TrfInput _ANSI_ARGS_ ((ClientData instanceData,
282 char* buf, int toRead,
283 int* errorCodePtr));
284
285 static int
286 TrfOutput _ANSI_ARGS_ ((ClientData instanceData,
287 CONST84 char* buf, int toWrite,
288 int* errorCodePtr));
289
290 static int
291 TrfSeek _ANSI_ARGS_ ((ClientData instanceData, long offset,
292 int mode, int* errorCodePtr));
293 static void
294 TrfWatch _ANSI_ARGS_ ((ClientData instanceData, int mask));
295
296 static int
297 TrfGetFile _ANSI_ARGS_ ((ClientData instanceData, int direction,
298 ClientData* handlePtr));
299
300 static int
301 TrfGetOption _ANSI_ARGS_ ((ClientData instanceData, Tcl_Interp* interp,
302 CONST84 char* optionName, Tcl_DString* dsPtr));
303
304 static int
305 TrfSetOption _ANSI_ARGS_((ClientData instanceData, Tcl_Interp* interp,
306 CONST char* optionName, CONST char* value));
307 #ifdef USE_TCL_STUBS
308 static int
309 TrfNotify _ANSI_ARGS_((ClientData instanceData, int interestMask));
310 #endif
311
312 static int
313 TransformImmediate _ANSI_ARGS_ ((Tcl_Interp* interp, Trf_RegistryEntry* entry,
314 Tcl_Channel source, Tcl_Channel destination,
315 struct Tcl_Obj* CONST in,
316 Trf_Options optInfo));
317
318 static int
319 AttachTransform _ANSI_ARGS_ ((Trf_RegistryEntry* entry,
320 Trf_BaseOptions* baseOpt,
321 Trf_Options optInfo,
322 Tcl_Interp* interp));
323
324 static int
325 PutDestination _ANSI_ARGS_ ((ClientData clientData,
326 unsigned char* outString, int outLen,
327 Tcl_Interp* interp));
328
329 static int
330 PutDestinationImm _ANSI_ARGS_ ((ClientData clientData,
331 unsigned char* outString, int outLen,
332 Tcl_Interp* interp));
333 static int
334 PutTrans _ANSI_ARGS_ ((ClientData clientData,
335 unsigned char* outString, int outLen,
336 Tcl_Interp* interp));
337
338 static int
339 PutInterpResult _ANSI_ARGS_ ((ClientData clientData,
340 unsigned char* outString, int outLen,
341 Tcl_Interp* interp));
342 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
343 */
344 static void
345 ChannelHandler _ANSI_ARGS_ ((ClientData clientData, int mask));
346
347 static void
348 ChannelHandlerTimer _ANSI_ARGS_ ((ClientData clientData));
349
350 #ifdef USE_TCL_STUBS
351 static Tcl_Channel
352 DownChannel _ANSI_ARGS_ ((TrfTransformationInstance* ctrl));
353
354 static int
355 DownSeek _ANSI_ARGS_ ((TrfTransformationInstance* ctrl, int offset, int mode));
356
357 static int
358 DownRead _ANSI_ARGS_ ((TrfTransformationInstance* ctrl,
359 char* buf, int toRead));
360 static int
361 DownWrite _ANSI_ARGS_ ((TrfTransformationInstance* ctrl,
362 char* buf, int toWrite));
363 static int
364 DownSOpt _ANSI_ARGS_ ((Tcl_Interp* interp,
365 TrfTransformationInstance* ctrl,
366 CONST char* optionName, CONST char* value));
367 static int
368 DownGOpt _ANSI_ARGS_ ((Tcl_Interp* interp,
369 TrfTransformationInstance* ctrl,
370 CONST84 char* optionName, Tcl_DString* dsPtr));
371
372 #define DOWNC(trans) (DownChannel (trans))
373 #define TELL(trans) (SEEK (trans, 0, SEEK_CUR))
374 #define SEEK(trans,off,mode) (DownSeek ((trans), (off), (mode)))
375 #define READ(trans,buf,toRead) (DownRead ((trans), (buf), (toRead)))
376 #define WRITE(trans,buf,toWrite) (DownWrite ((trans), (buf), (toWrite)))
377 #define SETOPT(i,trans,opt,val) (DownSOpt ((i), (trans), (opt), (val)))
378 #define GETOPT(i,trans,opt,ds) (DownGOpt ((i), (trans), (opt), (ds)))
379 #else
380 #define DOWNC(trans) ((trans)->parent)
381 #define TELL(trans) (SEEK (trans, 0, SEEK_CUR))
382 #define SEEK(trans,off,mode) (Tcl_Seek ((trans)->parent, (off), (mode)))
383 #define READ(trans,buf,toRead) (Tcl_Read ((trans)->parent, (buf), (toRead)))
384 #define WRITE(trans,buf,toWrite) (Tcl_Write ((trans)->parent, (buf), (toWrite)))
385 #define SETOPT(i,trans,opt,val) (Tcl_SetChannelOption ((i), (trans)->parent, (opt), (val)))
386 #define GETOPT(i,trans,opt,ds) (Tcl_GetChannelOption ((i), (trans)->parent, (opt), (ds)))
387 #endif
388
389 /* Convenience macro for allocation
390 * of new transformation instances.
391 */
392
393 #define NEW_TRANSFORM \
394 (TrfTransformationInstance*) ckalloc (sizeof (TrfTransformationInstance));
395
396 /* Procedures to handle the internal timer.
397 */
398
399 static void
400 TimerKill _ANSI_ARGS_ ((TrfTransformationInstance* trans));
401
402 static void
403 TimerSetup _ANSI_ARGS_ ((TrfTransformationInstance* trans));
404
405 static void
406 ChannelHandlerKS _ANSI_ARGS_ ((TrfTransformationInstance* trans, int mask));
407
408
409
410 /* Procedures to handle the internal read buffer.
411 */
412
413 static void ResultClear _ANSI_ARGS_ ((ResultBuffer* r));
414 static void ResultInit _ANSI_ARGS_ ((ResultBuffer* r));
415 static int ResultLength _ANSI_ARGS_ ((ResultBuffer* r));
416 static int ResultCopy _ANSI_ARGS_ ((ResultBuffer* r,
417 unsigned char* buf, int toRead));
418 static void ResultDiscardAtStart _ANSI_ARGS_ ((ResultBuffer* r,
419 int n));
420 static void ResultAdd _ANSI_ARGS_ ((ResultBuffer* r,
421 unsigned char* buf, int toWrite));
422
423 /*
424 * Procedures to handle seeking information.
425 */
426
427 static void
428 SeekCalculatePolicies _ANSI_ARGS_ ((TrfTransformationInstance* trans));
429
430 static void
431 SeekInitialize _ANSI_ARGS_ ((TrfTransformationInstance* trans));
432
433 static void
434 SeekClearBuffer _ANSI_ARGS_ ((TrfTransformationInstance* trans, int which));
435
436 static void
437 SeekSynchronize _ANSI_ARGS_ ((TrfTransformationInstance* trans,
438 Tcl_Channel parent));
439
440 static Tcl_Obj*
441 SeekStateGet _ANSI_ARGS_ ((Tcl_Interp* interp, SeekState* state));
442
443 static Tcl_Obj*
444 SeekConfigGet _ANSI_ARGS_ ((Tcl_Interp* interp, SeekConfig* cfg));
445
446 static void
447 SeekPolicyGet _ANSI_ARGS_ ((TrfTransformationInstance* trans,
448 char* policy));
449
450 #ifdef TRF_DEBUG
451 static void
452 SeekDump _ANSI_ARGS_ ((TrfTransformationInstance* trans, CONST char* place));
453
454 #define SEEK_DUMP(str) SeekDump (trans, #str)
455 #else
456 #define SEEK_DUMP(str)
457 #endif
458
459 /*
460 *------------------------------------------------------*
461 *
462 * TrfGetRegistry --
463 *
464 * ------------------------------------------------*
465 * Accessor to the interpreter associated registry
466 * of transformations.
467 * ------------------------------------------------*
468 *
469 * Sideeffects:
470 * Allocates and initializes the hashtable
471 * during the first call and associates it
472 * with the specified interpreter.
473 *
474 * Result:
475 * The internal registry of transformations.
476 *
477 *------------------------------------------------------*
478 */
479
480 Trf_Registry*
TrfGetRegistry(interp)481 TrfGetRegistry (interp)
482 Tcl_Interp* interp;
483 {
484 Trf_Registry* registry;
485
486 START (TrfGetRegistry);
487
488 registry = TrfPeekForRegistry (interp);
489
490 if (registry == (Trf_Registry*) NULL) {
491 registry = (Trf_Registry*) ckalloc (sizeof (Trf_Registry));
492 registry->registry = (Tcl_HashTable*) ckalloc (sizeof (Tcl_HashTable));
493
494 Tcl_InitHashTable (registry->registry, TCL_STRING_KEYS);
495
496 Tcl_SetAssocData (interp, ASSOC, TrfDeleteRegistry,
497 (ClientData) registry);
498 }
499
500 DONE (TrfGetRegistry);
501 return registry;
502 }
503
504 /*
505 *------------------------------------------------------*
506 *
507 * TrfPeekForRegistry --
508 *
509 * ------------------------------------------------*
510 * Accessor to the interpreter associated registry
511 * of transformations. Does not create the registry
512 * (in contrast to 'TrfGetRegistry').
513 * ------------------------------------------------*
514 *
515 * Sideeffects:
516 * None.
517 *
518 * Result:
519 * The internal registry of transformations.
520 *
521 *------------------------------------------------------*
522 */
523
524 Trf_Registry*
TrfPeekForRegistry(interp)525 TrfPeekForRegistry (interp)
526 Tcl_Interp* interp;
527 {
528 Tcl_InterpDeleteProc* proc;
529
530 START (TrfPeekForRegistry);
531
532 proc = TrfDeleteRegistry;
533
534 DONE (TrfPeekForRegistry);
535 return (Trf_Registry*) Tcl_GetAssocData (interp, ASSOC, &proc);
536 }
537
538 /*
539 *------------------------------------------------------*
540 *
541 * Trf_Register --
542 *
543 * ------------------------------------------------*
544 * Announce a transformation to the registry associated
545 * with the specified interpreter.
546 * ------------------------------------------------*
547 *
548 * Sideeffects:
549 * May create the registry. Allocates and
550 * initializes the structure describing
551 * the announced transformation.
552 *
553 * Result:
554 * A standard TCL error code.
555 *
556 *------------------------------------------------------*
557 */
558
559 int
Trf_Register(interp,type)560 Trf_Register (interp, type)
561 Tcl_Interp* interp;
562 CONST Trf_TypeDefinition* type;
563 {
564 Trf_Registry* registry;
565 Trf_RegistryEntry* entry;
566 Tcl_HashEntry* hPtr;
567 int new;
568
569 START (Trf_Register);
570 PRINT ("(%p, \"%s\")\n", type, type->name); FL;
571
572 registry = TrfGetRegistry (interp);
573
574 /*
575 * Already defined ?
576 */
577
578 hPtr = Tcl_FindHashEntry (registry->registry, (char*) type->name);
579
580 if (hPtr != (Tcl_HashEntry*) NULL) {
581 PRINT ("Already defined!\n"); FL;
582 DONE (Trf_Register);
583 return TCL_ERROR;
584 }
585
586 /*
587 * Check validity of given structure
588 */
589
590 #define IMPLY(a,b) ((! (a)) || (b))
591
592 /* assert (type->options); */
593 assert (IMPLY(type->options != NULL, type->options->createProc != NULL));
594 assert (IMPLY(type->options != NULL, type->options->deleteProc != NULL));
595 assert (IMPLY(type->options != NULL, type->options->checkProc != NULL));
596 assert (IMPLY(type->options != NULL,
597 (type->options->setProc != NULL) ||
598 (type->options->setObjProc != NULL)));
599 assert (IMPLY(type->options != NULL, type->options->queryProc != NULL));
600
601 assert (type->encoder.createProc);
602 assert (type->encoder.deleteProc);
603 assert ((type->encoder.convertProc != NULL) ||
604 (type->encoder.convertBufProc != NULL));
605 assert (type->encoder.flushProc);
606 assert (type->encoder.clearProc);
607
608 assert (type->decoder.createProc);
609 assert (type->decoder.deleteProc);
610 assert ((type->decoder.convertProc != NULL) ||
611 (type->decoder.convertBufProc != NULL));
612 assert (type->decoder.flushProc);
613 assert (type->decoder.clearProc);
614
615 /*
616 * Generate command to execute transformations immediately or to generate
617 * filters.
618 */
619
620 entry = (Trf_RegistryEntry*) ckalloc (sizeof (Trf_RegistryEntry));
621 entry->registry = registry;
622
623 entry->trfType = (Trf_TypeDefinition*) type;
624 entry->interp = interp;
625 #ifndef USE_TCL_STUBS
626 entry->transType = InitializeChannelType (type->name, -1);
627 #else
628 entry->transType = InitializeChannelType (type->name,
629 registry->patchVariant);
630 #endif
631 entry->trfCommand = Tcl_CreateObjCommand (interp, (char*) type->name,
632 TrfExecuteObjCmd,
633 (ClientData) entry, TrfDeleteCmd);
634
635 /*
636 * Add entry to internal registry.
637 */
638
639 hPtr = Tcl_CreateHashEntry (registry->registry, (char*) type->name, &new);
640 Tcl_SetHashValue (hPtr, entry);
641
642 DONE (Trf_Register);
643 return TCL_OK;
644 }
645
646 /*
647 *------------------------------------------------------*
648 *
649 * Trf_Unregister --
650 *
651 * ------------------------------------------------*
652 * Removes the transformation from the registry
653 * ------------------------------------------------*
654 *
655 * Sideeffects:
656 * Releases the memory allocated in 'Trf_Register'.
657 *
658 * Result:
659 * A standard TCL error code.
660 *
661 *------------------------------------------------------*
662 */
663
664 static int
TrfUnregister(interp,entry)665 TrfUnregister (interp, entry)
666 Tcl_Interp* interp;
667 Trf_RegistryEntry* entry;
668 {
669 Trf_Registry* registry;
670 Tcl_HashEntry* hPtr;
671
672 START (Trf_Unregister);
673
674 registry = TrfGetRegistry (interp);
675 hPtr = Tcl_FindHashEntry (registry->registry,
676 (char*) entry->trfType->name);
677
678 ckfree ((char*) entry->transType);
679 ckfree ((char*) entry);
680
681 Tcl_DeleteHashEntry (hPtr);
682
683 DONE (Trf_Unregister);
684 return TCL_OK;
685 }
686
687 /*
688 *------------------------------------------------------*
689 *
690 * TrfDeleteRegistry --
691 *
692 * ------------------------------------------------*
693 * Trap handler. Called by the Tcl core during
694 * interpreter destruction. Destroys the registry
695 * of transformations.
696 * ------------------------------------------------*
697 *
698 * Sideeffects:
699 * Releases the memory allocated in 'TrfGetRegistry'.
700 *
701 * Result:
702 * None.
703 *
704 *------------------------------------------------------*
705 */
706
707 static void
TrfDeleteRegistry(clientData,interp)708 TrfDeleteRegistry (clientData, interp)
709 ClientData clientData;
710 Tcl_Interp* interp;
711 {
712 Trf_Registry* registry = (Trf_Registry*) clientData;
713
714 START (TrfDeleteRegistry);
715
716 /*
717 * The commands are already deleted, therefore the hashtable is empty here.
718 */
719
720 Tcl_DeleteHashTable (registry->registry);
721 ckfree ((char*) registry);
722
723 DONE (TrfDeleteRegistry);
724 }
725
726 /* (readable) shortcuts for calling the option processing vectors.
727 */
728
729 #define CLT (entry->trfType->clientData)
730 #define OPT (entry->trfType->options)
731
732 #define CREATE_OPTINFO (OPT ? (*OPT->createProc) (CLT) : NULL)
733 #define DELETE_OPTINFO if (optInfo) (*OPT->deleteProc) (optInfo, CLT)
734 #define CHECK_OPTINFO(baseOpt) (optInfo ? (*OPT->checkProc) (optInfo, interp, &baseOpt, CLT) : TCL_OK)
735 #define SET_OPTION(opt,optval) (optInfo ? (*OPT->setProc) (optInfo, interp, opt, optval, CLT) : TCL_ERROR)
736
737 #define SET_OPTION_OBJ(opt,optval) (optInfo ? (*OPT->setObjProc) (optInfo, interp, opt, optval, CLT) : TCL_ERROR)
738
739 #define ENCODE_REQUEST(entry,optInfo) (optInfo ? (*OPT->queryProc) (optInfo, CLT) : 1)
740
741 /*
742 *------------------------------------------------------*
743 *
744 * TrfExecuteObjCmd --
745 *
746 * ------------------------------------------------*
747 * Implementation procedure for all transformations.
748 * Equivalent to 'TrfExecuteCmd', but using the new
749 * Object interfaces.
750 * ------------------------------------------------*
751 *
752 * Sideeffects:
753 * See 'TrfExecuteCmd'.
754 *
755 * Result:
756 * A standard TCL error code.
757 *
758 *------------------------------------------------------*
759 */
760
761 static int
TrfExecuteObjCmd(clientData,interp,objc,objv)762 TrfExecuteObjCmd (clientData, interp, objc, objv)
763 ClientData clientData;
764 Tcl_Interp* interp;
765 int objc;
766 struct Tcl_Obj* CONST * objv;
767 {
768 /* (readable) shortcuts for calling the option processing vectors.
769 * as defined in 'TrfExecuteCmd'.
770 */
771
772 int res, len;
773 /* Tcl_Channel source, destination;*/
774 /* int src_mode, dst_mode;*/
775 const char* cmd;
776 const char* option;
777 struct Tcl_Obj* optarg;
778 Trf_RegistryEntry* entry;
779 Trf_Options optInfo;
780 Trf_BaseOptions baseOpt;
781 int mode;
782 int wrong_mod2;
783 int wrong_number;
784
785 START (TrfExecuteObjCmd);
786 #ifdef TRF_DEBUG
787 {
788 int i;
789 for (i = 0; i < objc; i++) {
790 PRINT ("Argument [%03d] = \"%s\"\n",
791 i, Tcl_GetStringFromObj (objv [i], NULL)); FL;
792 }
793 }
794 #endif
795
796 baseOpt.attach = (Tcl_Channel) NULL;
797 baseOpt.attach_mode = 0;
798 baseOpt.source = (Tcl_Channel) NULL;
799 baseOpt.destination = (Tcl_Channel) NULL;
800 baseOpt.policy = (Tcl_Obj*) NULL;
801
802 entry = (Trf_RegistryEntry*) clientData;
803 cmd = Tcl_GetStringFromObj (objv [0], NULL);
804
805 objc --;
806 objv ++;
807
808 optInfo = CREATE_OPTINFO;
809
810 PRINT ("Processing options...\n"); FL; IN;
811
812 while ((objc > 0) && (*Tcl_GetStringFromObj (objv [0], NULL) == '-')) {
813 /*
814 * Process options, as long as they are found
815 */
816
817 option = Tcl_GetStringFromObj (objv [0], NULL);
818
819 if (0 == strcmp (option, "--")) {
820 /* end of option list */
821 objc--, objv++;
822 break;
823 }
824
825 wrong_number = (objc < 2); /* option, but without argument */
826
827 optarg = objv [1];
828
829 objc -= 2;
830 objv += 2;
831
832 len = strlen (option);
833
834 if (len < 2)
835 goto unknown_option;
836
837 switch (option [1])
838 {
839 case 'a':
840 if (0 != strncmp (option, "-attach", len))
841 goto check_for_trans_option;
842
843 if (wrong_number) {
844 Tcl_AppendResult (interp, cmd, ": wrong # args, option \"", option, "\" requires an argument", (char*) NULL);
845 OT;
846 goto cleanup_after_error;
847 }
848
849 baseOpt.attach = Tcl_GetChannel (interp,
850 Tcl_GetStringFromObj (optarg, NULL),
851 &baseOpt.attach_mode);
852 if (baseOpt.attach == (Tcl_Channel) NULL) {
853 OT;
854 goto cleanup_after_error;
855 }
856 break;
857
858 case 'i':
859 if (0 != strncmp (option, "-in", len))
860 goto check_for_trans_option;
861
862 if (wrong_number) {
863 Tcl_AppendResult (interp, cmd, ": wrong # args, option \"", option, "\" requires an argument", (char*) NULL);
864 OT;
865 goto cleanup_after_error;
866 }
867
868 baseOpt.source = Tcl_GetChannel (interp,
869 Tcl_GetStringFromObj (optarg, NULL),
870 &mode);
871 if (baseOpt.source == (Tcl_Channel) NULL)
872 goto cleanup_after_error;
873
874 if (! (mode & TCL_READABLE)) {
875 Tcl_AppendResult (interp, cmd,
876 ": source-channel not readable",
877 (char*) NULL);
878 OT;
879 goto cleanup_after_error;
880 }
881 break;
882
883 case 'o':
884 if (0 != strncmp (option, "-out", len))
885 goto check_for_trans_option;
886
887 if (wrong_number) {
888 Tcl_AppendResult (interp, cmd, ": wrong # args, option \"", option, "\" requires an argument", (char*) NULL);
889 OT;
890 goto cleanup_after_error;
891 }
892
893 baseOpt.destination = Tcl_GetChannel (interp,
894 Tcl_GetStringFromObj (optarg,
895 NULL),
896 &mode);
897
898 if (baseOpt.destination == (Tcl_Channel) NULL) {
899 OT;
900 goto cleanup_after_error;
901 }
902
903 if (! (mode & TCL_WRITABLE)) {
904 Tcl_AppendResult (interp, cmd,
905 ": destination-channel not writable",
906 (char*) NULL);
907 OT;
908 goto cleanup_after_error;
909 }
910 break;
911
912 case 's':
913 if (0 != strncmp (option, "-seekpolicy", len))
914 goto check_for_trans_option;
915
916 if (wrong_number) {
917 Tcl_AppendResult (interp, cmd, ": wrong # args, option \"", option, "\" requires an argument", (char*) NULL);
918 OT;
919 goto cleanup_after_error;
920 }
921
922 baseOpt.policy = optarg;
923 Tcl_IncrRefCount (optarg);
924 break;
925
926 default:
927 check_for_trans_option:
928 if (wrong_number) {
929 Tcl_AppendResult (interp, cmd, ": wrong # args, all options require an argument", (char*) NULL);
930 OT;
931 goto cleanup_after_error;
932 }
933
934 if ((*OPT->setObjProc) == NULL) {
935 res = SET_OPTION (option, Tcl_GetStringFromObj (optarg, NULL));
936 } else {
937 res = SET_OPTION_OBJ (option, optarg);
938 }
939
940 if (res != TCL_OK) {
941 OT;
942 goto cleanup_after_error;
943 }
944 break;
945 } /* switch option */
946 } /* while options */
947
948 OT;
949
950 /*
951 * Check argument restrictions, insert defaults if necessary,
952 * execute the required operation.
953 */
954
955 if ((baseOpt.attach != (Tcl_Channel) NULL) &&
956 ((baseOpt.source != (Tcl_Channel) NULL) ||
957 (baseOpt.destination != (Tcl_Channel) NULL))) {
958 Tcl_AppendResult (interp, cmd,
959 ": inconsistent options, -in/-out not allowed with -attach",
960 (char*) NULL);
961
962 PRINT ("Inconsistent options\n"); FL;
963 goto cleanup_after_error;
964 }
965
966 if ((baseOpt.attach == (Tcl_Channel) NULL) &&
967 baseOpt.policy != (Tcl_Obj*) NULL) {
968
969 Tcl_AppendResult (interp, cmd,
970 ": inconsistent options, -seekpolicy ",
971 "not allowed without -attach",
972 (char*) NULL);
973
974 PRINT ("Inconsistent options\n"); FL;
975 goto cleanup_after_error;
976 }
977
978 if ((baseOpt.source == (Tcl_Channel) NULL) &&
979 (baseOpt.attach == (Tcl_Channel) NULL))
980 wrong_mod2 = 0;
981 else
982 wrong_mod2 = 1;
983
984 if (wrong_mod2 == (objc % 2)) {
985 Tcl_AppendResult (interp, cmd, ": wrong # args", (char*) NULL);
986 PRINT ("Wrong # args\n"); FL;
987 goto cleanup_after_error;
988 }
989
990 res = CHECK_OPTINFO (baseOpt);
991 if (res != TCL_OK) {
992 DELETE_OPTINFO;
993
994 PRINT ("Options contain errors\n"); FL;
995 DONE (TrfExecuteObjCmd);
996 return TCL_ERROR;
997 }
998
999 if (baseOpt.attach == (Tcl_Channel) NULL) /* TRF_IMMEDIATE */ {
1000 /*
1001 * Immediate execution of transformation requested.
1002 */
1003
1004 res = TransformImmediate (interp, entry,
1005 baseOpt.source, baseOpt.destination,
1006 objv [0], optInfo);
1007
1008 } else /* TRF_ATTACH */ {
1009 /*
1010 * User requested attachment of transformation procedure to a channel.
1011 * In case of a stub-aware interpreter use that to check for the
1012 * existence of the necessary patches ! Bail out if not.
1013 */
1014
1015 #ifdef USE_TCL_STUBS
1016 if (Tcl_StackChannel == NULL) {
1017 Tcl_AppendResult (interp, cmd, ": this feature (-attach) is not ",
1018 "available as the required patch to the core ",
1019 "was not applied", (char*) NULL);
1020 DELETE_OPTINFO;
1021
1022 PRINT ("-attach not available\n"); FL;
1023 DONE (TrfExecuteObjCmd);
1024 return TCL_ERROR;
1025 }
1026 #endif
1027
1028 res = AttachTransform (entry, &baseOpt, optInfo, interp);
1029
1030 if (baseOpt.policy != (Tcl_Obj*) NULL) {
1031 Tcl_DecrRefCount (baseOpt.policy);
1032 baseOpt.policy = (Tcl_Obj*) NULL;
1033 }
1034 }
1035
1036 DELETE_OPTINFO;
1037 DONE (TrfExecuteObjCmd);
1038 return res;
1039
1040
1041 unknown_option:
1042 PRINT ("Unknown option \"%s\"\n", option); FL; OT;
1043
1044 Tcl_AppendResult (interp, cmd, ": unknown option '", option, "', should be '-attach/in/out' or '-seekpolicy'",
1045 (char*) NULL);
1046 /* fall through to cleanup */
1047
1048 cleanup_after_error:
1049 DELETE_OPTINFO;
1050 DONE (TrfExecuteObjCmd);
1051 return TCL_ERROR;
1052 }
1053
1054 /*
1055 *------------------------------------------------------*
1056 *
1057 * TrfDeleteCmd --
1058 *
1059 * ------------------------------------------------*
1060 * Trap handler. Called by the Tcl core during
1061 * destruction of the command for invocation of a
1062 * transformation.
1063 * ------------------------------------------------*
1064 *
1065 * Sideeffects:
1066 * Removes the transformation from the registry.
1067 *
1068 * Result:
1069 * None.
1070 *
1071 *------------------------------------------------------*
1072 */
1073
1074 static void
TrfDeleteCmd(clientData)1075 TrfDeleteCmd (clientData)
1076 ClientData clientData;
1077 {
1078 Trf_RegistryEntry* entry;
1079
1080 START (TrfDeleteCmd);
1081
1082 entry = (Trf_RegistryEntry*) clientData;
1083
1084 TrfUnregister (entry->interp, entry);
1085 DONE (TrfDeleteCmd);
1086 }
1087
1088 /*
1089 *----------------------------------------------------------------------
1090 *
1091 * TrfInfoObjCmd --
1092 *
1093 * This procedure is invoked to process the "trfinfo" Tcl command.
1094 * See the user documentation for details on what it does.
1095 *
1096 * Results:
1097 * A standard Tcl result.
1098 *
1099 * Side effects:
1100 * None.
1101 *
1102 *----------------------------------------------------------------------
1103 */
1104 #if 0
1105 static int
1106 TrfInfoObjCmd (notUsed, interp, objc, objv)
1107 ClientData notUsed; /* Not used. */
1108 Tcl_Interp* interp; /* Current interpreter. */
1109 int objc;
1110 struct Tcl_Obj* CONST * objv;
1111 {
1112 /*
1113 * trfinfo <channel>
1114 */
1115
1116 static char* subcmd [] = {
1117 "seekstate", "seekcfg", NULL
1118 };
1119 enum subcmd {
1120 TRFINFO_SEEKSTATE, TRFINFO_SEEKCFG
1121 };
1122
1123 Tcl_Channel chan;
1124 int mode, pindex;
1125 char* chanName;
1126 TrfTransformationInstance* trans;
1127
1128
1129 if ((objc < 2) || (objc > 3)) {
1130 Tcl_AppendResult (interp,
1131 "wrong # args: should be \"trfinfo cmd channel\"",
1132 (char*) NULL);
1133 return TCL_ERROR;
1134 }
1135
1136 chanName = Tcl_GetStringFromObj (objv [2], NULL);
1137 chan = Tcl_GetChannel (interp, chanName, &mode);
1138
1139 if (chan == (Tcl_Channel) NULL) {
1140 return TCL_ERROR;
1141 }
1142
1143 if (Tcl_GetChannelType (chan)->seekProc != TrfSeek) {
1144 /* No trf transformation, info not applicable.
1145 */
1146
1147 Tcl_AppendResult (interp,
1148 "channel \"", chanName,
1149 "\" is no transformation from trf",
1150 (char*) NULL);
1151 return TCL_ERROR;
1152 }
1153
1154 /* Peek into the instance structure and return the requested
1155 * information.
1156 */
1157
1158 if (Tcl_GetIndexFromObj(interp, objv [1], subcmd, "subcommand", 0,
1159 &pindex) != TCL_OK) {
1160 return TCL_ERROR;
1161 }
1162
1163 trans = (TrfTransformationInstance*) Tcl_GetChannelInstanceData (chan);
1164
1165 switch (pindex) {
1166 case TRFINFO_SEEKSTATE:
1167 {
1168 Tcl_Obj* state = SeekStateGet (interp, &trans->seekState);
1169
1170 if (state == NULL)
1171 return TCL_ERROR;
1172
1173 Tcl_SetObjResult (interp, state);
1174 return TCL_OK;
1175 }
1176 break;
1177
1178 case TRFINFO_SEEKCFG:
1179 {
1180 Tcl_Obj* cfg = SeekConfigGet (interp, &trans->seekCfg);
1181
1182 if (cfg == NULL)
1183 return TCL_ERROR;
1184
1185 Tcl_SetObjResult (interp, cfg);
1186 return TCL_OK;
1187 }
1188 break;
1189
1190 default:
1191 /* impossible */
1192 return TCL_ERROR;
1193 }
1194
1195 /* We should not come to this place */
1196 return TCL_ERROR;
1197 }
1198 #endif
1199
1200 /*
1201 *------------------------------------------------------*
1202 *
1203 * TrfInit_Info --
1204 *
1205 * ------------------------------------------------*
1206 * Register the 'info' command.
1207 * ------------------------------------------------*
1208 *
1209 * Sideeffects:
1210 * As of 'Tcl_CreateObjCommand'.
1211 *
1212 * Result:
1213 * A standard Tcl error code.
1214 *
1215 *------------------------------------------------------*
1216 */
1217
1218 int
TrfInit_Info(interp)1219 TrfInit_Info (interp)
1220 Tcl_Interp* interp;
1221 {
1222 #if 0
1223 Tcl_CreateObjCommand (interp, "trfinfo", TrfInfoObjCmd,
1224 (ClientData) NULL,
1225 (Tcl_CmdDeleteProc *) NULL);
1226 #endif
1227 return TCL_OK;
1228 }
1229
1230 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
1231 */
1232 /*
1233 *------------------------------------------------------*
1234 *
1235 * TrfBlock --
1236 *
1237 * ------------------------------------------------*
1238 * Trap handler. Called by the generic IO system
1239 * during option processing to change the blocking
1240 * mode of the channel.
1241 * ------------------------------------------------*
1242 *
1243 * Sideeffects:
1244 * Forwards the request to the underlying
1245 * channel.
1246 *
1247 * Result:
1248 * 0 if successful, errno when failed.
1249 *
1250 *------------------------------------------------------*
1251 */
1252
1253 static int
TrfBlock(instanceData,mode)1254 TrfBlock (instanceData, mode)
1255 ClientData instanceData;
1256 int mode;
1257 {
1258 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
1259 char block [2] = {0,0};
1260 Tcl_Channel parent;
1261
1262 START (TrfBlock);
1263 PRINT ("Mode = %d\n", mode); FL;
1264
1265 parent = DOWNC (trans);
1266
1267 if (mode == TCL_MODE_NONBLOCKING) {
1268 trans->flags |= CHANNEL_ASYNC;
1269 block [0] = '0';
1270 } else {
1271 trans->flags &= ~(CHANNEL_ASYNC);
1272 block [0] = '1';
1273 }
1274
1275 #ifndef USE_TCL_STUBS
1276 Tcl_SetChannelOption (NULL, parent, "-blocking", block);
1277 #else
1278 if ((trans->patchVariant == PATCH_ORIG) ||
1279 (trans->patchVariant == PATCH_82)) {
1280 /*
1281 * Both old-style patch and first integrated version of the patch
1282 * require the transformation to pass the blocking mode to the
1283 * channel downstream. The newest implementation (PATCH_832)
1284 * handles this in the core.
1285 */
1286
1287 Tcl_SetChannelOption (NULL, parent, "-blocking", block);
1288 }
1289 #endif
1290
1291 DONE (TrfBlock);
1292 return 0;
1293 }
1294
1295 /*
1296 *------------------------------------------------------*
1297 *
1298 * TrfClose --
1299 *
1300 * ------------------------------------------------*
1301 * Trap handler. Called by the generic IO system
1302 * during destruction of the transformation channel.
1303 * ------------------------------------------------*
1304 *
1305 * Sideeffects:
1306 * Releases the memory allocated in
1307 * 'AttachTransform'.
1308 *
1309 * Result:
1310 * None.
1311 *
1312 *------------------------------------------------------*
1313 */
1314
1315 static int
TrfClose(instanceData,interp)1316 TrfClose (instanceData, interp)
1317 ClientData instanceData;
1318 Tcl_Interp* interp;
1319 {
1320 /*
1321 * The parent channel will be removed automatically
1322 * (if necessary and/or desired).
1323 */
1324
1325 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
1326 Tcl_Channel parent;
1327
1328 START (TrfClose);
1329
1330 #ifndef USE_TCL_STUBS
1331 if ((trans == (TrfTransformationInstance*) NULL) ||
1332 (interp == (Tcl_Interp*) NULL)) {
1333 /* Hack, prevent 8.0 from crashing upon exit if channels
1334 * with transformations were left open during exit
1335 *
1336 * Suggested by Mikhail Teterin <mi@aldan.algebra.com> 25.11.1999.
1337 */
1338
1339 DONE (TrfClose);
1340 return TCL_OK;
1341 }
1342 #endif
1343
1344 parent = DOWNC (trans);
1345
1346 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
1347 * Remove event handler to underlying channel, this could
1348 * be because we are closing for real, or being "unstacked".
1349 */
1350
1351 #ifndef USE_TCL_STUBS
1352 Tcl_DeleteChannelHandler (parent, ChannelHandler, (ClientData) trans);
1353 #else
1354 if ((trans->patchVariant == PATCH_ORIG) ||
1355 (trans->patchVariant == PATCH_82)) {
1356 Tcl_DeleteChannelHandler (parent, ChannelHandler, (ClientData) trans);
1357 }
1358 /*
1359 * PATCH_832 doesn't use channelhandlers for communication of events
1360 * between the channels of stack anymore.
1361 */
1362 #endif
1363
1364 TimerKill (trans);
1365
1366 /*
1367 * Flush data waiting in transformation buffers to output.
1368 * Flush input too, maybe there are side effects other
1369 * parts do rely on (-> message digests).
1370 */
1371
1372 if (trans->mode & TCL_WRITABLE) {
1373 PRINT ("out.flushproc\n"); FL;
1374
1375 trans->out.vectors->flushProc (trans->out.control,
1376 (Tcl_Interp*) NULL,
1377 trans->clientData);
1378 }
1379
1380 if (trans->mode & TCL_READABLE) {
1381 if (!trans->readIsFlushed) {
1382 PRINT ("in_.flushproc\n"); FL;
1383
1384 trans->readIsFlushed = 1;
1385 trans->in.vectors->flushProc (trans->in.control,
1386 (Tcl_Interp*) NULL,
1387 trans->clientData);
1388 }
1389 }
1390
1391 if (trans->mode & TCL_WRITABLE) {
1392 PRINT ("out.deleteproc\n"); FL;
1393 trans->out.vectors->deleteProc (trans->out.control, trans->clientData);
1394 }
1395
1396 if (trans->mode & TCL_READABLE) {
1397 PRINT ("in_.deleteproc\n"); FL;
1398 trans->in.vectors->deleteProc (trans->in.control, trans->clientData);
1399 }
1400
1401 ResultClear (&trans->result);
1402
1403 /*
1404 * Complement to NEW_TRANSFORM in AttachChannel.
1405 * [Bug 2788106].
1406 */
1407 ckfree((void *)trans);
1408
1409 DONE (TrfClose);
1410 return TCL_OK;
1411 }
1412
1413 /*
1414 *------------------------------------------------------*
1415 *
1416 * TrfInput --
1417 *
1418 * ------------------------------------------------*
1419 * Called by the generic IO system to convert read data.
1420 * ------------------------------------------------*
1421 *
1422 * Sideeffects:
1423 * As defined by the conversion.
1424 *
1425 * Result:
1426 * A transformed buffer.
1427 *
1428 *------------------------------------------------------*
1429 */
1430
1431 static int
TrfInput(instanceData,buf,toRead,errorCodePtr)1432 TrfInput (instanceData, buf, toRead, errorCodePtr)
1433 ClientData instanceData;
1434 char* buf;
1435 int toRead;
1436 int* errorCodePtr;
1437 {
1438 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
1439 int gotBytes, read, i, res, copied, maxRead;
1440 Tcl_Channel parent;
1441
1442 START (TrfInput);
1443 PRINT ("trans = %p, toRead = %d\n", trans, toRead); FL;
1444
1445 parent = DOWNC (trans);
1446
1447 /* should assert (trans->mode & TCL_READABLE) */
1448
1449 gotBytes = 0;
1450
1451 SEEK_DUMP (TrfInput; Start);
1452
1453 while (toRead > 0) {
1454 /* Loop until the request is satisfied
1455 * (or no data available from below, possibly EOF).
1456 */
1457
1458 SEEK_DUMP (TrfInput; Loop_);
1459
1460 /* The position may be inside the buffer, and not at its start.
1461 * Remove the superfluous data now. There was no need to do it
1462 * earlier, as intervening seeks and writes could have discarded
1463 * the buffer completely, seeked back to an earlier point in it, etc.
1464 * We can be sure that the location is not behind its end!
1465 * And for an empty buffer location and buffer start are identical,
1466 * bypassing this code. See integrity constraints listed in the
1467 * description of Trf_TransformationInstance.
1468 */
1469
1470 if (trans->seekState.upLoc > trans->seekState.upBufStartLoc) {
1471 ResultDiscardAtStart (&trans->result,
1472 trans->seekState.upLoc - trans->seekState.upBufStartLoc);
1473 }
1474
1475 /* Assertion: UpLoc == UpBufStartLoc now. */
1476
1477 SEEK_DUMP (TrfInput; Disc<);
1478
1479 copied = ResultCopy (&trans->result, (unsigned char*) buf, toRead);
1480 toRead -= copied;
1481 buf += copied;
1482 gotBytes += copied;
1483 trans->seekState.upLoc += copied;
1484
1485 SEEK_DUMP (TrfInput; Copy<);
1486
1487 if (toRead == 0) {
1488 PRINT ("Got %d, satisfied from result buffer\n", gotBytes); FL;
1489 DONE (TrfInput);
1490 return gotBytes;
1491 }
1492
1493 /* The buffer is exhausted, but the caller wants even more. We now have
1494 * to go to the underlying channel, get more bytes and then transform
1495 * them for delivery. We may not get that we want (full EOF or temporary
1496 * out of data). This part has to manipulate the various seek locations
1497 * in a more complicated way to keep everything in sync.
1498 */
1499
1500 /* Assertion: UpLoc == UpBufEndLoc now (and == UpBufStartLoc).
1501 * Additionally: UP_CONVERT (DownLoc - AheadOffset) == BufEndLoc
1502 */
1503
1504 /*
1505 * Length (trans->result) == 0, toRead > 0 here Use 'buf'! as target
1506 * to store the intermediary information read from the parent channel.
1507 *
1508 * Ask the transform how much data it allows us to read from
1509 * the underlying channel. This feature allows the transform to
1510 * signal EOF upstream although there is none downstream. Useful
1511 * to control an unbounded 'fcopy' for example, either through counting
1512 * bytes, or by pattern matching.
1513 */
1514
1515 if (trans->in.vectors->maxReadProc == (Trf_QueryMaxRead*) NULL)
1516 maxRead = -1;
1517 else
1518 maxRead = trans->in.vectors->maxReadProc (trans->in.control,
1519 trans->clientData);
1520
1521 if (maxRead >= 0) {
1522 if (maxRead < toRead) {
1523 toRead = maxRead;
1524 }
1525 } /* else: 'maxRead < 0' == Accept the current value of toRead */
1526
1527 if (toRead <= 0) {
1528 PRINT ("Got %d, constrained by script\n", gotBytes); FL;
1529 DONE (TrfInput);
1530 return gotBytes;
1531 }
1532
1533 PRINT ("Read from parent %p\n", parent);
1534 IN; IN;
1535
1536 read = READ (trans, buf, toRead);
1537
1538 OT; OT;
1539 PRINT ("................\n");
1540 /*PRTSTR ("Retrieved = {%d, \"%s\"}\n", read, buf);*/
1541
1542 PRINT ("Retrieved = %d {\n", read);
1543 DUMP (read, buf);
1544 PRINT ("}\n");
1545 STREAM_IN (trans, read, buf);
1546
1547 if (read < 0) {
1548 /* Report errors to caller.
1549 * The state of the seek system is unchanged!
1550 */
1551
1552 if ((Tcl_GetErrno () == EAGAIN) && (gotBytes > 0)) {
1553 /* EAGAIN is a special situation. If we had some data
1554 * before we report that instead of the request to re-try.
1555 */
1556
1557 PRINT ("Got %d, read < 0, <EAGAIN>\n", gotBytes);
1558 FL; DONE (TrfInput);
1559 return gotBytes;
1560 }
1561
1562 *errorCodePtr = Tcl_GetErrno ();
1563
1564 PRINT ("Got %d, read < 0, report error %d\n", gotBytes, *errorCodePtr);
1565 FL; DONE (TrfInput);
1566 return -1;
1567 }
1568
1569 if (read == 0) {
1570 /* Check wether we hit on EOF in 'parent' or
1571 * not. If not differentiate between blocking and
1572 * non-blocking modes. In non-blocking mode we ran
1573 * temporarily out of data. Signal this to the caller
1574 * via EWOULDBLOCK and error return (-1). In the other
1575 * cases we simply return what we got and let the
1576 * caller wait for more. On the other hand, if we got
1577 * an EOF we have to convert and flush all waiting
1578 * partial data.
1579 */
1580
1581 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
1582 */
1583 if (! Tcl_Eof (parent)) {
1584 /* The state of the seek system is unchanged! */
1585
1586 if (gotBytes == 0 && trans->flags & CHANNEL_ASYNC) {
1587 *errorCodePtr = EWOULDBLOCK;
1588
1589 PRINT ("Got %d, report EWOULDBLOCK\n", gotBytes); FL;
1590 DONE (TrfInput);
1591 return -1;
1592 } else {
1593 PRINT ("(Got = %d || not async)\n", gotBytes); FL;
1594 DONE (TrfInput);
1595 return gotBytes;
1596 }
1597 } else {
1598 PRINT ("EOF in downstream channel\n"); FL;
1599 if (trans->readIsFlushed) {
1600 /* The state of the seek system is unchanged! */
1601 /* already flushed, nothing to do anymore */
1602 PRINT ("Got %d, !read flushed\n", gotBytes); FL;
1603 DONE (TrfInput);
1604 return gotBytes;
1605 }
1606
1607 /* Now this is a bit different. The partial data waiting is converted
1608 * and returned. So the 'AheadOffset' changes despite the location
1609 * downstream not changing at all. It is now the negative of its
1610 * additive inverse modulo 'numBytesDown':
1611 * -((-k)%n) == -((n-1)-k) == k+1-n.
1612 */
1613
1614 PRINT ("in_.flushproc\n"); FL;
1615
1616 trans->readIsFlushed = 1;
1617 trans->lastStored = 0;
1618
1619 res = trans->in.vectors->flushProc (trans->in.control,
1620 (Tcl_Interp*) NULL,
1621 trans->clientData);
1622 if (trans->seekState.allowed &&
1623 trans->seekState.used.numBytesDown > 1) {
1624 trans->seekState.aheadOffset += -trans->seekState.used.numBytesDown;
1625 }
1626
1627 SEEK_DUMP (TrfInput; AhdC<);
1628
1629 if (ResultLength (&trans->result) == 0) {
1630 /* we had nothing to flush */
1631 PRINT ("Got %d, read flushed / no result\n", gotBytes); FL;
1632 DONE (TrfInput);
1633 return gotBytes;
1634 }
1635 continue; /* at: while (toRead > 0) */
1636 }
1637 } /* read == 0 */
1638
1639 /* Transform the read chunk, which was not empty.
1640 * The transformation processes 'read + aheadOffset' bytes.
1641 * So UP_CONVERT (read+ahead) == #bytes produced == ResultLength!
1642 * And (read+ahead) % #down == #bytes now waiting == new ahead.
1643 */
1644
1645 SEEK_DUMP (TrfInput; Read<);
1646 trans->lastStored = 0;
1647
1648 if (trans->in.vectors->convertBufProc){
1649 PRINT ("in_.convertbufproc\n"); FL;
1650
1651 res = trans->in.vectors->convertBufProc (trans->in.control,
1652 (unsigned char*) buf, read,
1653 (Tcl_Interp*) NULL,
1654 trans->clientData);
1655 } else {
1656 PRINT ("in_.convertproc\n"); FL;
1657
1658 res = TCL_OK;
1659 for (i=0; i < read; i++) {
1660 res = trans->in.vectors->convertProc (trans->in.control, buf [i],
1661 (Tcl_Interp*) NULL,
1662 trans->clientData);
1663 if (res != TCL_OK) {
1664 break;
1665 }
1666 }
1667 }
1668
1669 if (res != TCL_OK) {
1670 *errorCodePtr = EINVAL;
1671 PRINT ("Got %d, report error in transform (EINVAL)\n", gotBytes); FL;
1672 DONE (TrfInput);
1673 return -1;
1674 }
1675
1676 /* Assert: UP_CONVERT (read+ahead) == ResultLength! */
1677
1678 trans->seekState.downLoc += read;
1679
1680 if (trans->seekState.allowed) {
1681 trans->seekState.aheadOffset += (read % trans->seekState.used.numBytesDown);
1682 trans->seekState.aheadOffset %= trans->seekState.used.numBytesDown;
1683 }
1684
1685 } /* while toRead > 0 */
1686
1687 SEEK_DUMP (TrfInput; Loop<);
1688
1689 PRINT ("Got %d, after loop\n", gotBytes); FL;
1690 DONE (TrfInput);
1691 return gotBytes;
1692 }
1693
1694 /*
1695 *------------------------------------------------------*
1696 *
1697 * TrfOutput --
1698 *
1699 * ------------------------------------------------*
1700 * Called by the generic IO system to convert data
1701 * waiting to be written.
1702 * ------------------------------------------------*
1703 *
1704 * Sideeffects:
1705 * As defined by the transformation.
1706 *
1707 * Result:
1708 * A transformed buffer.
1709 *
1710 *------------------------------------------------------*
1711 */
1712
1713 static int
TrfOutput(instanceData,buf,toWrite,errorCodePtr)1714 TrfOutput (instanceData, buf, toWrite, errorCodePtr)
1715 ClientData instanceData;
1716 CONST84 char* buf;
1717 int toWrite;
1718 int* errorCodePtr;
1719 {
1720 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
1721 int i, res;
1722 Tcl_Channel parent;
1723
1724 START (TrfOutput);
1725
1726 parent = DOWNC (trans);
1727
1728 /* should assert (trans->mode & TCL_WRITABLE) */
1729
1730 /*
1731 * transformation results are automatically written to
1732 * the parent channel ('PutDestination' was configured
1733 * as write procedure in 'AttachTransform').
1734 */
1735
1736 if (toWrite == 0) {
1737 /* Nothing came in to write, ignore the call
1738 */
1739
1740 PRINT ("Nothing to write\n"); FL; DONE (TrfOutput);
1741 return 0;
1742 }
1743
1744 SEEK_DUMP (TrfOutput; Start);
1745
1746 /* toWrite / seekState.used.numBytesTransform = #tuples converted.
1747 * toWrite % seekState.used.numBytesTransform = #Bytes waiting in the transform.
1748 */
1749
1750 SeekSynchronize (trans, parent);
1751
1752 SEEK_DUMP (TrfOutput; Syncd);
1753
1754 trans->lastWritten = 0;
1755
1756 if (trans->out.vectors->convertBufProc){
1757 PRINT ("out.convertbufproc\n"); FL;
1758
1759 res = trans->out.vectors->convertBufProc (trans->out.control,
1760 (unsigned char*) buf, toWrite,
1761 (Tcl_Interp*) NULL,
1762 trans->clientData);
1763 } else {
1764 PRINT ("out.convertproc\n"); FL;
1765
1766 res = TCL_OK;
1767 for (i=0; i < toWrite; i++) {
1768 res = trans->out.vectors->convertProc (trans->out.control, buf [i],
1769 (Tcl_Interp*) NULL,
1770 trans->clientData);
1771 if (res != TCL_OK) {
1772 break;
1773 }
1774 }
1775 }
1776
1777 if (res != TCL_OK) {
1778 *errorCodePtr = EINVAL;
1779 PRINT ("error EINVAL\n"); FL; DONE (TrfInput);
1780 return -1;
1781 }
1782
1783 /* Update seek state to new location
1784 * Assert: lastWritten == TRF_DOWN_CONVERT (trans, toWrite)
1785 */
1786
1787 trans->seekState.upLoc += toWrite;
1788 trans->seekState.upBufStartLoc = trans->seekState.upLoc;
1789 trans->seekState.upBufEndLoc = trans->seekState.upLoc;
1790 trans->seekState.downLoc += trans->lastWritten;
1791 trans->lastWritten = 0;
1792
1793 SEEK_DUMP (TrfOutput; Done_);
1794
1795 /* In the last statement above the integer division automatically
1796 * strips off the #bytes waiting in the transform.
1797 */
1798
1799 PRINT ("Written: %d\n", toWrite); FL; DONE (TrfOutput);
1800 return toWrite;
1801 }
1802
1803 /*
1804 *------------------------------------------------------*
1805 *
1806 * TrfSeek --
1807 *
1808 * ------------------------------------------------*
1809 * This procedure is called by the generic IO level
1810 * to move the access point in a channel.
1811 * ------------------------------------------------*
1812 *
1813 * Sideeffects:
1814 * Moves the location at which the channel
1815 * will be accessed in future operations.
1816 * Flushes all transformation buffers, then
1817 * forwards it to the underlying channel.
1818 *
1819 * Result:
1820 * -1 if failed, the new position if
1821 * successful. An output argument contains
1822 * the POSIX error code if an error
1823 * occurred, or zero.
1824 *
1825 *------------------------------------------------------*
1826 */
1827
1828 static int
TrfSeek(instanceData,offset,mode,errorCodePtr)1829 TrfSeek (instanceData, offset, mode, errorCodePtr)
1830 ClientData instanceData; /* The channel to manipulate */
1831 long offset; /* Size of movement. */
1832 int mode; /* How to move */
1833 int* errorCodePtr; /* Location of error flag. */
1834 {
1835 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
1836 int result;
1837 int newLoc;
1838
1839 START (TrfSeek);
1840 PRINT ("(Mode = %d, Offset = %ld)\n", mode, offset); FL;
1841
1842 /*
1843 * Several things to look at before deciding what to do.
1844 * Is it a tell request ?
1845 * Is the channel unseekable ?
1846 * If not, are we in pass-down mode ?
1847 * If not, check buffer boundaries, etc. before discarding buffers, etc.
1848 */
1849
1850 if ((offset == 0) && (mode == SEEK_CUR)) {
1851 /* Tell location.
1852 */
1853
1854 PRINT ("[Tell], Location = %d\n", trans->seekState.upLoc); FL;
1855 DONE (TrfSeek);
1856 return trans->seekState.upLoc;
1857 }
1858
1859 if (!trans->seekState.allowed) {
1860 *errorCodePtr = EINVAL;
1861
1862 PRINT ("[Unseekable]\n"); FL; DONE (TrfSeek);
1863 return -1;
1864 }
1865
1866 /* Assert: seekState.allowed, numBytesDown > 0, numBytesTransform > 0 */
1867
1868 if (trans->seekCfg.identity) {
1869 /* Pass down mode. Pass request and record the change. This is used after
1870 * restoration of constrained seek to force the usage of a new zero-point.
1871 */
1872
1873 PRINT ("[Passing down]\n"); FL;
1874
1875 SeekClearBuffer (trans, TCL_WRITABLE | TCL_READABLE);
1876
1877 trans->seekState.changed = 1;
1878
1879 result = SEEK (trans, offset, mode);
1880 *errorCodePtr = (result == -1) ? Tcl_GetErrno () : 0;
1881
1882 SEEK_DUMP (TrfSeek; Pass<);
1883 DONE (TrfSeek);
1884 return result;
1885 }
1886
1887 /* Constrained seeking, as specified by the transformation.
1888 */
1889
1890 if (mode == SEEK_SET) {
1891 /* Convert and handle absolute from start as relative to current
1892 * location.
1893 */
1894
1895 PRINT ("[Seek from start] => Seek relative\n"); FL;
1896 result = TrfSeek (trans, offset - trans->seekState.upLoc, SEEK_CUR,
1897 errorCodePtr);
1898 DONE (TrfSeek);
1899 return result;
1900 }
1901
1902 if (mode == SEEK_END) {
1903 /* Can't do that right now! TODO */
1904 *errorCodePtr = EINVAL;
1905
1906 PRINT ("[Seek from end not available]"); FL; DONE (TrfSeek);
1907 return -1;
1908 }
1909
1910 /* Seeking relative to the current location.
1911 */
1912
1913 newLoc = trans->seekState.upLoc + offset;
1914
1915 if (newLoc % trans->seekState.used.numBytesTransform) {
1916 /* Seek allowed only to locations which are multiples of the input.
1917 */
1918
1919 *errorCodePtr = EINVAL;
1920
1921 PRINT ("Seek constrained to multiples of input tuples\n"); FL;
1922 DONE (TrfSeek);
1923 return -1;
1924 }
1925
1926 if (newLoc < 0) {
1927 *errorCodePtr = EINVAL;
1928
1929 PRINT ("[Seek relative], cannot seek before start of stream\n"); FL;
1930 DONE (TrfSeek);
1931 return -1;
1932 }
1933
1934 if ((newLoc < trans->seekState.upBufStartLoc) ||
1935 (trans->seekState.upBufEndLoc <= newLoc)) {
1936 /* We are seeking out of the read buffer.
1937 * Discard it, adjust our position and seek the channel below to the
1938 * equivalent position.
1939 */
1940
1941 int offsetDown, newDownLoc;
1942
1943 PRINT ("[Seek relative], beyond read buffer\n"); FL;
1944
1945 newDownLoc = trans->seekState.downZero + TRF_DOWN_CONVERT (trans, newLoc);
1946 offsetDown = newDownLoc - trans->seekState.downLoc;
1947
1948 SeekClearBuffer (trans, TCL_WRITABLE | TCL_READABLE);
1949
1950 if (offsetDown != 0) {
1951 result = SEEK (trans, offsetDown, SEEK_CUR);
1952 *errorCodePtr = (result == -1) ? Tcl_GetErrno () : 0;
1953 }
1954
1955 trans->seekState.downLoc += offsetDown;
1956 trans->seekState.upLoc = newLoc;
1957 trans->seekState.upBufStartLoc = newLoc;
1958 trans->seekState.upBufEndLoc = newLoc;
1959
1960 SEEK_DUMP (TrfSeek; NoBuf);
1961 DONE (TrfSeek);
1962 return newLoc;
1963 }
1964
1965 /* We are still inside the buffer, adjust the position
1966 * and clear out incomplete data waiting in the write
1967 * buffers, they are now invalid.
1968 */
1969
1970 SeekClearBuffer (trans, TCL_WRITABLE);
1971 trans->seekState.upLoc = newLoc;
1972
1973 SEEK_DUMP (TrfSeek; Base_);
1974 DONE (TrfSeek);
1975 return newLoc;
1976 }
1977
1978 /*
1979 *------------------------------------------------------*
1980 *
1981 * TrfWatch --
1982 *
1983 * ------------------------------------------------*
1984 * Initialize the notifier to watch Tcl_Files from
1985 * this channel.
1986 * ------------------------------------------------*
1987 *
1988 * Sideeffects:
1989 * Sets up the notifier so that a future
1990 * event on the channel will be seen by Tcl.
1991 *
1992 * Result:
1993 * None.
1994 *
1995 *------------------------------------------------------*
1996 */
1997 /* ARGSUSED */
1998 static void
TrfWatch(instanceData,mask)1999 TrfWatch (instanceData, mask)
2000 ClientData instanceData; /* Channel to watch */
2001 int mask; /* Events of interest */
2002 {
2003 /*
2004 * 08/01/2000 - Completely rewritten to support as many versions of
2005 * the core and their different implementation s of stacked channels.
2006 */
2007 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
2008 * Added the comments. */
2009 /* The caller expressed interest in events occuring for this
2010 * channel. Instead of forwarding the call to the underlying
2011 * channel we now express our interest in events on that
2012 * channel. This will ripple through all stacked channels to
2013 * the bottom-most real one actually able to generate events
2014 * (files, sockets, pipes, ...). The improvement beyond the
2015 * simple forwarding is that the generated events will ripple
2016 * back up to us, until they reach the channel the user
2017 * expressed his interest in (via fileevent). This way the
2018 * low-level events are propagated upward to the place where
2019 * the real event script resides, something which does not
2020 * happen in the simple forwarding model. It loses these events.
2021 */
2022
2023 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
2024
2025 START (TrfWatch);
2026
2027 #ifndef USE_TCL_STUBS
2028 /* 8.0.x. Original patch. */
2029
2030 if (mask == trans->watchMask) {
2031 /* No changes in the expressed interest, skip this call.
2032 */
2033 DONE (TrfWatch);
2034 return;
2035 }
2036
2037 ChannelHandlerKS (trans, mask);
2038 #else
2039 /* 8.1. and up */
2040
2041 if ((trans->patchVariant == PATCH_ORIG) ||
2042 (trans->patchVariant == PATCH_82)) {
2043
2044 if (mask == trans->watchMask) {
2045 /* No changes in the expressed interest, skip this call.
2046 */
2047 DONE (TrfWatch);
2048 return;
2049 }
2050
2051 ChannelHandlerKS (trans, mask);
2052
2053 } else if (trans->patchVariant == PATCH_832) {
2054 /* 8.3.2 and up */
2055
2056 Tcl_DriverWatchProc* watchProc;
2057 Tcl_Channel parent;
2058
2059 trans->watchMask = mask;
2060
2061 /* No channel handlers any more. We will be notified automatically
2062 * about events on the channel below via a call to our
2063 * 'TransformNotifyProc'. But we have to pass the interest down now.
2064 * We are allowed to add additional 'interest' to the mask if we want
2065 * to. But this transformation has no such interest. It just passes
2066 * the request down, unchanged.
2067 */
2068
2069 parent = DOWNC (trans);
2070 watchProc = Tcl_ChannelWatchProc (Tcl_GetChannelType (parent));
2071
2072 (*watchProc) (Tcl_GetChannelInstanceData(parent), mask);
2073
2074 } else {
2075 Tcl_Panic ("Illegal value for 'patchVariant'");
2076 }
2077 #endif
2078
2079 /*
2080 * Management of the internal timer.
2081 */
2082
2083 if (!(mask & TCL_READABLE) || (ResultLength(&trans->result) == 0)) {
2084 /* A pending timer may exist, but either is there no (more)
2085 * interest in the events it generates or nothing is available
2086 * for reading. Remove it, if existing.
2087 */
2088
2089 TimerKill (trans);
2090 } else {
2091 /* There might be no pending timer, but there is interest in
2092 * readable events and we actually have data waiting, so
2093 * generate a timer to flush that if it does not exist.
2094 */
2095
2096 TimerSetup (trans);
2097 }
2098
2099 DONE (TrfWatch);
2100 }
2101
2102 /*
2103 *------------------------------------------------------*
2104 *
2105 * TrfGetFile --
2106 *
2107 * ------------------------------------------------*
2108 * Called from Tcl_GetChannelHandle to retrieve
2109 * OS specific file handle from inside this channel.
2110 * ------------------------------------------------*
2111 *
2112 * Sideeffects:
2113 * None.
2114 *
2115 * Result:
2116 * The appropriate Tcl_File or NULL if not
2117 * present.
2118 *
2119 *------------------------------------------------------*
2120 */
2121
2122 static int
TrfGetFile(instanceData,direction,handlePtr)2123 TrfGetFile (instanceData, direction, handlePtr)
2124 ClientData instanceData; /* Channel to query */
2125 int direction; /* Direction of interest */
2126 ClientData* handlePtr; /* Place to store the handle into */
2127 {
2128 /*
2129 * return handle belonging to parent channel
2130 */
2131
2132 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
2133 Tcl_Channel parent;
2134
2135 START (TrfGetFile);
2136
2137 parent = DOWNC (trans);
2138
2139 DONE (TrfGetFile);
2140 return Tcl_GetChannelHandle (parent, direction, handlePtr);
2141 }
2142
2143 /*
2144 *------------------------------------------------------*
2145 *
2146 * TrfSetOption --
2147 *
2148 * ------------------------------------------------*
2149 * Called by the generic layer to handle the reconfi-
2150 * guration of channel specific options. Unknown
2151 * options are passed downstream.
2152 * ------------------------------------------------*
2153 *
2154 * Sideeffects:
2155 * As defined by the channel downstream.
2156 *
2157 * Result:
2158 * A standard TCL error code.
2159 *
2160 *------------------------------------------------------*
2161 */
2162
2163 static int
TrfSetOption(instanceData,interp,optionName,value)2164 TrfSetOption (instanceData, interp, optionName, value)
2165 ClientData instanceData;
2166 Tcl_Interp* interp;
2167 CONST char* optionName;
2168 CONST char* value;
2169 {
2170 /* Recognized options:
2171 *
2172 * -seekpolicy Accepted values: unseekable, identity, {}
2173 */
2174
2175 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
2176
2177 START (TrfSetOption);
2178
2179 if (0 == strcmp (optionName, "-seekpolicy")) {
2180 /* The seekpolicy is about to be changed. Make sure that we got a valid
2181 * value and that it really changes the used policy. Failing the first
2182 * test causes an error, failing the second causes the system to silently
2183 * ignore this request. Reconfiguration will fail for a non-overidable
2184 * policy too.
2185 */
2186
2187 if (!trans->seekCfg.overideAllowed) {
2188 Tcl_SetErrno (EINVAL);
2189 Tcl_AppendResult (interp, "It is not allowed to overide ",
2190 "the seek policy used by this channel.", NULL);
2191 DONE (TrfSetOption);
2192 return TCL_ERROR;
2193 }
2194
2195 if (0 == strcmp (value, "unseekable")) {
2196 if (!trans->seekState.allowed) {
2197 /* Ignore the request if the channel already uses this policy.
2198 */
2199 DONE (TrfSetOption);
2200 return TCL_OK;
2201 }
2202
2203 TRF_SET_UNSEEKABLE (trans->seekState.used);
2204 trans->seekState.allowed = 0;
2205 trans->seekCfg.identity = 0;
2206
2207 /* Changed is not touched! We might have been forced to identity
2208 * before, and have to remember this for any restoration.
2209 */
2210
2211 } else if (0 == strcmp (value, "identity")) {
2212
2213 if (trans->seekState.allowed &&
2214 (trans->seekState.used.numBytesTransform == 1) &&
2215 (trans->seekState.used.numBytesDown == 1)) {
2216
2217 /* Ignore the request if the channel already uses this policy.
2218 */
2219 DONE (TrfSetOption);
2220 return TCL_OK;
2221 }
2222
2223 trans->seekState.used.numBytesTransform = 1;
2224 trans->seekState.used.numBytesDown = 1;
2225 trans->seekState.allowed = 1;
2226 trans->seekCfg.identity = 1;
2227 trans->seekState.changed = 0;
2228
2229 } else if (0 == strcmp (value, "")) {
2230 if ((trans->seekState.used.numBytesTransform ==
2231 trans->seekCfg.chosen.numBytesTransform) &&
2232 (trans->seekState.used.numBytesDown ==
2233 trans->seekCfg.chosen.numBytesDown)) {
2234 /* Ignore the request if the channel already uses hios chosen policy.
2235 */
2236 DONE (TrfSetOption);
2237 return TCL_OK;
2238 }
2239
2240 trans->seekState.used.numBytesTransform =
2241 trans->seekCfg.chosen.numBytesTransform;
2242
2243 trans->seekState.used.numBytesDown =
2244 trans->seekCfg.chosen.numBytesDown;
2245
2246 trans->seekState.allowed = !TRF_IS_UNSEEKABLE (trans->seekState.used);
2247
2248 if (trans->seekState.changed) {
2249 /* Define new base location. Resync up and down to get the
2250 * proper location without read-ahead. Reinitialize the
2251 * upper location.
2252 */
2253
2254 Tcl_Channel parent = DOWNC (trans);
2255 SeekSynchronize (trans, parent);
2256 trans->seekState.downLoc = TELL (trans);
2257
2258 #ifdef USE_TCL_STUBS
2259 if (trans->patchVariant == PATCH_832) {
2260 trans->seekState.downLoc -= Tcl_ChannelBuffered (parent);
2261 }
2262 #endif
2263 trans->seekState.downZero = trans->seekState.downLoc;
2264 trans->seekState.aheadOffset = 0;
2265
2266 trans->seekState.upLoc = 0;
2267 trans->seekState.upBufStartLoc = 0;
2268 trans->seekState.upBufEndLoc = ResultLength (&trans->result);
2269 }
2270
2271 trans->seekCfg.identity = 0;
2272 trans->seekState.changed = 0;
2273
2274 } else {
2275 Tcl_SetErrno (EINVAL);
2276 Tcl_AppendResult (interp, "Invalid value \"", value,
2277 "\", must be one of 'unseekable', 'identity' or ''.",
2278 NULL);
2279 DONE (TrfSetOption);
2280 return TCL_ERROR;
2281 }
2282
2283 } else {
2284 int res;
2285 res = SETOPT (interp, trans, optionName, value);
2286 DONE (TrfSetOption);
2287 return res;
2288 }
2289
2290 DONE (TrfSetOption);
2291 return TCL_OK;
2292 }
2293
2294 /*
2295 *------------------------------------------------------*
2296 *
2297 * TrfGetOption --
2298 *
2299 * ------------------------------------------------*
2300 * Called by generic layer to handle requests for
2301 * the values of channel specific options. As this
2302 * channel type does not have such, it simply passes
2303 * all requests downstream.
2304 * ------------------------------------------------*
2305 *
2306 * Sideeffects:
2307 * Adds characters to the DString refered by
2308 * 'dsPtr'.
2309 *
2310 * Result:
2311 * A standard TCL error code.
2312 *
2313 *------------------------------------------------------*
2314 */
2315
2316 static int
TrfGetOption(instanceData,interp,optionName,dsPtr)2317 TrfGetOption (instanceData, interp, optionName, dsPtr)
2318 ClientData instanceData;
2319 Tcl_Interp* interp;
2320 CONST84 char* optionName;
2321 Tcl_DString* dsPtr;
2322 {
2323 /* Recognized options:
2324 *
2325 * -seekcfg
2326 * -seekstate
2327 * -seekpolicy
2328 */
2329
2330 TrfTransformationInstance* trans = (TrfTransformationInstance*) instanceData;
2331
2332 if (optionName == (char*) NULL) {
2333 /* A list of options and their values was requested,
2334 */
2335
2336 Tcl_Obj* tmp;
2337 char policy [20];
2338
2339 SeekPolicyGet (trans, policy);
2340 Tcl_DStringAppendElement (dsPtr, "-seekpolicy");
2341 Tcl_DStringAppendElement (dsPtr, policy);
2342
2343 Tcl_DStringAppendElement (dsPtr, "-seekcfg");
2344 tmp = SeekConfigGet (interp, &trans->seekCfg);
2345 Tcl_DStringAppendElement (dsPtr, Tcl_GetStringFromObj (tmp, NULL));
2346 Tcl_DecrRefCount (tmp);
2347
2348 Tcl_DStringAppendElement (dsPtr, "-seekstate");
2349 tmp = SeekStateGet (interp, &trans->seekState);
2350 Tcl_DStringAppendElement (dsPtr, Tcl_GetStringFromObj (tmp, NULL));
2351 Tcl_DecrRefCount (tmp);
2352
2353 /* Pass the request down to all channels below so that we may a complete
2354 * state.
2355 */
2356
2357 return GETOPT (interp, trans, optionName, dsPtr);
2358
2359 } else if (0 == strcmp (optionName, "-seekpolicy")) {
2360 /* Deduce the policy in effect, use chosen/used
2361 * policy and identity to do this. Use a helper
2362 * procedure to allow easy reuse in the code above.
2363 */
2364
2365 char policy [20];
2366
2367 SeekPolicyGet (trans, policy);
2368 Tcl_DStringAppend (dsPtr, policy, -1);
2369 return TCL_OK;
2370
2371 } else if (0 == strcmp (optionName, "-seekcfg")) {
2372 Tcl_Obj* tmp;
2373
2374 tmp = SeekConfigGet (interp, &trans->seekCfg);
2375 Tcl_DStringAppend (dsPtr, Tcl_GetStringFromObj (tmp, NULL), -1);
2376 Tcl_DecrRefCount (tmp);
2377
2378 return TCL_OK;
2379 } else if (0 == strcmp (optionName, "-seekstate")) {
2380 Tcl_Obj* tmp;
2381
2382 tmp = SeekStateGet (interp, &trans->seekState);
2383 Tcl_DStringAppend (dsPtr, Tcl_GetStringFromObj (tmp, NULL), -1);
2384 Tcl_DecrRefCount (tmp);
2385
2386 return TCL_OK;
2387 } else {
2388 /* Unknown option. Pass it down to the channels below, maybe one
2389 * of them is able to handle this request.
2390 */
2391
2392 return GETOPT (interp, trans, optionName, dsPtr);
2393 #if 0
2394 Tcl_SetErrno (EINVAL);
2395 return Tcl_BadChannelOption (interp, optionName, "seekcfg seekstate");
2396 #endif
2397 }
2398 }
2399
2400 #ifdef USE_TCL_STUBS
2401 /*
2402 *------------------------------------------------------*
2403 *
2404 * TrfNotify --
2405 *
2406 * ------------------------------------------------*
2407 * Called by the generic layer of 8.3.2 and higher
2408 * to handle events coming from below. We simply pass
2409 * them upward.
2410 * ------------------------------------------------*
2411 *
2412 * Sideeffects:
2413 * None.
2414 *
2415 * Result:
2416 * The unchanged interest mask.
2417 *
2418 *------------------------------------------------------*
2419 */
2420 static int
TrfNotify(instanceData,interestMask)2421 TrfNotify (instanceData, interestMask)
2422 ClientData instanceData;
2423 int interestMask;
2424 {
2425 /*
2426 * An event occured in the underlying channel. This transformation
2427 * doesn't process such events thus returns the incoming mask
2428 * unchanged.
2429 *
2430 * We do delete an existing timer. It was not fired, yet we are
2431 * here, so the channel below generated such an event and we don't
2432 * have to. The renewal of the interest after the execution of
2433 * channel handlers will eventually cause us to recreate the timer
2434 * (in TrfWatch).
2435 */
2436
2437 TimerKill ((TrfTransformationInstance*) instanceData);
2438 return interestMask;
2439 }
2440 #endif
2441
2442 /*
2443 *------------------------------------------------------*
2444 *
2445 * TransformImmediate --
2446 *
2447 * ------------------------------------------------*
2448 * Read from source, apply the specified transformation
2449 * and write the result to destination.
2450 * ------------------------------------------------*
2451 *
2452 * Sideeffects:
2453 * The access points of source and destination
2454 * change, data is added to destination too.
2455 *
2456 * Result:
2457 * A standard Tcl error code.
2458 *
2459 *------------------------------------------------------* */
2460
2461 static int
TransformImmediate(interp,entry,source,destination,in,optInfo)2462 TransformImmediate (interp, entry, source, destination, in, optInfo)
2463 Tcl_Interp* interp;
2464 Trf_RegistryEntry* entry;
2465 Tcl_Channel source;
2466 Tcl_Channel destination;
2467 struct Tcl_Obj* CONST in;
2468 Trf_Options optInfo;
2469 {
2470 Trf_Vectors* v;
2471 Trf_ControlBlock control;
2472 int res = TCL_OK;
2473
2474 ResultBuffer r;
2475
2476 START (TransformImmediate);
2477
2478 if (ENCODE_REQUEST (entry, optInfo)) {
2479 v = &(entry->trfType->encoder);
2480 } else {
2481 v = &(entry->trfType->decoder);
2482 }
2483
2484 /* Take care of output (channel vs. interpreter result area).
2485 */
2486
2487 if (destination == (Tcl_Channel) NULL) {
2488 ResultInit (&r);
2489
2490 PRINT ("___.createproc\n"); FL;
2491 control = v->createProc ((ClientData) &r, PutInterpResult,
2492 optInfo, interp,
2493 entry->trfType->clientData);
2494 } else {
2495 PRINT ("___.createproc\n"); FL;
2496 control = v->createProc ((ClientData) destination, PutDestinationImm,
2497 optInfo, interp,
2498 entry->trfType->clientData);
2499 }
2500
2501 if (control == (Trf_ControlBlock) NULL) {
2502 DONE (TransformImmediate);
2503 return TCL_ERROR;
2504 }
2505
2506
2507 /* Now differentiate between immediate value and channel as input.
2508 */
2509
2510 if (source == (Tcl_Channel) NULL) {
2511 /* Immediate value.
2512 * -- VERSION DEPENDENT CODE --
2513 */
2514 int length;
2515 unsigned char* buf;
2516
2517 buf = GET_DATA (in, &length);
2518 if (v->convertBufProc) {
2519 /* play it safe, use a copy, avoid clobbering the input. */
2520 unsigned char* tmp;
2521
2522 tmp = (unsigned char*) ckalloc (length);
2523 memcpy (tmp, buf, length);
2524
2525 PRINT ("___.convertbufproc\n"); FL;
2526
2527 res = v->convertBufProc (control, tmp, length, interp,
2528 entry->trfType->clientData);
2529 ckfree ((char*) tmp);
2530 } else {
2531 unsigned int i, c;
2532
2533 PRINT ("___.convertproc\n"); FL;
2534
2535 for (i=0; i < ((unsigned int) length); i++) {
2536 c = buf [i];
2537 res = v->convertProc (control, c, interp,
2538 entry->trfType->clientData);
2539
2540 if (res != TCL_OK)
2541 break;
2542 }
2543 }
2544
2545 if (res == TCL_OK) {
2546 PRINT ("___.flushproc\n"); FL;
2547
2548 res = v->flushProc (control, interp, entry->trfType->clientData);
2549 }
2550 } else {
2551 /* Read from channel.
2552 */
2553
2554 unsigned char* buf;
2555 int actuallyRead;
2556
2557 buf = (unsigned char*) ckalloc (READ_CHUNK_SIZE);
2558
2559 while (1) {
2560 if (Tcl_Eof (source))
2561 break;
2562
2563 actuallyRead = Tcl_Read (source, (char*) buf, READ_CHUNK_SIZE);
2564
2565 if (actuallyRead <= 0)
2566 break;
2567
2568 if (v->convertBufProc) {
2569 PRINT ("___.convertbufproc\n"); FL;
2570
2571 res = v->convertBufProc (control, buf, actuallyRead, interp,
2572 entry->trfType->clientData);
2573 } else {
2574 unsigned int i, c;
2575
2576 PRINT ("___.convertproc\n"); FL;
2577
2578 for (i=0; i < ((unsigned int) actuallyRead); i++) {
2579 c = buf [i];
2580 res = v->convertProc (control, c, interp,
2581 entry->trfType->clientData);
2582
2583 if (res != TCL_OK)
2584 break;
2585 }
2586 }
2587
2588 if (res != TCL_OK)
2589 break;
2590 }
2591
2592 ckfree ((char*) buf);
2593
2594 if (res == TCL_OK)
2595 res = v->flushProc (control, interp, entry->trfType->clientData);
2596 }
2597
2598 PRINT ("___.deleteproc\n"); FL;
2599 v->deleteProc (control, entry->trfType->clientData);
2600
2601
2602 if (destination == (Tcl_Channel) NULL) {
2603 /* Now write into interpreter result area.
2604 */
2605
2606 if (res == TCL_OK) {
2607 Tcl_ResetResult (interp);
2608
2609 if (r.buf != NULL) {
2610 Tcl_Obj* o = NEW_DATA (r);
2611 Tcl_IncrRefCount (o);
2612 Tcl_SetObjResult (interp, o);
2613 Tcl_DecrRefCount (o);
2614 }
2615 }
2616 ResultClear (&r);
2617 }
2618
2619 DONE (TransformImmediate);
2620 return res;
2621 }
2622
2623 /*
2624 *------------------------------------------------------*
2625 *
2626 * AttachTransform --
2627 *
2628 * ------------------------------------------------*
2629 * Create an instance of a transformation and
2630 * associate as filter it with the specified channel.
2631 * ------------------------------------------------*
2632 *
2633 * Sideeffects:
2634 * Allocates memory, changes the internal
2635 * state of the channel.
2636 *
2637 * Result:
2638 * A standard Tcl error code.
2639 *
2640 *------------------------------------------------------*
2641 */
2642
2643 static int
AttachTransform(entry,baseOpt,optInfo,interp)2644 AttachTransform (entry, baseOpt, optInfo, interp)
2645 Trf_RegistryEntry* entry;
2646 Trf_BaseOptions* baseOpt;
2647 Trf_Options optInfo;
2648 Tcl_Interp* interp;
2649 {
2650 TrfTransformationInstance* trans;
2651
2652 trans = NEW_TRANSFORM;
2653
2654 START (AttachTransform);
2655
2656 #ifdef TRF_STREAM_DEBUG
2657 trans->inCounter = 0;
2658 trans->outCounter = 0;
2659 trans->name = (char*) entry->trfType->name;
2660 #endif
2661 #ifdef USE_TCL_STUBS
2662 trans->patchVariant = entry->registry->patchVariant;
2663 #endif
2664
2665 /* trans->standard.typePtr = entry->transType; */
2666 trans->clientData = entry->trfType->clientData;
2667
2668 if (trans->patchVariant == PATCH_832) {
2669 trans->parent = Tcl_GetTopChannel (baseOpt->attach);
2670 } else {
2671 trans->parent = baseOpt->attach;
2672 }
2673
2674 trans->readIsFlushed = 0;
2675
2676 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
2677 */
2678 trans->flags = 0;
2679 trans->watchMask = 0;
2680
2681 /* 03/28/2000 Added by DNew@Invisible.Net because Purify says so. */
2682 trans->lastStored = 0;
2683
2684 trans->mode = Tcl_GetChannelMode (baseOpt->attach);
2685 trans->timer = (Tcl_TimerToken) NULL;
2686
2687 if (ENCODE_REQUEST (entry, optInfo)) {
2688 /* ENCODE on write
2689 * DECODE on read
2690 */
2691
2692 trans->out.vectors = ((trans->mode & TCL_WRITABLE) ?
2693 &entry->trfType->encoder :
2694 NULL);
2695 trans->in.vectors = ((trans->mode & TCL_READABLE) ?
2696 &entry->trfType->decoder :
2697 NULL);
2698
2699 } else /* mode == DECODE */ {
2700 /* DECODE on write
2701 * ENCODE on read
2702 */
2703
2704 trans->out.vectors = ((trans->mode & TCL_WRITABLE) ?
2705 &entry->trfType->decoder :
2706 NULL);
2707 trans->in.vectors = ((trans->mode & TCL_READABLE) ?
2708 &entry->trfType->encoder :
2709 NULL);
2710 }
2711
2712 /* 'PutDestination' is ok for write, only read
2713 * requires 'PutTrans' and its internal buffer.
2714 */
2715
2716 if (trans->mode & TCL_WRITABLE) {
2717 PRINT ("out.createproc\n"); FL;
2718
2719 trans->out.control = trans->out.vectors->createProc ((ClientData) trans,
2720 PutDestination,
2721 optInfo, interp,
2722 trans->clientData);
2723
2724 if (trans->out.control == (Trf_ControlBlock) NULL) {
2725 ckfree ((char*) trans);
2726 DONE (AttachTransform);
2727 return TCL_ERROR;
2728 }
2729 }
2730
2731 if (trans->mode & TCL_READABLE) {
2732 PRINT ("in_.createproc\n"); FL;
2733
2734 trans->in.control = trans->in.vectors->createProc ((ClientData) trans,
2735 PutTrans,
2736 optInfo, interp,
2737 trans->clientData);
2738
2739 if (trans->in.control == (Trf_ControlBlock) NULL) {
2740 ckfree ((char*) trans);
2741 DONE (AttachTransform);
2742 return TCL_ERROR;
2743 }
2744 }
2745
2746 ResultInit (&trans->result);
2747 trans->result.seekState = &trans->seekState;
2748
2749 /*
2750 * Build channel from converter definition and stack it upon the one we
2751 * shall attach to.
2752 */
2753
2754 /* Discard information dangerous for the integrated patch.
2755 * (This makes sure that we don't miss any place using this pointer
2756 * without generating a crash (instead of some silent failure, like
2757 * thrashing far away memory)).
2758 */
2759
2760 #ifndef USE_TCL_STUBS
2761 trans->self = Tcl_StackChannel (interp, entry->transType,
2762 (ClientData) trans, trans->mode,
2763 trans->parent);
2764 #else
2765 if ((trans->patchVariant == PATCH_ORIG) ||
2766 (trans->patchVariant == PATCH_832)) {
2767
2768 trans->self = Tcl_StackChannel (interp, entry->transType,
2769 (ClientData) trans, trans->mode,
2770 trans->parent);
2771
2772 } else if (trans->patchVariant == PATCH_82) {
2773 trans->parent = NULL;
2774 trans->self = baseOpt->attach;
2775
2776 Tcl_StackChannel (interp, entry->transType,
2777 (ClientData) trans, trans->mode,
2778 trans->self);
2779 } else {
2780 Tcl_Panic ("Illegal value for 'patchVariant'");
2781 }
2782 #endif
2783
2784 if (trans->self == (Tcl_Channel) NULL) {
2785 ckfree ((char*) trans);
2786 Tcl_AppendResult (interp, "internal error in Tcl_StackChannel",
2787 (char*) NULL);
2788 DONE (AttachTransform);
2789 return TCL_ERROR;
2790 }
2791
2792 /* Initialize the seek subsystem.
2793 */
2794
2795 PRINTLN ("Initialize Seeking");
2796 PRINTLN ("Copy configuration");
2797
2798 trans->seekCfg.natural.numBytesTransform =
2799 entry->trfType->naturalSeek.numBytesTransform;
2800
2801 trans->seekCfg.natural.numBytesDown =
2802 entry->trfType->naturalSeek.numBytesDown;
2803
2804 if (optInfo && (*OPT->seekQueryProc != (Trf_SeekQueryOptions*) NULL)) {
2805 PRINTLN ("Query seekQueryProc");
2806 (*OPT->seekQueryProc) (interp, optInfo, &trans->seekCfg.natural, CLT);
2807 }
2808
2809 PRINTLN ("Determine Policy");
2810 SeekCalculatePolicies (trans);
2811
2812 PRINTLN (" Initialize");
2813 SeekInitialize (trans);
2814
2815 /* Check for options overiding the policy. If they do despite being not
2816 * allowed to do so we have to remove the transformation and break it down.
2817 * We do this by calling 'Unstack', which does all the necessary things for
2818 * us.
2819 */
2820
2821 PRINTLN (" Policy options ?");
2822 if (baseOpt->policy != (Tcl_Obj*) NULL) {
2823 if (TCL_OK != TrfSetOption ((ClientData) trans, interp, "-seekpolicy",
2824 Tcl_GetStringFromObj (baseOpt->policy,
2825 NULL))) {
2826
2827 /* An error prevented setting a policy. Save the resulting error
2828 * message across the necessary unstacking of the now faulty
2829 * transformation.
2830 */
2831
2832 #if GT81
2833 Tcl_SavedResult ciSave;
2834
2835 Tcl_SaveResult (interp, &ciSave);
2836 Tcl_UnstackChannel (interp, trans->self);
2837 Tcl_RestoreResult (interp, &ciSave);
2838 #else
2839 Tcl_UnstackChannel (interp, trans->self);
2840 #endif
2841 DONE (AttachTransform);
2842 return TCL_ERROR;
2843 }
2844 }
2845
2846 /* Tcl_RegisterChannel (interp, new); */
2847 Tcl_AppendResult (interp, Tcl_GetChannelName (trans->self),
2848 (char*) NULL);
2849 DONE (AttachTransform);
2850 return TCL_OK;
2851 }
2852
2853 /*
2854 *------------------------------------------------------*
2855 *
2856 * PutDestination --
2857 *
2858 * ------------------------------------------------*
2859 * Handler used by a transformation to write its results.
2860 * ------------------------------------------------*
2861 *
2862 * Sideeffects:
2863 * Writes to the channel.
2864 *
2865 * Result:
2866 * A standard Tcl error code.
2867 *
2868 *------------------------------------------------------*
2869 */
2870
2871 static int
PutDestination(clientData,outString,outLen,interp)2872 PutDestination (clientData, outString, outLen, interp)
2873 ClientData clientData;
2874 unsigned char* outString;
2875 int outLen;
2876 Tcl_Interp* interp;
2877 {
2878 TrfTransformationInstance* trans = (TrfTransformationInstance*) clientData;
2879 int res;
2880 Tcl_Channel parent;
2881
2882 START (PutDestination);
2883 /*PRTSTR ("Data = {%d, \"%s\"}\n", outLen, outString);*/
2884 PRINT ("Data = %d {\n", outLen);
2885 DUMP (outLen, outString);
2886 PRINT ("}\n");
2887
2888 parent = DOWNC (trans);
2889
2890 trans->lastWritten += outLen;
2891
2892 res = WRITE (trans, (char*) outString, outLen);
2893
2894 if (res < 0) {
2895 if (interp) {
2896 Tcl_AppendResult (interp, "error writing \"",
2897 Tcl_GetChannelName (parent),
2898 "\": ", Tcl_PosixError (interp),
2899 (char*) NULL);
2900 }
2901 PRINT ("ERROR /written = %d, errno = %d, (%d) %s\n",
2902 res, Tcl_GetErrno (), EACCES, strerror (Tcl_GetErrno ()));
2903 DONE (PutDestination);
2904 return TCL_ERROR;
2905 }
2906
2907 DONE (PutDestination);
2908 return TCL_OK;
2909 }
2910
2911 /*
2912 *------------------------------------------------------*
2913 *
2914 * PutDestinationImm --
2915 *
2916 * ------------------------------------------------*
2917 * Handler used during an immediate transformation
2918 * to write its results into the -out channel.
2919 * ------------------------------------------------*
2920 *
2921 * Sideeffects:
2922 * Writes to the channel.
2923 *
2924 * Result:
2925 * A standard Tcl error code.
2926 *
2927 *------------------------------------------------------*
2928 */
2929
2930 static int
PutDestinationImm(clientData,outString,outLen,interp)2931 PutDestinationImm (clientData, outString, outLen, interp)
2932 ClientData clientData;
2933 unsigned char* outString;
2934 int outLen;
2935 Tcl_Interp* interp;
2936 {
2937 int res;
2938 Tcl_Channel destination = (Tcl_Channel) clientData;
2939
2940 START (PutDestinationImm);
2941 /*PRTSTR ("Data = {%d, \"%s\"}\n", outLen, outString);*/
2942 PRINT ("Data = %d {\n", outLen);
2943 DUMP (outLen, outString);
2944 PRINT ("}\n");
2945
2946 res = Tcl_Write (destination, (char*) outString, outLen);
2947
2948 if (res < 0) {
2949 if (interp) {
2950 Tcl_AppendResult (interp, "error writing \"",
2951 Tcl_GetChannelName (destination),
2952 "\": ", Tcl_PosixError (interp),
2953 (char*) NULL);
2954 }
2955 DONE (PutDestinationImm);
2956 return TCL_ERROR;
2957 }
2958
2959 DONE (PutDestinationImm);
2960 return TCL_OK;
2961 }
2962
2963 /*
2964 *------------------------------------------------------*
2965 *
2966 * PutTrans --
2967 *
2968 * ------------------------------------------------*
2969 * Handler used by a transformation to write its
2970 * results (to be read later). Used by transformations
2971 * acting as filter.
2972 * ------------------------------------------------*
2973 *
2974 * Sideeffects:
2975 * May allocate memory.
2976 *
2977 * Result:
2978 * A standard Tcl error code.
2979 *
2980 *------------------------------------------------------*
2981 */
2982
2983 static int
PutTrans(clientData,outString,outLen,interp)2984 PutTrans (clientData, outString, outLen, interp)
2985 ClientData clientData;
2986 unsigned char* outString;
2987 int outLen;
2988 Tcl_Interp* interp;
2989 {
2990 TrfTransformationInstance* trans = (TrfTransformationInstance*) clientData;
2991
2992 START (PutTrans);
2993 /*PRTSTR ("Data = {%d, \"%s\"}\n", outLen, outString);*/
2994 PRINT ("Data = %d {\n", outLen);
2995 DUMP (outLen, outString);
2996 PRINT ("}\n");
2997 STREAM_OUT (trans, outLen, outString);
2998
2999 trans->lastStored += outLen;
3000
3001 ResultAdd (&trans->result, outString, outLen);
3002
3003 DONE (PutTrans);
3004 return TCL_OK;
3005 }
3006
3007 /*
3008 *------------------------------------------------------*
3009 *
3010 * PutInterpResult --
3011 *
3012 * ------------------------------------------------*
3013 * Handler used by a transformation to write its
3014 * results into the interpreter result area.
3015 * ------------------------------------------------*
3016 *
3017 * Sideeffects:
3018 * changes the contents of the interpreter
3019 * result area.
3020 *
3021 * Result:
3022 * A standard Tcl error code.
3023 *
3024 *------------------------------------------------------*
3025 */
3026
3027 static int
PutInterpResult(clientData,outString,outLen,interp)3028 PutInterpResult (clientData, outString, outLen, interp)
3029 ClientData clientData;
3030 unsigned char* outString;
3031 int outLen;
3032 Tcl_Interp* interp;
3033 {
3034 ResultBuffer* r = (ResultBuffer*) clientData;
3035
3036 START (PutInterpResult);
3037 /*PRTSTR ("Data = {%d, \"%s\"}\n", outLen, outString);*/
3038 PRINT ("Data = %d {\n", outLen);
3039 DUMP (outLen, outString);
3040 PRINT ("}\n");
3041
3042 ResultAdd (r, outString, outLen);
3043
3044 DONE (PutInterpResult);
3045 return TCL_OK;
3046 }
3047
3048 /* 04/13/1999 Fileevent patch from Matt Newman <matt@novadigm.com>
3049 */
3050 /*
3051 *------------------------------------------------------*
3052 *
3053 * ChannelHandler --
3054 *
3055 * ------------------------------------------------*
3056 * Handler called by Tcl as a result of
3057 * Tcl_CreateChannelHandler - to inform us of activity
3058 * on the underlying channel.
3059 * ------------------------------------------------*
3060 *
3061 * Sideeffects:
3062 * May generate subsequent calls to
3063 * Tcl_NotifyChannel.
3064 *
3065 * Result:
3066 * None.
3067 *
3068 *------------------------------------------------------*
3069 */
3070
3071 static void
ChannelHandler(clientData,mask)3072 ChannelHandler (clientData, mask)
3073 ClientData clientData;
3074 int mask;
3075 {
3076 /*
3077 * An event occured in the underlying channel. Forward it to
3078 * ourself. This will either execute an attached event script
3079 * (fileevent) or an intermediate handler like this one propagating
3080 * the event further upward.
3081 *
3082 * This procedure is called only for the original and the 8.2
3083 * patch. The 8.2.3 patch uses a new vector in the driver to get and
3084 * handle events coming from below.
3085 */
3086
3087 TrfTransformationInstance* trans = (TrfTransformationInstance*) clientData;
3088
3089 #ifndef USE_TCL_STUBS
3090 /*
3091 * Core 8.0.x. Forward the event to ourselves.
3092 */
3093
3094 Tcl_NotifyChannel (trans->self, mask);
3095 #else
3096 /*
3097 * Check for the correct variants first. Forwarding the event is not
3098 * required for the 8.2 patch. For that variant the core,
3099 * i.e. Tcl_NotifyChannel loops over all channels in the stack by
3100 * itself.
3101 */
3102
3103 if (trans->patchVariant == PATCH_832) {
3104 Tcl_Panic ("Illegal value for 'patchVariant' in ChannelHandler");
3105 }
3106 if (trans->patchVariant == PATCH_ORIG) {
3107 Tcl_NotifyChannel (trans->self, mask);
3108 }
3109 #endif
3110
3111 /*
3112 * Check the I/O-Buffers of this channel for waiting information.
3113 * Setup a timer generating an artificial event for us if we have
3114 * such. We could call Tcl_NotifyChannel directly, but this would
3115 * starve other event sources, so a timer is used to prevent that.
3116 */
3117
3118 TimerKill (trans);
3119
3120 /* Check for waiting data, flush it out with a timer.
3121 */
3122
3123 #ifndef USE_TCL_STUBS
3124 if ((mask & TCL_READABLE) && ((ResultLength (&trans->result) > 0) ||
3125 (Tcl_InputBuffered (trans->self) > 0))) {
3126 TimerSetup (trans);
3127 }
3128 #else
3129 if (trans->patchVariant != PATCH_ORIG) {
3130 if ((mask & TCL_READABLE) && (ResultLength (&trans->result) > 0)) {
3131 TimerSetup (trans);
3132 }
3133 } else {
3134 if ((mask & TCL_READABLE) && ((ResultLength (&trans->result) > 0) ||
3135 (Tcl_InputBuffered (trans->self) > 0))) {
3136 TimerSetup (trans);
3137 }
3138 }
3139 #endif
3140 }
3141
3142 /*
3143 *------------------------------------------------------*
3144 *
3145 * ChannelHandlerTimer --
3146 *
3147 * ------------------------------------------------*
3148 * Called by the notifier (-> timer) to flush out
3149 * information waiting in channel buffers.
3150 * ------------------------------------------------*
3151 *
3152 * Sideeffects:
3153 * As of 'ChannelHandler'.
3154 *
3155 * Result:
3156 * None.
3157 *
3158 *------------------------------------------------------*
3159 */
3160
3161 static void
ChannelHandlerTimer(clientData)3162 ChannelHandlerTimer (clientData)
3163 ClientData clientData; /* Transformation to query */
3164 {
3165 TrfTransformationInstance* trans = (TrfTransformationInstance*) clientData;
3166
3167 trans->timer = (Tcl_TimerToken) NULL;
3168
3169 #ifndef USE_TCL_STUBS
3170 /* 8.0.x.
3171 * Use the channel handler itself to do the necessary actions
3172 */
3173
3174 ChannelHandler (clientData, trans->watchMask);
3175 #else
3176 if ((trans->patchVariant == PATCH_82) ||
3177 (trans->patchVariant == PATCH_832)) {
3178 /*
3179 * Use the standard notification mechanism to invoke all channel
3180 * handlers.
3181 */
3182 Tcl_NotifyChannel (trans->self, TCL_READABLE);
3183 } else {
3184 /* PATCH_ORIG, seee 8.0.x
3185 */
3186
3187 ChannelHandler (clientData, trans->watchMask);
3188 }
3189 #endif
3190 }
3191
3192 #ifdef USE_TCL_STUBS
3193 /*
3194 *------------------------------------------------------*
3195 *
3196 * DownSOpt --
3197 *
3198 * Helper procedure. Writes an option to the downstream channel.
3199 *
3200 * Sideeffects:
3201 * As of Tcl_SetChannelOption
3202 *
3203 * Result:
3204 * A standard tcl error code.
3205 *
3206 *------------------------------------------------------*
3207 */
3208
3209 static int
DownSOpt(interp,ctrl,optionName,value)3210 DownSOpt (interp, ctrl, optionName, value)
3211 Tcl_Interp* interp;
3212 TrfTransformationInstance* ctrl;
3213 CONST char* optionName;
3214 CONST char* value;
3215 {
3216 Tcl_Channel parent = DOWNC (ctrl);
3217
3218 if (ctrl->patchVariant == PATCH_832) {
3219 /*
3220 * The newly written patch forces direct use of the driver.
3221 */
3222
3223 Tcl_DriverSetOptionProc *setOptionProc =
3224 Tcl_ChannelSetOptionProc (Tcl_GetChannelType (parent));
3225
3226 if (setOptionProc != NULL) {
3227 return (*setOptionProc) (Tcl_GetChannelInstanceData (parent),
3228 interp, optionName, value);
3229 } else {
3230 return TCL_ERROR;
3231 }
3232
3233 } else {
3234 return Tcl_SetChannelOption (interp, parent, optionName, value);
3235 }
3236 }
3237
3238 /*
3239 *------------------------------------------------------*
3240 *
3241 * DownGOpt --
3242 *
3243 * Helper procedure. Reads options from the downstream channel.
3244 *
3245 * Sideeffects:
3246 * As of Tcl_GetChannelOption
3247 *
3248 * Result:
3249 * A standard tcl error code.
3250 *
3251 *------------------------------------------------------*
3252 */
3253
3254 static int
DownGOpt(interp,ctrl,optionName,dsPtr)3255 DownGOpt (interp, ctrl, optionName, dsPtr)
3256 Tcl_Interp* interp;
3257 TrfTransformationInstance* ctrl;
3258 CONST84 char* optionName;
3259 Tcl_DString* dsPtr;
3260 {
3261 Tcl_Channel parent = DOWNC (ctrl);
3262
3263 if (ctrl->patchVariant == PATCH_832) {
3264 /*
3265 * The newly written patch forces direct use of the driver.
3266 */
3267
3268 Tcl_DriverGetOptionProc *getOptionProc =
3269 Tcl_ChannelGetOptionProc (Tcl_GetChannelType (parent));
3270
3271 if (getOptionProc != NULL) {
3272 return (*getOptionProc) (Tcl_GetChannelInstanceData (parent),
3273 interp, optionName, dsPtr);
3274 }
3275
3276 /*
3277 * Downstream channel has no driver to get options. Fall back on
3278 * some default behaviour. A query for all options is ok. A
3279 * request for a specific unknown option OTOH has to fail.
3280 */
3281
3282 if (optionName == (char*) NULL) {
3283 return TCL_OK;
3284 } else {
3285 return TCL_ERROR;
3286 }
3287 } else {
3288 return Tcl_GetChannelOption (interp, parent, optionName, dsPtr);
3289 }
3290 }
3291
3292 /*
3293 *------------------------------------------------------*
3294 *
3295 * DownWrite --
3296 *
3297 * Helper procedure. Writes to the downstream channel.
3298 *
3299 * Sideeffects:
3300 * As of TclWrite / Tcl_WriteRaw
3301 *
3302 * Result:
3303 * The number of bytes written.
3304 *
3305 *------------------------------------------------------*
3306 */
3307
3308 static int
DownWrite(ctrl,buf,toWrite)3309 DownWrite (ctrl, buf, toWrite)
3310 TrfTransformationInstance* ctrl;
3311 char* buf;
3312 int toWrite;
3313 {
3314 Tcl_Channel parent = DOWNC (ctrl);
3315
3316 if (ctrl->patchVariant == PATCH_832) {
3317 /*
3318 * The newly written patch forces use of the new raw-API.
3319 */
3320
3321 PRINT ("WriteRaw %p %s\n", parent, Tcl_GetChannelType (parent)->typeName);
3322 return Tcl_WriteRaw (parent, buf, toWrite);
3323 } else {
3324 return Tcl_Write (parent, buf, toWrite);
3325 }
3326 return TCL_OK;
3327 }
3328
3329 /*
3330 *------------------------------------------------------*
3331 *
3332 * DownRead --
3333 *
3334 * Helper procedure. Reads from the downstream channel.
3335 *
3336 * Sideeffects:
3337 * As of TclRead / Tcl_ReadRaw
3338 *
3339 * Result:
3340 * The number of bytes read.
3341 *
3342 *------------------------------------------------------*
3343 */
3344
3345 static int
DownRead(ctrl,buf,toRead)3346 DownRead (ctrl, buf, toRead)
3347 TrfTransformationInstance* ctrl;
3348 char* buf;
3349 int toRead;
3350 {
3351 Tcl_Channel parent = DOWNC (ctrl);
3352
3353 if (ctrl->patchVariant == PATCH_832) {
3354 /*
3355 * The newly written patch forces use of the new raw-API.
3356 */
3357
3358 return Tcl_ReadRaw (parent, buf, toRead);
3359 } else {
3360 return Tcl_Read (parent, buf, toRead);
3361 }
3362 return TCL_OK;
3363 }
3364
3365 /*
3366 *------------------------------------------------------*
3367 *
3368 * DownSeek --
3369 *
3370 * Helper procedure. Asks the downstream channel
3371 * to seek, or for its current location.
3372 *
3373 * Sideeffects:
3374 * None.
3375 *
3376 * Result:
3377 * The location in the downstream channel
3378 *
3379 *------------------------------------------------------*
3380 */
3381
3382 static int
DownSeek(ctrl,offset,mode)3383 DownSeek (ctrl, offset, mode)
3384 TrfTransformationInstance* ctrl;
3385 int offset;
3386 int mode;
3387 {
3388 Tcl_Channel parent = DOWNC (ctrl);
3389
3390 if (ctrl->patchVariant == PATCH_832) {
3391 /*
3392 * The newly rewritten patch forces the transformation into
3393 * directly using the seek-proc of the downstream driver. Tcl_Seek
3394 * would compensate for the stack and cause and infinite recursion
3395 * blowing the stack.
3396 */
3397 #if TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 4
3398 const
3399 #endif
3400 Tcl_ChannelType* parentType = Tcl_GetChannelType (parent);
3401 Tcl_DriverSeekProc* parentSeekProc = Tcl_ChannelSeekProc (parentType);
3402 int errorCode;
3403
3404 if (parentSeekProc == (Tcl_DriverSeekProc*) NULL) {
3405 return -1;
3406 }
3407
3408 return (*parentSeekProc) (Tcl_GetChannelInstanceData (parent),
3409 offset, mode, &errorCode);
3410 }
3411
3412 /*
3413 * (ctrl->patchVariant == PATCH_ORIG)
3414 * (ctrl->patchVariant == PATCH_82)
3415 *
3416 * Both the original patch for stacked channels and rewritten
3417 * implementation for 8.2. have the same simple semantics for
3418 * getting at the location of the downstream channel.
3419 *
3420 * Just use the standard 'Tcl_Seek'.
3421 */
3422
3423 return (int) Tcl_Seek (parent, offset, mode);
3424 }
3425
3426 /*
3427 *------------------------------------------------------*
3428 *
3429 * DownChannel --
3430 *
3431 * Helper procedure. Finds the downstream channel.
3432 *
3433 * Sideeffects:
3434 * May modify 'self'.
3435 *
3436 * Result:
3437 * None.
3438 *
3439 *------------------------------------------------------*
3440 */
3441
3442 static Tcl_Channel
DownChannel(ctrl)3443 DownChannel (ctrl)
3444 TrfTransformationInstance* ctrl;
3445 {
3446 Tcl_Channel self;
3447 Tcl_Channel next;
3448
3449 if ((ctrl->patchVariant == PATCH_ORIG) ||
3450 (ctrl->patchVariant == PATCH_832)) {
3451 /*
3452 * Both the original patch for stacked channels and rewritten
3453 * implementation for 8.3.2. have simple semantics for getting at
3454 * the parent of a channel.
3455 */
3456
3457 return ctrl->parent;
3458 }
3459
3460 /*
3461 * The first rewrite of the stacked channel patch initially included
3462 * in 8.2. requires that a transformation searches it's channel in
3463 * the whole stack. Only for the versions of the core using this
3464 * implementation, 8.2 till 8.3.1, the comments below apply.
3465 */
3466
3467 /* The reason for the existence of this procedure is
3468 * the fact that stacking a transform over another
3469 * transform will leave our internal pointer unchanged,
3470 * and thus pointing to the new transform, and not the
3471 * Channel structure containing the saved state of this
3472 * transform. This is the price to pay for leaving
3473 * Tcl_Channel references intact. The only other solution
3474 * is an extension of Tcl_ChannelType with another driver
3475 * procedure to notify a Channel about the (un)stacking.
3476 *
3477 * It walks the chain of Channel structures until it
3478 * finds the one pointing having 'ctrl' as instanceData
3479 * and then returns the superceding channel to that.
3480 */
3481
3482 self = ctrl->self;
3483
3484 while ((ClientData) ctrl != Tcl_GetChannelInstanceData (self)) {
3485 next = Tcl_GetStackedChannel (self);
3486 if (next == (Tcl_Channel) NULL) {
3487 /* 09/24/1999 Unstacking bug, found by Matt Newman <matt@sensus.org>.
3488 *
3489 * We were unable to find the channel structure for this
3490 * transformation in the chain of stacked channel. This
3491 * means that we are currently in the process of unstacking
3492 * it *and* there were some bytes waiting which are now
3493 * flushed. In this situation the pointer to the channel
3494 * itself already refers to the parent channel we have to
3495 * write the bytes into, so we return that.
3496 */
3497 return ctrl->self;
3498 }
3499 self = next;
3500 }
3501
3502 return Tcl_GetStackedChannel (self);
3503 }
3504 #endif
3505
3506 /*
3507 *------------------------------------------------------*
3508 *
3509 * ResultClear --
3510 *
3511 * Deallocates any memory allocated by 'ResultAdd'.
3512 *
3513 * Sideeffects:
3514 * See above.
3515 *
3516 * Result:
3517 * None.
3518 *
3519 *------------------------------------------------------*
3520 */
3521
3522 static void
ResultClear(r)3523 ResultClear (r)
3524 ResultBuffer* r; /* Reference to the buffer to clear out */
3525 {
3526 r->used = 0;
3527
3528 if (r->allocated) {
3529 ckfree ((char*) r->buf);
3530 r->buf = (unsigned char*) NULL;
3531 r->allocated = 0;
3532 }
3533
3534 if (r->seekState != (SeekState*) NULL) {
3535 r->seekState->upBufStartLoc = r->seekState->upLoc;
3536 r->seekState->upBufEndLoc = r->seekState->upLoc;
3537 }
3538 }
3539
3540 /*
3541 *------------------------------------------------------*
3542 *
3543 * ResultInit --
3544 *
3545 * Initializes the specified buffer structure. The
3546 * structure will contain valid information for an
3547 * emtpy buffer.
3548 *
3549 * Sideeffects:
3550 * See above.
3551 *
3552 * Result:
3553 * None.
3554 *
3555 *------------------------------------------------------*
3556 */
3557
3558 static void
ResultInit(r)3559 ResultInit (r)
3560 ResultBuffer* r; /* Reference to the structure to initialize */
3561 {
3562 r->used = 0;
3563 r->allocated = 0;
3564 r->buf = (unsigned char*) NULL;
3565 r->seekState = (SeekState*) NULL;
3566 }
3567
3568 /*
3569 *------------------------------------------------------*
3570 *
3571 * ResultLength --
3572 *
3573 * Returns the number of bytes stored in the buffer.
3574 *
3575 * Sideeffects:
3576 * None.
3577 *
3578 * Result:
3579 * An integer, see above too.
3580 *
3581 *------------------------------------------------------*
3582 */
3583
3584 static int
ResultLength(r)3585 ResultLength (r)
3586 ResultBuffer* r; /* The structure to query */
3587 {
3588 return r->used;
3589 }
3590
3591 /*
3592 *------------------------------------------------------*
3593 *
3594 * ResultCopy --
3595 *
3596 * Copies the requested number of bytes from the
3597 * buffer into the specified array and removes them
3598 * from the buffer afterward. Copies less if there
3599 * is not enough data in the buffer.
3600 *
3601 * Sideeffects:
3602 * See above.
3603 *
3604 * Result:
3605 * The number of actually copied bytes,
3606 * possibly less than 'toRead'.
3607 *
3608 *------------------------------------------------------*
3609 */
3610
3611 static int
ResultCopy(r,buf,toRead)3612 ResultCopy (r, buf, toRead)
3613 ResultBuffer* r; /* The buffer to read from */
3614 unsigned char* buf; /* The buffer to copy into */
3615 int toRead; /* Number of requested bytes */
3616 {
3617 int copied;
3618
3619 START (ResultCopy);
3620 PRINT ("request = %d, have = %d\n", toRead, r->used); FL;
3621
3622 if (r->used == 0) {
3623 /* Nothing to copy in the case of an empty buffer.
3624 */
3625
3626 copied = 0;
3627 goto done;
3628 }
3629
3630 if (r->used == toRead) {
3631 /* We have just enough. Copy everything to the caller.
3632 */
3633
3634 memcpy ((VOID*) buf, (VOID*) r->buf, toRead);
3635 r->used = 0;
3636
3637 copied = toRead;
3638 goto done;
3639 }
3640
3641 if (r->used > toRead) {
3642 /* The internal buffer contains more than requested.
3643 * Copy the requested subset to the caller, and shift
3644 * the remaining bytes down.
3645 */
3646
3647 memcpy ((VOID*) buf, (VOID*) r->buf, toRead);
3648 memmove ((VOID*) r->buf, (VOID*) (r->buf + toRead), r->used - toRead);
3649
3650 r->used -= toRead;
3651
3652 copied = toRead;
3653 goto done;
3654 }
3655
3656 /* There is not enough in the buffer to satisfy the caller, so
3657 * take everything.
3658 */
3659
3660 memcpy ((VOID*) buf, (VOID*) r->buf, r->used);
3661 toRead = r->used;
3662 r->used = 0;
3663 copied = toRead;
3664
3665 /* -- common postwork code ------- */
3666
3667 done:
3668 if ((copied > 0) &&
3669 (r->seekState != (SeekState*) NULL)) {
3670 r->seekState->upBufStartLoc += copied;
3671 }
3672
3673 DONE (ResultCopy);
3674 return copied;
3675 }
3676
3677 /*
3678 *------------------------------------------------------*
3679 *
3680 * ResultDiscardAtStart --
3681 *
3682 * Removes the n bytes at the beginning of the buffer
3683 * from it. Clears the buffer if n is greater than
3684 * its length.
3685 *
3686 * Sideeffects:
3687 * See above.
3688 *
3689 * Result:
3690 * None.
3691 *
3692 *------------------------------------------------------*
3693 */
3694
3695 static void
ResultDiscardAtStart(r,n)3696 ResultDiscardAtStart (r, n)
3697 ResultBuffer* r; /* The buffer to manipulate */
3698 int n; /* Number of bytes to remove */
3699 {
3700 START (ResultDiscardAtStart);
3701 PRINT ("n = %d, have = %d\n", n, r->used); FL;
3702
3703 if (r->used == 0) {
3704 /* Nothing to remove in the case of an empty buffer.
3705 */
3706
3707 DONE (ResultDiscardAtStart);
3708 return;
3709 }
3710
3711 if (n > r->used) {
3712 ResultClear (r);
3713 DONE (ResultDiscardAtStart);
3714 return;
3715 }
3716
3717 /* Shift remaining information down */
3718
3719 memmove ((VOID*) r->buf, (VOID*) (r->buf + n), r->used - n);
3720 r->used -= n;
3721
3722 if (r->seekState != (SeekState*) NULL) {
3723 r->seekState->upBufStartLoc += n;
3724 }
3725
3726 DONE (ResultCopy);
3727 }
3728
3729 /*
3730 *------------------------------------------------------*
3731 *
3732 * ResultAdd --
3733 *
3734 * Adds the bytes in the specified array to the
3735 * buffer, by appending it.
3736 *
3737 * Sideeffects:
3738 * See above.
3739 *
3740 * Result:
3741 * None.
3742 *
3743 *------------------------------------------------------*
3744 */
3745
3746 static void
ResultAdd(r,buf,toWrite)3747 ResultAdd (r, buf, toWrite)
3748 ResultBuffer* r; /* The buffer to extend */
3749 unsigned char* buf; /* The buffer to read from */
3750 int toWrite; /* The number of bytes in 'buf' */
3751 {
3752 START (ResultAdd);
3753 PRINT ("have %d, adding %d\n", r->used, toWrite); FL;
3754
3755 if ((r->used + toWrite + 1) > r->allocated) {
3756 /* Extension of the internal buffer is required.
3757 */
3758
3759 if (r->allocated == 0) {
3760 r->allocated = toWrite + INCREMENT;
3761 r->buf = (unsigned char*) ckalloc (r->allocated);
3762 } else {
3763 r->allocated += toWrite + INCREMENT;
3764 r->buf = (unsigned char*) ckrealloc((char*) r->buf,
3765 r->allocated);
3766 }
3767 }
3768
3769 /* now copy data */
3770 memcpy (r->buf + r->used, buf, toWrite);
3771 r->used += toWrite;
3772
3773 if (r->seekState != (SeekState*) NULL) {
3774 r->seekState->upBufEndLoc += toWrite;
3775 }
3776
3777 DONE (ResultAdd);
3778 }
3779
3780 /*
3781 *------------------------------------------------------*
3782 *
3783 * SeekCalculatePolicies --
3784 *
3785 * Computes standard and used policy from the natural
3786 * policy of the transformation, all transformations
3787 * below and its base channel.
3788 *
3789 * Sideeffects:
3790 * See above.
3791 *
3792 * Result:
3793 * None.
3794 *
3795 *------------------------------------------------------*
3796 */
3797
3798 static void
SeekCalculatePolicies(trans)3799 SeekCalculatePolicies (trans)
3800 TrfTransformationInstance* trans;
3801 {
3802 /* Define seek related runtime configuration.
3803 * seekCfg.overideAllowed, seekCfg.chosen, seekState.used
3804 *
3805 * i. some transformation below unseekable ? not-overidable unseekable
3806 * ii. base channel unseekable ? see above
3807 * iii. naturally unseekable ? overidable unseekable.
3808 *
3809 * WARNING: For 8.0 and 8.1 we will always return 'unseekable'. Due to a
3810 * missing 'Tcl_GetStackedChannel' we are unable to go down through the
3811 * stack of transformations.
3812 */
3813
3814 #ifndef USE_TCL_STUBS
3815 START (SeekCalculatePolicies);
3816 PRINTLN ("8.0., no Tcl_GetStackedChannel, unseekable, no overide");
3817
3818 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3819 trans->seekCfg.overideAllowed = 0;
3820
3821 #else
3822 Tcl_Channel self = trans->self;
3823 Tcl_Channel next;
3824
3825 int stopped = 0;
3826
3827 START (SeekCalculatePolicies);
3828
3829 if (trans->patchVariant == PATCH_ORIG) {
3830 PRINTLN ("8.1., no Tcl_GetStackedChannel, unseekable, no overide");
3831
3832 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3833 trans->seekCfg.overideAllowed = 0;
3834 goto done;
3835 }
3836
3837 /* 8.2 or higher */
3838
3839 while (self != (Tcl_Channel) NULL) {
3840 PRINT ("Check %p\n", self); FL;
3841
3842 #if GT81
3843 next = Tcl_GetStackedChannel (self);
3844 #else
3845 /* In case of 8.1 and higher we can use the (integrated or patched)
3846 * 'Tcl_GetStackedChannel' to find the next transform in a general
3847 * way. Else we have to check the type of 'next' itself before trying
3848 * to peek into its structure. If it is no Trf transform we cannot go
3849 * deeper into the stack. But that is not necessary, as the result of
3850 * 'unseekable' will not change anymore.
3851 */
3852
3853 if (Tcl_GetChannelType (self)->seekProc != TrfSeek) {
3854 PRINTLN ("Can't go further down, unseekable, disallow overide");
3855
3856 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3857 trans->seekCfg.overideAllowed = 0;
3858 stopped = 1;
3859 break;
3860 }
3861
3862 next = ((TrfTransformationInstance*)
3863 Tcl_GetChannelInstanceData (self))->parent;
3864 #endif
3865
3866 if (next == (Tcl_Channel) NULL) {
3867 /* self points to base channel (ii).
3868 */
3869
3870 if (Tcl_GetChannelType (self)->seekProc == (Tcl_DriverSeekProc*) NULL) {
3871 /* Base is unseekable.
3872 */
3873
3874 PRINTLN ("Base is unseekable");
3875
3876 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3877 trans->seekCfg.overideAllowed = 0;
3878 stopped = 1;
3879 break;
3880 }
3881 } else {
3882 /* 'next' points to a transformation.
3883 */
3884
3885 Tcl_Channel nextAfter;
3886
3887 #if GT81
3888 nextAfter = Tcl_GetStackedChannel (next);
3889 #else
3890 nextAfter = ((TrfTransformationInstance*)
3891 Tcl_GetChannelInstanceData (next))->parent;
3892 #endif
3893
3894 if (nextAfter != (Tcl_Channel) NULL) {
3895 /* next points to a transformation below the top (i).
3896 * Assume unseekable for a non-trf transformation, else peek directly
3897 * into the relevant structure
3898 */
3899
3900 if (Tcl_GetChannelType (next)->seekProc != TrfSeek) {
3901 PRINTLN ("Unknown type of transform, unseekable, no overide");
3902
3903 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3904 trans->seekCfg.overideAllowed = 0;
3905 stopped = 1;
3906 } else {
3907 TrfTransformationInstance* down =
3908 (TrfTransformationInstance*) Tcl_GetChannelInstanceData (next);
3909
3910 if (!down->seekState.allowed) {
3911 PRINTLN ("Trf transform, unseekable");
3912
3913 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3914 trans->seekCfg.overideAllowed = 0;
3915 stopped = 1;
3916 }
3917 }
3918 } else {
3919 /* Next points to the base channel */
3920 /* assert (0); */
3921 }
3922 }
3923
3924 self = next;
3925 }
3926
3927 PRINTLN ("Looping done");
3928
3929 if (!stopped) {
3930 PRINTLN ("Search went through, check natural policy");
3931
3932 if (TRF_IS_UNSEEKABLE (trans->seekCfg.natural)) {
3933 /* Naturally unseekable (iii)
3934 */
3935
3936 PRINTLN ("Naturally unseekable");
3937
3938 TRF_SET_UNSEEKABLE (trans->seekCfg.chosen);
3939 trans->seekCfg.overideAllowed = 1;
3940 } else {
3941 /* Take the natural ratio.
3942 */
3943
3944 PRINTLN ("naturally seekable");
3945
3946 trans->seekCfg.chosen.numBytesTransform =
3947 trans->seekCfg.natural.numBytesTransform;
3948
3949 trans->seekCfg.chosen.numBytesDown =
3950 trans->seekCfg.natural.numBytesDown;
3951
3952 trans->seekCfg.overideAllowed = 1;
3953 }
3954 }
3955 #endif
3956
3957 PRINTLN ("Copy ratio chosen :- used");
3958
3959 #ifdef USE_TCL_STUBS
3960 done:
3961 #endif
3962 trans->seekState.used.numBytesTransform =
3963 trans->seekCfg.chosen.numBytesTransform;
3964
3965 trans->seekState.used.numBytesDown =
3966 trans->seekCfg.chosen.numBytesDown;
3967
3968 trans->seekState.allowed =
3969 !TRF_IS_UNSEEKABLE (trans->seekState.used);
3970
3971 DONE (SeekCalculatePolicies);
3972 }
3973
3974 /*
3975 *------------------------------------------------------*
3976 *
3977 * SeekInitialize --
3978 *
3979 * Initialize the runtime state of the seek mechanisms
3980 *
3981 * Sideeffects:
3982 * See above.
3983 *
3984 * Result:
3985 * None.
3986 *
3987 *------------------------------------------------------*
3988 */
3989
3990 static void
SeekInitialize(trans)3991 SeekInitialize (trans)
3992 TrfTransformationInstance* trans;
3993 {
3994 trans->seekState.upLoc = 0;
3995 trans->seekState.upBufStartLoc = 0;
3996 trans->seekState.upBufEndLoc = 0;
3997
3998 if (trans->seekState.allowed) {
3999 trans->seekState.downLoc = TELL (trans);
4000 #ifdef USE_TCL_STUBS
4001 if (trans->patchVariant == PATCH_832) {
4002 trans->seekState.downLoc -= Tcl_ChannelBuffered (DOWNC (trans));
4003 }
4004 #endif
4005 trans->seekState.downZero = trans->seekState.downLoc;
4006 trans->seekState.aheadOffset = 0;
4007 } else {
4008 trans->seekState.downLoc = 0;
4009 trans->seekState.downZero = 0;
4010 trans->seekState.aheadOffset = 0;
4011 }
4012
4013 trans->seekCfg.identity = 0;
4014 trans->seekState.changed = 0;
4015
4016 SEEK_DUMP (Seek Initialized);
4017 }
4018
4019 /*
4020 *------------------------------------------------------*
4021 *
4022 * SeekClearBuffer --
4023 *
4024 * Clear read / write buffers of the transformation,
4025 * as specified by the second argument.
4026 *
4027 * Sideeffects:
4028 * See above.
4029 *
4030 * Result:
4031 * None.
4032 *
4033 *------------------------------------------------------*
4034 */
4035
4036 static void
SeekClearBuffer(trans,which)4037 SeekClearBuffer (trans, which)
4038 TrfTransformationInstance* trans;
4039 int which;
4040 {
4041 /*
4042 * Discard everything in the input and output buffers, both
4043 * in the transformation and in the generic layer of Trf.
4044 */
4045
4046 if (trans->mode & which & TCL_WRITABLE) {
4047 PRINT ("out.clearproc\n"); FL;
4048
4049 trans->out.vectors->clearProc (trans->out.control, trans->clientData);
4050 }
4051
4052 if (trans->mode & which & TCL_READABLE) {
4053 PRINT ("in.clearproc\n"); FL;
4054
4055 trans->in.vectors->clearProc (trans->in.control, trans->clientData);
4056 trans->readIsFlushed = 0;
4057 ResultClear (&trans->result);
4058 }
4059 }
4060
4061 /*
4062 *------------------------------------------------------*
4063 *
4064 * SeekSynchronize --
4065 *
4066 * Discard an existing read buffer and annulate the
4067 * read ahead in the downstream channel.
4068 *
4069 * Sideeffects:
4070 * See above.
4071 *
4072 * Result:
4073 * None.
4074 *
4075 *------------------------------------------------------*
4076 */
4077
4078 static void
SeekSynchronize(trans,parent)4079 SeekSynchronize (trans, parent)
4080 TrfTransformationInstance* trans;
4081 Tcl_Channel parent;
4082 {
4083 int offsetDown;
4084
4085 if (!trans->seekState.allowed) {
4086 /* No synchronisation required for an unseekable transform */
4087 return;
4088 }
4089
4090 if ((trans->seekState.upLoc == trans->seekState.upBufEndLoc) &&
4091 (trans->seekState.aheadOffset == 0)) {
4092 /* Up and down locations are in sync, nothing to do. */
4093 return;
4094 }
4095
4096 PRINT ("in.clearproc\n"); FL;
4097
4098 trans->in.vectors->clearProc (trans->in.control, trans->clientData);
4099 trans->readIsFlushed = 0;
4100
4101 offsetDown = TRF_DOWN_CONVERT (trans,
4102 trans->seekState.upLoc - trans->seekState.upBufEndLoc);
4103 offsetDown -= trans->seekState.aheadOffset; /* !! */
4104
4105 ResultClear (&trans->result);
4106
4107 if (offsetDown != 0) {
4108 SEEK (trans, offsetDown, SEEK_CUR);
4109 }
4110
4111 trans->seekState.downLoc += offsetDown;
4112 }
4113
4114 /*
4115 *------------------------------------------------------*
4116 *
4117 * SeekPolicyGet --
4118 *
4119 * Compute the currently used policy and store its
4120 * name into the character buffer.
4121 *
4122 * Sideeffects:
4123 * See above.
4124 *
4125 * Result:
4126 * None.
4127 *
4128 *------------------------------------------------------*
4129 */
4130
4131 static void
SeekPolicyGet(trans,policy)4132 SeekPolicyGet (trans, policy)
4133 TrfTransformationInstance* trans;
4134 char* policy;
4135 {
4136 if (trans->seekCfg.identity) {
4137 /* identity forced */
4138
4139 strcpy (policy, "identity");
4140 return;
4141 }
4142
4143 if (!trans->seekState.allowed &&
4144 ((trans->seekState.used.numBytesTransform !=
4145 trans->seekCfg.chosen.numBytesTransform) ||
4146 (trans->seekState.used.numBytesDown !=
4147 trans->seekCfg.chosen.numBytesDown))) {
4148 /* unseekable forced */
4149
4150 strcpy (policy, "unseekable");
4151 return;
4152 }
4153
4154 /* chosen policy in effect */
4155
4156 strcpy (policy, "");
4157 return;
4158 }
4159
4160 /*
4161 *------------------------------------------------------*
4162 *
4163 * SeekConfigGet --
4164 *
4165 * Generates a list containing the current configuration
4166 * of the seek system in a readable manner.
4167 *
4168 * Sideeffects:
4169 * See above.
4170 *
4171 * Result:
4172 * An Tcl_Obj, or NULL.
4173 *
4174 *------------------------------------------------------*
4175 */
4176
4177 static Tcl_Obj*
SeekConfigGet(interp,cfg)4178 SeekConfigGet (interp, cfg)
4179 Tcl_Interp* interp;
4180 SeekConfig* cfg;
4181 {
4182 int res;
4183 Tcl_Obj* list = (Tcl_Obj*) NULL;
4184 Tcl_Obj* sub1 = (Tcl_Obj*) NULL;
4185 Tcl_Obj* sub2 = (Tcl_Obj*) NULL;
4186
4187 list = Tcl_NewListObj (0, NULL);
4188
4189 if (list == (Tcl_Obj*) NULL) {
4190 goto error;
4191 }
4192
4193 LIST_ADDSTR (error, list, "ratioNatural");
4194 sub1 = Tcl_NewListObj (0, NULL);
4195
4196 if (sub1 == (Tcl_Obj*) NULL) {
4197 goto error;
4198 }
4199
4200 LIST_ADDINT (error, sub1, cfg->natural.numBytesTransform);
4201 LIST_ADDINT (error, sub1, cfg->natural.numBytesDown);
4202 LIST_ADDOBJ (error, list, sub1);
4203
4204
4205 LIST_ADDSTR (error, list, "ratioChosen");
4206 sub2 = Tcl_NewListObj (0, NULL);
4207
4208 if (sub2 == (Tcl_Obj*) NULL) {
4209 goto error;
4210 }
4211
4212 LIST_ADDINT (error, sub2, cfg->chosen.numBytesTransform);
4213 LIST_ADDINT (error, sub2, cfg->chosen.numBytesDown);
4214 LIST_ADDOBJ (error, list, sub2);
4215
4216 LIST_ADDSTR (error, list, "overideAllowed");
4217 LIST_ADDINT (error, list, cfg->overideAllowed);
4218
4219 LIST_ADDSTR (error, list, "identityForced");
4220 LIST_ADDINT (error, list, cfg->identity);
4221
4222 return list;
4223
4224 error:
4225 /* Cleanup any remnants of errors above */
4226
4227 if (list != (Tcl_Obj*) NULL) {
4228 Tcl_DecrRefCount (list);
4229 }
4230
4231 if (sub1 != (Tcl_Obj*) NULL) {
4232 Tcl_DecrRefCount (sub1);
4233 }
4234
4235 if (sub2 != (Tcl_Obj*) NULL) {
4236 Tcl_DecrRefCount (sub2);
4237 }
4238
4239 return NULL;
4240 }
4241
4242 /*
4243 *------------------------------------------------------*
4244 *
4245 * SeekStateGet --
4246 *
4247 * Generates a list containing the current state of
4248 * the seek system in a readable manner.
4249 *
4250 * Sideeffects:
4251 * See above.
4252 *
4253 * Result:
4254 * An Tcl_Obj, or NULL.
4255 *
4256 *------------------------------------------------------*
4257 */
4258
4259 static Tcl_Obj*
SeekStateGet(interp,state)4260 SeekStateGet (interp, state)
4261 Tcl_Interp* interp;
4262 SeekState* state;
4263 {
4264 int res;
4265 Tcl_Obj* list = (Tcl_Obj*) NULL;
4266 Tcl_Obj* sub = (Tcl_Obj*) NULL;
4267
4268 list = Tcl_NewListObj (0, NULL);
4269
4270 if (list == (Tcl_Obj*) NULL) {
4271 goto error;
4272 }
4273
4274 LIST_ADDSTR (error, list, "seekable");
4275 LIST_ADDINT (error, list, state->allowed);
4276
4277 LIST_ADDSTR (error, list, "ratio");
4278
4279 sub = Tcl_NewListObj (0, NULL);
4280 if (sub == (Tcl_Obj*) NULL) {
4281 goto error;
4282 }
4283
4284 LIST_ADDINT (error, sub, state->used.numBytesTransform);
4285 LIST_ADDINT (error, sub, state->used.numBytesDown);
4286 LIST_ADDOBJ (error, list, sub);
4287
4288 LIST_ADDSTR (error, list, "up");
4289 LIST_ADDINT (error, list, state->upLoc);
4290
4291 LIST_ADDSTR (error, list, "upBufStart");
4292 LIST_ADDINT (error, list, state->upBufStartLoc);
4293
4294 LIST_ADDSTR (error, list, "upBufEnd");
4295 LIST_ADDINT (error, list, state->upBufEndLoc);
4296
4297 LIST_ADDSTR (error, list, "down");
4298 LIST_ADDINT (error, list, state->downLoc);
4299
4300 LIST_ADDSTR (error, list, "downBase");
4301 LIST_ADDINT (error, list, state->downZero);
4302
4303 LIST_ADDSTR (error, list, "downAhead");
4304 LIST_ADDINT (error, list, state->aheadOffset);
4305
4306 LIST_ADDSTR (error, list, "changed");
4307 LIST_ADDINT (error, list, state->changed);
4308
4309 return list;
4310
4311 error:
4312 /* Cleanup any remnants of errors above */
4313
4314 if (list != (Tcl_Obj*) NULL) {
4315 Tcl_DecrRefCount (list);
4316 }
4317
4318 if (sub != (Tcl_Obj*) NULL) {
4319 Tcl_DecrRefCount (sub);
4320 }
4321
4322 return NULL;
4323 }
4324
4325 #ifdef TRF_DEBUG
4326 /*
4327 *------------------------------------------------------*
4328 *
4329 * PrintString --
4330 *
4331 * Defined only in debug mode, enforces correct
4332 * printing of strings by adding a \0 after its value.
4333 *
4334 * Sideeffects:
4335 * See above.
4336 *
4337 * Result:
4338 * None.
4339 *
4340 *------------------------------------------------------*
4341 */
4342
4343 void
PrintString(fmt,len,bytes)4344 PrintString (fmt,len,bytes)
4345 char* fmt;
4346 int len;
4347 char* bytes;
4348 {
4349 char* tmp = (char*) ckalloc (len+1);
4350 memcpy (tmp, bytes, len);
4351 tmp [len] = '\0';
4352
4353 PRINT (fmt, len, tmp);
4354
4355 ckfree (tmp);
4356 }
4357
4358 /*
4359 *------------------------------------------------------*
4360 *
4361 * DumpString --
4362 *
4363 * Defined only in debug mode, dumps information
4364 * in hex blocks
4365 *
4366 * Sideeffects:
4367 * See above.
4368 *
4369 * Result:
4370 * None.
4371 *
4372 *------------------------------------------------------*
4373 */
4374
4375 void
DumpString(n,len,bytes)4376 DumpString (n,len,bytes)
4377 int n;
4378 int len;
4379 char* bytes;
4380 {
4381 int i, c;
4382
4383 for (i=0, c=0; i < len; i++, c++) {
4384 if (c == 0) {
4385 BLNKS;
4386 }
4387
4388 printf (" %02x", (0xff & bytes [i]));
4389
4390 if (c == 16) {
4391 c = -1;
4392 printf ("\n");
4393 }
4394 }
4395
4396 if (c != 0) {
4397 printf ("\n");
4398 }
4399 }
4400
4401 /*
4402 *------------------------------------------------------*
4403 *
4404 * SeekDump --
4405 *
4406 * Defined only in debug mode, dumps the complete
4407 * state of all seek variables.
4408 *
4409 * Sideeffects:
4410 * See above.
4411 *
4412 * Result:
4413 * None.
4414 *
4415 *------------------------------------------------------*
4416 */
4417
4418 static void
SeekDump(trans,place)4419 SeekDump (trans, place)
4420 TrfTransformationInstance* trans;
4421 CONST char* place;
4422 {
4423 int loc;
4424 Tcl_Channel parent = DOWNC (trans);
4425
4426 loc = TELL (trans);
4427
4428 #if 0
4429 PRINT ("SeekDump (%s) {\n", place); FL; IN;
4430
4431 PRINT ("ratio up:down %d : %d\n",
4432 trans->seekState.used.numBytesTransform,
4433 trans->seekState.used.numBytesDown); FL;
4434 PRINT ("seekable %d\n",
4435 trans->seekState.allowed); FL;
4436 PRINT ("up %d [%d .. %d]\n",
4437 trans->seekState.upLoc,
4438 trans->seekState.upBufStartLoc,
4439 trans->seekState.upBufEndLoc); FL;
4440 PRINT ("down %d [%d] | %d\n",
4441 trans->seekState.downLoc,
4442 trans->seekState.aheadOffset,
4443 loc); FL;
4444 PRINT ("base %d\n",
4445 trans->seekState.downZero); FL;
4446 PRINT ("identity force %d\n",
4447 trans->seekCfg.identity); FL;
4448 PRINT ("seek while ident %d\n",
4449 trans->seekState.changed); FL;
4450 PRINT ("read buffer %d\n",
4451 ResultLength (&trans->result)); FL;
4452
4453 OT ; PRINT ("}\n"); FL;
4454 #else
4455 PRINT ("SkDmp (%s) ", place); FL;
4456
4457 #if 0
4458 NPRINT ("(%2d : %2d) | ",
4459 trans->seekCfg.natural.numBytesTransform,
4460 trans->seekCfg.natural.numBytesDown); FL;
4461 NPRINT ("(%2d : %2d) | ",
4462 trans->seekCfg.chosen.numBytesTransform,
4463 trans->seekCfg.chosen.numBytesDown); FL;
4464 #endif
4465 NPRINT ("%2d:%2d /%1d |r %5d |u %5d [%5d..%5d] |d %5d [%2d] %5d | %5d | %1d %1d",
4466 trans->seekState.used.numBytesTransform,
4467 trans->seekState.used.numBytesDown,
4468 trans->seekState.allowed,
4469 ResultLength (&trans->result),
4470 trans->seekState.upLoc,
4471 trans->seekState.upBufStartLoc,
4472 trans->seekState.upBufEndLoc,
4473 trans->seekState.downLoc,
4474 trans->seekState.aheadOffset,
4475 loc,
4476 trans->seekState.downZero,
4477 trans->seekCfg.identity,
4478 trans->seekState.changed
4479 ); FL;
4480
4481 NPRINT ("\n"); FL;
4482 #endif
4483 }
4484 #endif
4485
4486 /*
4487 *------------------------------------------------------*
4488 *
4489 * AllocChannelType --
4490 *
4491 * Allocates a new ChannelType structure.
4492 *
4493 *
4494 * Sideeffects:
4495 * See above.
4496 *
4497 * Result:
4498 * A reference to the new structure.
4499 *
4500 *------------------------------------------------------*
4501 */
4502
4503 static Tcl_ChannelType*
AllocChannelType(sizePtr)4504 AllocChannelType (sizePtr)
4505 int* sizePtr;
4506 {
4507 /*
4508 * Allocation of a new channeltype structure is not easy, because of
4509 * the various version of the core and subsequent changes to the
4510 * structure. The main challenge is to allocate enough memory for
4511 * modern versions even if this extension is compiled against one
4512 * of the older variants!
4513 *
4514 * (1) Versions before stubs (8.0.x) are simple, because they are
4515 * supported only if the extension is compiled against exactly
4516 * that version of the core.
4517 *
4518 * (2) With stubs we just determine the difference between the older
4519 * and modern variant and overallocate accordingly if compiled
4520 * against an older variant.
4521 */
4522
4523 int size = sizeof(Tcl_ChannelType); /* Base size */
4524
4525 #ifdef USE_TCL_STUBS
4526 /*
4527 * Size of a procedure pointer. We assume that all procedure
4528 * pointers are of the same size, regardless of exact type
4529 * (arguments and return values).
4530 *
4531 * 8.1. First version containing close2proc. Baseline.
4532 * 8.3.2 Three additional vectors. Moved blockMode, new flush- and
4533 * handlerProc's.
4534 * 8.4+ wide seek, and thread action.
4535 *
4536 * => Compilation against earlier version has to overallocate five
4537 * procedure pointers.
4538 */
4539
4540 #if !(GT832)
4541 size += 5 * procPtrSize;
4542 #endif
4543 #endif
4544
4545 if (sizePtr != (int*) NULL) {
4546 *sizePtr = size;
4547 }
4548 return (Tcl_ChannelType*) ckalloc (size);
4549 }
4550
4551 /*
4552 *------------------------------------------------------*
4553 *
4554 * InitializeChannelType --
4555 *
4556 * Initializes a new ChannelType structure.
4557 *
4558 *
4559 * Sideeffects:
4560 * See above.
4561 *
4562 * Result:
4563 * None.
4564 *
4565 *------------------------------------------------------*
4566 */
4567
4568 static Tcl_ChannelType*
InitializeChannelType(name,patchVariant)4569 InitializeChannelType (name, patchVariant)
4570 CONST char* name;
4571 int patchVariant;
4572 {
4573 Tcl_ChannelType* tct;
4574 int size;
4575
4576 /*
4577 * Initialization of a new channeltype structure is not easy,
4578 * because of the various version of the core and subsequent changes
4579 * to the structure. The main problem is if compiled against an
4580 * older version how to access the elements of the structure not
4581 * known in that version. It is made a bit easier because the
4582 * allocation routine returns the allocated size. This allows us to
4583 * clear out the entire structure. So we just have to deal with the
4584 * elements to set and not the ones left alone.
4585 */
4586
4587 tct = AllocChannelType (&size);
4588 tct->typeName = (char*) name;
4589
4590 memset ((VOID*) tct, '\0', size);
4591
4592 /*
4593 * Common elements of the structure (no changes in location or name)
4594 */
4595
4596 tct->closeProc = TrfClose;
4597 tct->inputProc = TrfInput;
4598 tct->outputProc = TrfOutput;
4599 tct->seekProc = TrfSeek;
4600 tct->setOptionProc = TrfSetOption;
4601 tct->getOptionProc = TrfGetOption;
4602 tct->watchProc = TrfWatch;
4603 tct->getHandleProc = TrfGetFile;
4604
4605 /*
4606 * No need to handle close2Proc. Already cleared with the 'memset'
4607 * above.
4608 */
4609
4610 /*
4611 * blockModeProc is a twister. For 8.0.x we can access it
4612 * immediately. For the higher versions we have to make some
4613 * runtime-choices, and their implementation depends on the version
4614 * we compile against.
4615 */
4616
4617 #ifndef USE_TCL_STUBS
4618 /* 8.0.x */
4619 tct->blockModeProc = TrfBlock;
4620 #else
4621 #if GT832
4622 /* 8.3.2. and higher. Direct access to all elements possible. Use
4623 *'patchVariant' information to select the values to use.
4624 */
4625
4626 if ((patchVariant == PATCH_ORIG) ||
4627 (patchVariant == PATCH_82)) {
4628 /* The 'version' element of 8.3.2 is in the the place of the
4629 * blockModeProc. For the original patch in 8.1.x and the firstly
4630 * included (8.2) we have to set our blockModeProc into this
4631 * place.
4632 */
4633 tct->version = (Tcl_ChannelTypeVersion) TrfBlock;
4634 } else /* patchVariant == PATCH_832 */ {
4635 /* For the 8.3.2 core we present ourselves as a version 2
4636 * driver. This means a speciial value in version (ex
4637 * blockModeProc), blockModeProc in a different place and of
4638 * course usage of the handlerProc.
4639 */
4640
4641 tct->version = TCL_CHANNEL_VERSION_2;
4642 tct->blockModeProc = TrfBlock;
4643 tct->handlerProc = TrfNotify;
4644 }
4645 #else
4646 /* Same as above, but as we are compiling against an older core we
4647 * have to create some definitions for the new elements as the compiler
4648 * does not know them by name.
4649 */
4650
4651 if ((patchVariant == PATCH_ORIG) ||
4652 (patchVariant == PATCH_82)) {
4653 /* The 'version' element of 8.3.2 is in the the place of the
4654 * blockModeProc. For the original patch in 8.1.x and the firstly
4655 * included (8.2) we have to set our blockModeProc into this
4656 * place.
4657 */
4658 tct->blockModeProc = TrfBlock;
4659 } else /* patchVariant == PATCH_832 */ {
4660 /* For the 8.3.2 core we present ourselves as a version 2
4661 * driver. This means a special value in version (ex
4662 * blockModeProc), blockModeProc in a different place and of
4663 * course usage of the handlerProc.
4664 */
4665
4666 #define TRF_CHANNEL_VERSION_2 ((TrfChannelTypeVersion) 0x2)
4667
4668 #define BMP (*((Tcl_DriverBlockModeProc**) (&(tct->close2Proc) + 1)))
4669 #define HP (*((TrfDriverHandlerProc**) (&(tct->close2Proc) + 3)))
4670
4671 typedef struct TrfChannelTypeVersion_* TrfChannelTypeVersion;
4672 typedef int (TrfDriverHandlerProc) _ANSI_ARGS_((ClientData instanceData,
4673 int interestMask));
4674
4675 tct->blockModeProc = (Tcl_DriverBlockModeProc*) TRF_CHANNEL_VERSION_2;
4676
4677 BMP = TrfBlock;
4678 HP = TrfNotify;
4679
4680 #undef BMP
4681 #undef HP
4682 #undef TRF_CHANNEL_VERSION_2
4683 }
4684 #endif
4685 #endif
4686
4687 return tct;
4688 }
4689
4690 /*
4691 *------------------------------------------------------*
4692 *
4693 * TimerKill --
4694 *
4695 * Timer management. Removes the internal timer
4696 * if it exists.
4697 *
4698 * Sideeffects:
4699 * See above.
4700 *
4701 * Result:
4702 * None.
4703 *
4704 *------------------------------------------------------*
4705 */
4706
4707 static void
TimerKill(trans)4708 TimerKill (trans)
4709 TrfTransformationInstance* trans;
4710 {
4711 if (trans->timer != (Tcl_TimerToken) NULL) {
4712 /* Delete an existing flush-out timer,
4713 * prevent it from firing on removed channel.
4714 */
4715
4716 Tcl_DeleteTimerHandler (trans->timer);
4717 trans->timer = (Tcl_TimerToken) NULL;
4718
4719 PRINT ("Timer deleted ..."); FL;
4720 }
4721 }
4722
4723 /*
4724 *------------------------------------------------------*
4725 *
4726 * TimerSetup --
4727 *
4728 * Timer management. Creates the internal timer
4729 * if it does not exist.
4730 *
4731 * Sideeffects:
4732 * See above.
4733 *
4734 * Result:
4735 * None.
4736 *
4737 *------------------------------------------------------*
4738 */
4739
4740 static void
TimerSetup(trans)4741 TimerSetup (trans)
4742 TrfTransformationInstance* trans;
4743 {
4744 if (trans->timer == (Tcl_TimerToken) NULL) {
4745 trans->timer = Tcl_CreateTimerHandler (TRF_DELAY, ChannelHandlerTimer,
4746 (ClientData) trans);
4747 }
4748 }
4749
4750 /*
4751 *------------------------------------------------------*
4752 *
4753 * ChannelHandlerKS --
4754 *
4755 * Management of channel handlers. Deletes/Recreates
4756 * as required by the specified mask.
4757 *
4758 * Sideeffects:
4759 * See above.
4760 *
4761 * Result:
4762 * None.
4763 *
4764 *------------------------------------------------------*
4765 */
4766
4767 static void
ChannelHandlerKS(trans,mask)4768 ChannelHandlerKS (trans, mask)
4769 TrfTransformationInstance* trans;
4770 int mask;
4771 {
4772 /*
4773 * This procedure is called only for the original and the 8.2
4774 * patch. The new 8.2.3 patch does not use channel handlers but a
4775 * separate NotifyHandler in the driver.
4776 */
4777
4778 Tcl_Channel parent = DOWNC (trans);
4779
4780 if (trans->watchMask) {
4781 /*
4782 * Remove event handler to underlying channel, this could
4783 * be because we are closing for real, or being "unstacked".
4784 */
4785
4786 Tcl_DeleteChannelHandler (parent, ChannelHandler,
4787 (ClientData) trans);
4788 }
4789
4790 trans->watchMask = mask;
4791
4792 if (trans->watchMask) {
4793 /*
4794 * Setup active monitor for events on underlying Channel
4795 */
4796
4797 Tcl_CreateChannelHandler (parent, trans->watchMask,
4798 ChannelHandler, (ClientData) trans);
4799 }
4800 }
4801