wasCSharpSQLite – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Channel.java
3 *
4 * Copyright (c) 1997 Sun Microsystems, Inc.
5 *
6 * See the file "license.terms" for information on usage and
7 * redistribution of this file, and for a DISCLAIMER OF ALL
8 * WARRANTIES.
9 *
10 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
11 *
12 * RCS @(#) $Id: Channel.java,v 1.25 2003/03/08 03:42:43 mdejong Exp $
13 */
14 using System;
15 using System.Text;
16 using System.IO;
17  
18 namespace tcl.lang
19 {
20  
21 /// <summary> The Channel class provides functionality that will
22 /// be needed for any type of Tcl channel. It performs
23 /// generic reads, writes, without specifying how a
24 /// given channel is actually created. Each new channel
25 /// type will need to extend the abstract Channel class
26 /// and override any methods it needs to provide a
27 /// specific implementation for.
28 /// </summary>
29  
30 public abstract class Channel
31 {
32 private void InitBlock()
33 {
34 buffering = TclIO.BUFF_FULL;
35 inputTranslation = TclIO.TRANS_AUTO;
36 outputTranslation = TclIO.TRANS_PLATFORM;
37 }
38 /// <summary> This method should be overridden in the subclass to provide
39 /// a channel specific InputStream object.
40 /// </summary>
41 protected internal abstract Stream InputStream
42 {
43 get;
44 }
45 /// <summary> This method should be overridden in the subclass to provide
46 /// a channel specific OutputStream object.
47 /// </summary>
48 protected internal abstract Stream OutputStream
49 {
50 get;
51 }
52 /// <summary> Gets the chanName that is the key for the chanTable hashtable.</summary>
53 /// <returns> channelId
54 /// </returns>
55 /// <summary> Sets the chanName that is the key for the chanTable hashtable.</summary>
56 /// <param name="chan">the unique channelId
57 /// </param>
58 public string ChanName
59 {
60  
61  
62 get
63 {
64 return chanName;
65 }
66  
67  
68  
69 set
70 {
71 chanName = value;
72 }
73  
74 }
75 /// <summary> Return a string that describes the channel type.
76 ///
77 /// This is the equivilent of the Tcl_ChannelTypE.typeName field.
78 /// </summary>
79 public abstract string ChanType
80 {
81 get;
82 }
83 /// <summary> Return number of references to this Channel.</summary>
84 public int RefCount
85 {
86  
87  
88 get
89 {
90 return refCount;
91 }
92  
93 }
94 public bool ReadOnly
95 {
96 get
97 {
98 return ( ( mode & TclIO.RDONLY ) != 0 );
99 }
100  
101 }
102 public bool WriteOnly
103 {
104 get
105 {
106 return ( ( mode & TclIO.WRONLY ) != 0 );
107 }
108  
109 }
110 public bool ReadWrite
111 {
112 get
113 {
114 return ( ( mode & TclIO.RDWR ) != 0 );
115 }
116  
117 }
118 /// <summary> Query blocking mode.</summary>
119 /// <summary> Set blocking mode.
120 ///
121 /// </summary>
122 /// <param name="blocking">new blocking mode
123 /// </param>
124 public bool Blocking
125 {
126  
127  
128 get
129 {
130 return blocking;
131 }
132  
133  
134  
135 set
136 {
137 blocking = value;
138  
139 if ( input != null )
140 input.Blocking = blocking;
141 if ( output != null )
142 output.Blocking = blocking;
143 }
144  
145 }
146 /// <summary> Query buffering mode.</summary>
147 /// <summary> Set buffering mode
148 ///
149 /// </summary>
150 /// <param name="buffering">One of TclIO.BUFF_FULL, TclIO.BUFF_LINE,
151 /// or TclIO.BUFF_NONE
152 /// </param>
153 public int Buffering
154 {
155  
156  
157 get
158 {
159 return buffering;
160 }
161  
162  
163  
164 set
165 {
166 if ( value < TclIO.BUFF_FULL || value > TclIO.BUFF_NONE )
167 throw new TclRuntimeError( "invalid buffering mode in Channel.setBuffering()" );
168  
169 buffering = value;
170 if ( input != null )
171 input.Buffering = buffering;
172 if ( output != null )
173 output.Buffering = buffering;
174 }
175  
176 }
177 /// <summary> Query buffer size</summary>
178 /// <summary> Tcl_SetChannelBufferSize -> setBufferSize
179 ///
180 /// </summary>
181 /// <param name="size">new buffer size
182 /// </param>
183 public int BufferSize
184 {
185  
186  
187 get
188 {
189 return bufferSize;
190 }
191  
192  
193  
194 set
195 {
196  
197 // If the buffer size is smaller than 10 bytes or larger than 1 Meg
198 // do not accept the requested size and leave the current buffer size.
199  
200 if ( ( value < 10 ) || ( value > ( 1024 * 1024 ) ) )
201 {
202 return;
203 }
204  
205 bufferSize = value;
206 if ( input != null )
207 input.BufferSize = bufferSize;
208 if ( output != null )
209 output.BufferSize = bufferSize;
210 }
211  
212 }
213 public int NumBufferedInputBytes
214 {
215 get
216 {
217 if ( input != null )
218 return input.NumBufferedBytes;
219 else
220 return 0;
221 }
222  
223 }
224 public int NumBufferedOutputBytes
225 {
226 get
227 {
228 if ( output != null )
229 return output.NumBufferedBytes;
230 else
231 return 0;
232 }
233  
234 }
235 /// <summary> Returns true if a background flush is waiting to happen.</summary>
236 public bool BgFlushScheduled
237 {
238  
239  
240 get
241 {
242 // FIXME: Need to query output here
243 return false;
244 }
245  
246 }
247 /// <summary> Query encoding
248 ///
249 /// </summary>
250 /// <returns> Name of Channel's Java encoding (null if no encoding)
251 /// </returns>
252 /// <summary> Set new Java encoding</summary>
253 internal System.Text.Encoding Encoding
254 {
255 get
256 {
257 return encoding;
258 }
259 set
260 {
261 encoding = value;
262 if ( (System.Object)encoding == null )
263 bytesPerChar = 1;
264 else
265 bytesPerChar = EncodingCmd.getBytesPerChar( encoding );
266  
267 if ( input != null )
268 input.Encoding = encoding;
269 if ( output != null )
270 output.Encoding = encoding;
271  
272 // FIXME: Pass bytesPerChar to input and output
273 }
274  
275 }
276 /// <summary> Query input translation
277 /// Set new input translation</summary>
278 public int InputTranslation
279 {
280  
281  
282 get
283 {
284 return inputTranslation;
285 }
286  
287  
288  
289 set
290 {
291 inputTranslation = value;
292 if ( input != null )
293 input.Translation = inputTranslation;
294 }
295  
296 }
297 /// <summary> Query output translation
298 /// Set new output translation</summary>
299 public int OutputTranslation
300 {
301  
302  
303 get
304 {
305 return outputTranslation;
306 }
307  
308  
309  
310 set
311 {
312 outputTranslation = value;
313 if ( output != null )
314 output.Translation = outputTranslation;
315 }
316  
317 }
318 /// <summary> Query input eof character</summary>
319 /// <summary> Set new input eof character</summary>
320 internal char InputEofChar
321 {
322  
323  
324 get
325 {
326 return inputEofChar;
327 }
328  
329  
330  
331 set
332 {
333 // Store as a byte, not a unicode character
334 inputEofChar = (char)( value & 0xFF );
335 if ( input != null )
336 input.EofChar = inputEofChar;
337 }
338  
339 }
340 /// <summary> Query output eof character</summary>
341 /// <summary> Set new output eof character</summary>
342 internal char OutputEofChar
343 {
344  
345  
346 get
347 {
348 return outputEofChar;
349 }
350  
351  
352  
353 set
354 {
355 // Store as a byte, not a unicode character
356 outputEofChar = (char)( value & 0xFF );
357 if ( output != null )
358 output.EofChar = outputEofChar;
359 }
360  
361 }
362  
363 /// <summary> The read, write, append and create flags are set here. The
364 /// variables used to set the flags are found in the class TclIO.
365 /// </summary>
366  
367 protected internal int mode;
368  
369 /// <summary> This is a unique name that sub-classes need to set. It is used
370 /// as the key in the hashtable of registered channels (in interp).
371 /// </summary>
372  
373 private string chanName;
374  
375 /// <summary> How many interpreters hold references to this IO channel?</summary>
376  
377 protected internal int refCount = 0;
378  
379 /// <summary> Tcl input and output objecs. These are like a mix between
380 /// a Java Stream and a Reader.
381 /// </summary>
382  
383 protected internal TclInputStream input = null;
384 protected internal TclOutputStream output = null;
385  
386 /// <summary> Set to false when channel is in non-blocking mode.</summary>
387  
388 protected internal bool blocking = true;
389  
390 /// <summary> Buffering (full,line, or none)</summary>
391  
392 protected internal int buffering;
393  
394 /// <summary> Buffer size, in bytes, allocated for channel to store input or output</summary>
395  
396 protected internal int bufferSize = 4096;
397  
398 /// <summary> Name of Java encoding for this Channel.
399 /// A null value means use no encoding (binary).
400 /// </summary>
401  
402 // FIXME: Check to see if this field is updated after a call
403 // to "encoding system $enc" for new Channel objects!
404  
405 protected internal System.Text.Encoding encoding;
406 protected internal int bytesPerChar;
407  
408 /// <summary> Translation mode for end-of-line character</summary>
409  
410 protected internal int inputTranslation;
411 protected internal int outputTranslation;
412  
413 /// <summary> If nonzero, use this as a signal of EOF on input.</summary>
414  
415 protected internal char inputEofChar = (char)( 0 );
416  
417 /// <summary> If nonzero, append this to a writeable channel on close.</summary>
418  
419 protected internal char outputEofChar = (char)( 0 );
420  
421 internal Channel()
422 {
423 InitBlock();
424 Encoding = EncodingCmd.systemJavaEncoding;
425 }
426  
427 /// <summary> Tcl_ReadChars -> read
428 ///
429 /// Read data from the Channel into the given TclObject.
430 ///
431 /// </summary>
432 /// <param name="interp"> is used for TclExceptions.
433 /// </param>
434 /// <param name="tobj"> the object data will be added to.
435 /// </param>
436 /// <param name="readType"> specifies if the read should read the entire
437 /// buffer (TclIO.READ_ALL), the next line
438 /// (TclIO.READ_LINE), of a specified number
439 /// of bytes (TclIO.READ_N_BYTES).
440 /// </param>
441 /// <param name="numBytes"> the number of bytes/chars to read. Used only
442 /// when the readType is TclIO.READ_N_BYTES.
443 /// </param>
444 /// <returns> the number of bytes read.
445 /// Returns -1 on EOF or on error.
446 /// </returns>
447 /// <exception cref=""> TclException is thrown if read occurs on WRONLY channel.
448 /// </exception>
449 /// <exception cref=""> IOException is thrown when an IO error occurs that was not
450 /// correctly tested for. Most cases should be caught.
451 /// </exception>
452  
453 internal int read( Interp interp, TclObject tobj, int readType, int numBytes )
454 {
455 TclObject dataObj;
456  
457 checkRead( interp );
458 initInput();
459  
460 switch ( readType )
461 {
462  
463 case TclIO.READ_ALL:
464 {
465 return input.doReadChars( tobj, -1 );
466 }
467  
468 case TclIO.READ_LINE:
469 {
470 return input.getsObj( tobj );
471 }
472  
473 case TclIO.READ_N_BYTES:
474 {
475 return input.doReadChars( tobj, numBytes );
476 }
477  
478 default:
479 {
480 throw new TclRuntimeError( "Channel.read: Invalid read mode." );
481 }
482  
483 }
484 }
485  
486 /// <summary> Tcl_WriteObj -> write
487 ///
488 /// Write data to the Channel
489 ///
490 /// </summary>
491 /// <param name="interp">is used for TclExceptions.
492 /// </param>
493 /// <param name="outData">the TclObject that holds the data to write.
494 /// </param>
495  
496 public virtual void write( Interp interp, TclObject outData )
497 {
498  
499 checkWrite( interp );
500 initOutput();
501  
502 // FIXME: Is it possible for a write to happen with a null output?
503 if ( output != null )
504 {
505 output.writeObj( outData );
506 }
507 }
508  
509 /// <summary> Tcl_WriteChars -> write
510 ///
511 /// Write string data to the Channel.
512 ///
513 /// </summary>
514 /// <param name="interp">is used for TclExceptions.
515 /// </param>
516 /// <param name="outStr">the String object to write.
517 /// </param>
518  
519 public void write( Interp interp, string outStr )
520 {
521 write( interp, TclString.newInstance( outStr ) );
522 }
523  
524 /// <summary> Close the Channel. The channel is only closed, it is
525 /// the responsibility of the "closer" to remove the channel from
526 /// the channel table.
527 /// </summary>
528  
529 internal virtual void close()
530 {
531  
532 IOException ex = null;
533  
534 if ( input != null )
535 {
536 try
537 {
538 input.close();
539 }
540 catch ( IOException e )
541 {
542 ex = e;
543 }
544 input = null;
545 }
546  
547 if ( output != null )
548 {
549 try
550 {
551 output.close();
552 }
553 catch ( IOException e )
554 {
555 ex = e;
556 }
557 output = null;
558 }
559  
560 if ( ex != null )
561 throw ex;
562 }
563  
564 /// <summary> Flush the Channel.
565 ///
566 /// </summary>
567 /// <exception cref=""> TclException is thrown when attempting to flush a
568 /// read only channel.
569 /// </exception>
570 /// <exception cref=""> IOEcception is thrown for all other flush errors.
571 /// </exception>
572  
573 public void flush( Interp interp )
574 {
575  
576 checkWrite( interp );
577  
578 if ( output != null )
579 {
580 output.flush();
581 }
582 }
583  
584 /// <summary> Move the current file pointer. If seek is not supported on the
585 /// given channel then -1 will be returned. A subclass should
586 /// override this method if it supports the seek operation.
587 ///
588 /// </summary>
589 /// <param name="interp">currrent interpreter.
590 /// </param>
591 /// <param name="offset">The number of bytes to move the file pointer.
592 /// </param>
593 /// <param name="mode">where to begin incrementing the file pointer; beginning,
594 /// current, end.
595 /// </param>
596  
597 public virtual void seek( Interp interp, long offset, int mode )
598 {
599 throw new TclPosixException( interp, TclPosixException.EINVAL, true, "error during seek on \"" + ChanName + "\"" );
600 }
601  
602 /// <summary> Return the current file pointer. If tell is not supported on the
603 /// given channel then -1 will be returned. A subclass should override
604 /// this method if it supports the tell operation.
605 /// </summary>
606  
607 public virtual long tell()
608 {
609 return (long)( -1 );
610 }
611  
612 /// <summary> Setup the TclInputStream on the first call to read</summary>
613  
614 protected internal void initInput()
615 {
616 if ( input != null )
617 return;
618  
619 input = new TclInputStream( InputStream );
620 input.Encoding = encoding;
621 input.Translation = inputTranslation;
622 input.EofChar = inputEofChar;
623 input.Buffering = buffering;
624 input.BufferSize = bufferSize;
625 input.Blocking = blocking;
626 }
627  
628 /// <summary> Setup the TclOutputStream on the first call to write</summary>
629  
630 protected internal void initOutput()
631 {
632 if ( output != null )
633 return;
634  
635 output = new TclOutputStream( OutputStream );
636 output.Encoding = encoding;
637 output.Translation = outputTranslation;
638 output.EofChar = outputEofChar;
639 output.Buffering = buffering;
640 output.BufferSize = bufferSize;
641 output.Blocking = blocking;
642 }
643  
644 /// <summary> Returns true if the last read reached the EOF.</summary>
645  
646 public bool eof()
647 {
648 if ( input != null )
649 return input.eof();
650 else
651 return false;
652 }
653  
654 // Helper methods to check read/write permission and raise a
655 // TclException if reading is not allowed.
656  
657 protected internal void checkRead( Interp interp )
658 {
659 if ( !ReadOnly && !ReadWrite )
660 {
661 throw new TclException( interp, "channel \"" + ChanName + "\" wasn't opened for reading" );
662 }
663 }
664  
665 protected internal void checkWrite( Interp interp )
666 {
667 if ( !WriteOnly && !ReadWrite )
668 {
669 throw new TclException( interp, "channel \"" + ChanName + "\" wasn't opened for writing" );
670 }
671 }
672  
673 /// <summary> Tcl_InputBlocked -> isBlocked
674 ///
675 /// Returns true if input is blocked on this channel, false otherwise.
676 ///
677 /// </summary>
678  
679 public bool isBlocked( Interp interp )
680 {
681 checkRead( interp );
682  
683 if ( input != null )
684 return input.Blocked;
685 else
686 return false;
687 }
688  
689 /// <summary> Channel is in CRLF eol input translation mode and the last
690 /// byte seen was a CR.
691 /// </summary>
692  
693 public bool inputSawCR()
694 {
695 if ( input != null )
696 return input.sawCR();
697 return false;
698 }
699 }
700 }