Source Code Cross Referenced for TclOutputStream.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * TclOutputStream.java
0003:         *
0004:         * Copyright (c) 2003 Mo DeJong
0005:         *
0006:         * See the file "license.terms" for information on usage and
0007:         * redistribution of this file, and for a DISCLAIMER OF ALL
0008:         * WARRANTIES.
0009:         * 
0010:         * RCS: @(#) $Id: TclOutputStream.java,v 1.4 2006/07/07 23:36:00 mdejong Exp $
0011:         */
0012:
0013:        // A TclOutputStream is a cross between a Java OutputStream and
0014:        // a Writer. The class supports writing raw bytes as well as
0015:        // encoded characters.
0016:        package tcl.lang;
0017:
0018:        import java.io.IOException;
0019:        import java.io.EOFException;
0020:        import java.io.OutputStream;
0021:        import java.io.FileOutputStream;
0022:        import java.io.UnsupportedEncodingException;
0023:
0024:        import java.nio.CharBuffer;
0025:        import java.nio.ByteBuffer;
0026:
0027:        import java.nio.charset.Charset;
0028:        import java.nio.charset.CharsetEncoder;
0029:        import java.nio.charset.CoderResult;
0030:        import java.nio.charset.IllegalCharsetNameException;
0031:        import java.nio.charset.UnsupportedCharsetException;
0032:
0033:        class TclOutputStream {
0034:
0035:            /**
0036:             * The Java byte stream object data will be written to.
0037:             */
0038:
0039:            private OutputStream output;
0040:
0041:            /**
0042:             * If nonzero, use this character as EOF marker.
0043:             */
0044:
0045:            private char eofChar;
0046:
0047:            /**
0048:             * Translation mode for end-of-line character
0049:             */
0050:
0051:            protected int translation;
0052:
0053:            /**
0054:             * Name of Java encoding for this Channel.
0055:             * A null value means use no encoding (binary).
0056:             */
0057:
0058:            protected String encoding;
0059:
0060:            /**
0061:             * Charset encoder object. A null value means
0062:             * that no conversions have been done yet.
0063:             */
0064:
0065:            protected CharsetEncoder cse = null;
0066:
0067:            /**
0068:             * Buffering
0069:             */
0070:
0071:            protected int buffering;
0072:
0073:            /**
0074:             * Blocking
0075:             */
0076:
0077:            protected boolean blocking;
0078:
0079:            /**
0080:             * Blocked
0081:             */
0082:
0083:            protected boolean blocked = false;
0084:
0085:            /**
0086:             * Buffer size in bytes
0087:             */
0088:
0089:            protected int bufSize;
0090:
0091:            /**
0092:             * Staging area used to store chars before conversion into
0093:             * buffered bytes.
0094:             */
0095:
0096:            protected char[] outputStage = null;
0097:
0098:            /**
0099:             * Flags used to track encoding states.
0100:             * The encodingState member of called outputEncodingState
0101:             * in the C ChannelState type. The encodingStart and encodingEnd
0102:             * members combined are called outputEncodingFlags
0103:             * and have the bit values TCL_ENCODING_END and TCL_ENCODING_START.
0104:             */
0105:
0106:            Object encodingState = null;
0107:            boolean encodingStart = true;
0108:            boolean encodingEnd = false;
0109:
0110:            /**
0111:             * First and last buffers in the output queue and
0112:             * the current buffer being filled.
0113:             */
0114:
0115:            ChannelBuffer outQueueHead = null;
0116:            ChannelBuffer outQueueTail = null;
0117:            ChannelBuffer curOut = null;
0118:
0119:            /**
0120:             * Used to track buffer state, these are bit flags stored
0121:             * in the flags filed in the C impl.
0122:             */
0123:
0124:            protected boolean bufferReady = false;
0125:            protected boolean bgFlushScheduled = false;
0126:            protected boolean closed = false;
0127:
0128:            /**
0129:             * Posix error code of deferred error.
0130:             */
0131:            protected int unreportedError = 0;
0132:
0133:            /**
0134:             * FIXME: add desc
0135:             */
0136:
0137:            protected int refCount = 0;
0138:
0139:            /**
0140:             * This flag is true when the OutputStream is from
0141:             * a file on disk that should be sync()'ed after
0142:             * a flush. A sync should not be used for non-file
0143:             * streams.
0144:             */
0145:
0146:            protected boolean canSync = false;
0147:
0148:            /**
0149:             * Constructor for Tcl input stream class. We require
0150:             * a byte stream source at init time, the stram can't
0151:             * be changed after the TclInputStream is created.
0152:             */
0153:
0154:            TclOutputStream(OutputStream inOutput) {
0155:                output = inOutput;
0156:            }
0157:
0158:            /**
0159:             * Set the sync flag for a channel so that a
0160:             * sync will be invoked in addition to a flush.
0161:             */
0162:
0163:            void setSync(boolean canSync) {
0164:                this .canSync = canSync;
0165:            }
0166:
0167:            /**
0168:             * Tcl_Close -> close
0169:             *
0170:             * Closes a channel.
0171:             *
0172:             * Closes the channel if this is the last reference.
0173:             *
0174:             * close removes the channel as far as the user is concerned.
0175:             * However, it may continue to exist for a while longer if it has
0176:             * a background flush scheduled. The device itself is eventually
0177:             * closed and the channel record removed, in closeChannel.
0178:             */
0179:
0180:            void close() throws IOException {
0181:                //CloseCallback *cbPtr;
0182:                //Channel *chanPtr;
0183:                //ChannelState *statePtr;
0184:                int result;
0185:
0186:                // Perform special handling for standard channels being closed. If the
0187:                // refCount is now 1 it means that the last reference to the standard
0188:                // channel is being explicitly closed, so bump the refCount down
0189:                // artificially to 0. This will ensure that the channel is actually
0190:                // closed, below. Also set the static pointer to NULL for the channel.
0191:
0192:                //CheckForStdChannelsBeingClosed();
0193:
0194:                // This operation should occur at the top of a channel stack.
0195:
0196:                //chanPtr = (Channel *) chan;
0197:                //statePtr = chanPtr->state;
0198:                //chanPtr = statePtr->topChanPtr;
0199:
0200:                if (refCount > 0) {
0201:                    throw new TclRuntimeError(
0202:                            "called Tcl_Close on channel with refCount > 0");
0203:                }
0204:
0205:                // When the channel has an escape sequence driven encoding such as
0206:                // iso2022, the terminated escape sequence must write to the buffer.
0207:
0208:                if ((encoding != null) && (curOut != null)
0209:                /*&& (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)*/) {
0210:                    encodingEnd = true;
0211:                    char[] empty = new char[0];
0212:                    writeChars(empty, 0, 0);
0213:                }
0214:
0215:                // FIXME: Impl channel close callbacks ???
0216:                //Tcl_ClearChannelHandlers(chan);
0217:
0218:                // Invoke the registered close callbacks and delete their records.
0219:
0220:                //while (statePtr->closeCbPtr != (CloseCallback *) NULL) {
0221:                //    cbPtr = statePtr->closeCbPtr;
0222:                //    statePtr->closeCbPtr = cbPtr->nextPtr;
0223:                //    (cbPtr->proc) (cbPtr->clientData);
0224:                //    ckfree((char *) cbPtr);
0225:                //}
0226:
0227:                // Ensure that the last output buffer will be flushed.
0228:
0229:                if ((curOut != null) && (curOut.nextAdded > curOut.nextRemoved)) {
0230:                    bufferReady = true;
0231:                }
0232:
0233:                // If this channel supports it, close the read side, since we don't need it
0234:                // anymore and this will help avoid deadlocks on some channel types.
0235:
0236:                //if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) {
0237:                //    result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp,
0238:                //            TCL_CLOSE_READ);
0239:                //} else {
0240:                //    result = 0;
0241:                //}
0242:                result = 0;
0243:
0244:                // The call to flushChannel will flush any queued output and invoke
0245:                // the close function of the channel driver, or it will set up the
0246:                // channel to be flushed and closed asynchronously.
0247:
0248:                closed = true;
0249:                if ((flushChannel(/*interp*/null, false) != 0)
0250:                        || (result != 0)) {
0251:                    // FIXME: We should raise a TclPosixException here instead
0252:                    //return TCL_ERROR;
0253:                    throw new IOException("Exception in flushChannel");
0254:                }
0255:            }
0256:
0257:            /**
0258:             * CloseChannel -> closeChannel
0259:             *
0260:             * Utility procedure to close a channel and free associated resources.
0261:             *
0262:             * If the channel was stacked, then the it will copy the necessary
0263:             * elements of the NEXT channel into the TOP channel, in essence
0264:             * unstacking the channel.  The NEXT channel will then be freed.
0265:             *
0266:             * If the channel was not stacked, then we will free all the bits
0267:             * for the TOP channel, including the data structure itself.
0268:             *
0269:             * Returns 1 if the channel was stacked, 0 otherwise.
0270:             */
0271:
0272:            protected int closeChannel(Interp interp, int errorCode)
0273:                    throws IOException {
0274:                int result = 0;
0275:                //ChannelState *statePtr;		// state of the channel stack.
0276:                //ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
0277:
0278:                //if (chanPtr == NULL) {
0279:                //    return result;
0280:                //}
0281:                //statePtr = chanPtr->state;
0282:
0283:                // Discard a leftover buffer in the current output buffer field.
0284:
0285:                if (curOut != null) {
0286:                    //ckfree((char *) statePtr->curOutPtr);
0287:                    curOut = null;
0288:                }
0289:
0290:                // The caller guarantees that there are no more buffers
0291:                // queued for output.
0292:
0293:                if (outQueueHead != null) {
0294:                    throw new TclRuntimeError(
0295:                            "TclFlush, closed channel: queued output left");
0296:                }
0297:
0298:                // If the EOF character is set in the channel, append that to the
0299:                // output device.
0300:
0301:                if (eofChar != 0) {
0302:                    try {
0303:                        output.write((byte) eofChar);
0304:                    } catch (IOException ex) {
0305:                        // FIXME: How can we recover here??
0306:                        ex.printStackTrace(System.err);
0307:                    }
0308:                }
0309:
0310:                // Remove this channel from of the list of all channels.
0311:
0312:                //Tcl_CutChannel((Tcl_Channel) chanPtr);
0313:
0314:                // Close and free the channel driver state.
0315:
0316:                //if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
0317:                //    result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp);
0318:                //} else {
0319:                //    result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp,
0320:                //            0);
0321:                //}
0322:
0323:                // Some resources can be cleared only if the bottom channel
0324:                // in a stack is closed. All the other channels in the stack
0325:                // are not allowed to remove.
0326:
0327:                //if (chanPtr == statePtr->bottomChanPtr) {
0328:                //    if (statePtr->channelName != (char *) NULL) {
0329:                //        ckfree((char *) statePtr->channelName);
0330:                //        statePtr->channelName = NULL;
0331:                //    }
0332:
0333:                //    Tcl_FreeEncoding(statePtr->encoding);
0334:                //    if (statePtr->outputStage != NULL) {
0335:                //        ckfree((char *) statePtr->outputStage);
0336:                //       statePtr->outputStage = (char *) NULL;
0337:                //    }
0338:                //}
0339:
0340:                // If we are being called synchronously, report either
0341:                // any latent error on the channel or the current error.
0342:
0343:                if (unreportedError != 0) {
0344:                    errorCode = unreportedError;
0345:                }
0346:                if (errorCode == 0) {
0347:                    errorCode = result;
0348:                    if (errorCode != 0) {
0349:                        // FIXME: How can we deal with this errno issue?
0350:                        //Tcl_SetErrno(errorCode);
0351:                    }
0352:                }
0353:
0354:                // Cancel any outstanding timer.
0355:
0356:                //Tcl_DeleteTimerHandler(statePtr->timer);
0357:
0358:                // Mark the channel as deleted by clearing the type structure.
0359:
0360:                //if (chanPtr->downChanPtr != (Channel *) NULL) {
0361:                //    Channel *downChanPtr = chanPtr->downChanPtr;
0362:
0363:                //    statePtr->nextCSPtr	= tsdPtr->firstCSPtr;
0364:                //    tsdPtr->firstCSPtr = statePtr;
0365:
0366:                //    statePtr->topChanPtr = downChanPtr;
0367:                //    downChanPtr->upChanPtr = (Channel *) NULL;
0368:                //    chanPtr->typePtr = NULL;
0369:
0370:                //    Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);
0371:                //    return Tcl_Close(interp, (Tcl_Channel) downChanPtr);
0372:                //}
0373:
0374:                // There is only the TOP Channel, so we free the remaining
0375:                // pointers we have and then ourselves.  Since this is the
0376:                // last of the channels in the stack, make sure to free the
0377:                // ChannelState structure associated with it.  We use
0378:                // Tcl_EventuallyFree to allow for any last
0379:
0380:                //chanPtr->typePtr = NULL;
0381:
0382:                //Tcl_EventuallyFree((ClientData) statePtr, TCL_DYNAMIC);
0383:                //Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);
0384:
0385:                return errorCode;
0386:            }
0387:
0388:            /**
0389:             * Tcl_Flush -> flush
0390:             *
0391:             * Flushes output data on a channel.
0392:             */
0393:
0394:            void flush() throws IOException {
0395:                // Force current output buffer to be output also.
0396:
0397:                if ((curOut != null) && (curOut.nextAdded > curOut.nextRemoved)) {
0398:                    bufferReady = true;
0399:                }
0400:
0401:                int result = flushChannel(null, false);
0402:                if (result != 0) {
0403:                    // FIXME: Should we throw an exception here?
0404:                    throw new IOException("Exception during flushChannel");
0405:                }
0406:            }
0407:
0408:            /**
0409:             * FlushChannel -> flushChannel
0410:             *
0411:             * This function flushes as much of the queued output as is possible
0412:             * now. If calledFromAsyncFlush is true, it is being called in an
0413:             * event handler to flush channel output asynchronously.
0414:             *
0415:             * Return 0 if successful, else the error code that was returned by the
0416:             * channel type operation.
0417:             *
0418:             * May produce output on a channel. May block indefinitely if the
0419:             * channel is synchronous. May schedule an async flush on the channel.
0420:             * May recycle memory for buffers in the output queue.
0421:             *
0422:             * @param interp                 Interp object.
0423:             * @param calledFromAsyncFlush   True if called from an asynchronous
0424:             *                               flush callback.
0425:             */
0426:
0427:            int flushChannel(Interp interp, boolean calledFromAsyncFlush)
0428:                    throws IOException {
0429:                //ChannelState *statePtr = chanPtr->state;
0430:                ChannelBuffer buf;
0431:                int toWrite; // Amount of output data in current
0432:                // buffer available to be written.
0433:                int written; // Amount of output data actually
0434:                // written in current round.
0435:                int errorCode = 0; // Stores POSIX error codes from
0436:                // channel driver operations.
0437:                boolean wroteSome = false; // Set to true if any data was
0438:                // written to the driver.
0439:
0440:                try {
0441:
0442:                    // Prevent writing on a dead channel -- a channel that has been closed
0443:                    // but not yet deallocated. This can occur if the exit handler for the
0444:                    // channel deallocation runs before all channels are deregistered in
0445:                    // all interpreters.
0446:
0447:                    //if (CheckForDeadChannel(interp, statePtr)) return -1;
0448:
0449:                    // Loop over the queued buffers and attempt to flush as
0450:                    // much as possible of the queued output to the channel.
0451:
0452:                    while (true) {
0453:                        // If the queue is empty and there is a ready current buffer, OR if
0454:                        // the current buffer is full, then move the current buffer to the
0455:                        // queue.
0456:
0457:                        if (((curOut != null) && (curOut.nextAdded == curOut.bufLength))
0458:                                || (bufferReady && (outQueueHead == null))) {
0459:                            bufferReady = false;
0460:                            curOut.next = null;
0461:                            if (outQueueHead == null) {
0462:                                outQueueHead = curOut;
0463:                            } else {
0464:                                outQueueTail.next = curOut;
0465:                            }
0466:                            outQueueTail = curOut;
0467:                            curOut = null;
0468:                        }
0469:                        buf = outQueueHead;
0470:
0471:                        // If we are not being called from an async flush and an async
0472:                        // flush is active, we just return without producing any output.
0473:
0474:                        if ((!calledFromAsyncFlush) && bgFlushScheduled) {
0475:                            return 0;
0476:                        }
0477:
0478:                        // If the output queue is still empty, break out of the while loop.
0479:
0480:                        if (buf == null) {
0481:                            break; // Out of the "while (true)".
0482:                        }
0483:
0484:                        // Produce the output on the channel.
0485:
0486:                        toWrite = buf.nextAdded - buf.nextRemoved;
0487:                        //written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData,
0488:                        //        bufPtr->buf + bufPtr->nextRemoved, toWrite,
0489:                        //        &errorCode);
0490:                        try {
0491:                            output.write(buf.buf, buf.nextRemoved, toWrite);
0492:                            written = toWrite;
0493:                        } catch (IOException ex) {
0494:                            // FIXME: How can we recover and get posix errors?
0495:                            ex.printStackTrace(System.err);
0496:                            errorCode = TclPosixException.EIO; // Generic I/O error ???
0497:                            written = -1;
0498:                        }
0499:
0500:                        // If the write failed completely attempt to start the asynchronous
0501:                        // flush mechanism and break out of this loop - do not attempt to
0502:                        // write any more output at this time.
0503:
0504:                        if (written < 0) {
0505:                            // If the last attempt to write was interrupted, simply retry.
0506:
0507:                            if (errorCode == TclPosixException.EINTR) {
0508:                                errorCode = 0;
0509:                                continue;
0510:                            }
0511:
0512:                            // If the channel is non-blocking and we would have blocked,
0513:                            // start a background flushing handler and break out of the loop.
0514:
0515:                            if ((errorCode == TclPosixException.EWOULDBLOCK)
0516:                                    || (errorCode == TclPosixException.EAGAIN)) {
0517:                                // This used to check for CHANNEL_NONBLOCKING, and panic
0518:                                // if the channel was blocking.  However, it appears
0519:                                // that setting stdin to -blocking 0 has some effect on
0520:                                // the stdout when it's a tty channel (dup'ed underneath)
0521:
0522:                                if (!bgFlushScheduled) {
0523:                                    bgFlushScheduled = true;
0524:                                    updateInterest();
0525:                                }
0526:                                errorCode = 0;
0527:                                break;
0528:                            }
0529:
0530:                            // Decide whether to report the error upwards or defer it.
0531:
0532:                            if (calledFromAsyncFlush) {
0533:                                if (unreportedError == 0) {
0534:                                    unreportedError = errorCode;
0535:                                }
0536:                            } else {
0537:                                // FIXME: Need to figure out what to do here!
0538:                                //Tcl_SetErrno(errorCode);
0539:                                //if (interp != NULL) {
0540:                                //    // Casting away CONST here is safe because the
0541:                                //    // TCL_VOLATILE flag guarantees CONST treatment
0542:                                //    // of the Posix error string.
0543:                                //    Tcl_SetResult(interp,
0544:                                //            (char *) Tcl_PosixError(interp), TCL_VOLATILE);
0545:                            }
0546:
0547:                            // When we get an error we throw away all the output
0548:                            // currently queued.
0549:
0550:                            discardQueued();
0551:                            continue;
0552:                        } else {
0553:                            wroteSome = true;
0554:                        }
0555:
0556:                        buf.nextRemoved += written;
0557:
0558:                        // If this buffer is now empty, recycle it.
0559:
0560:                        if (buf.nextRemoved == buf.nextAdded) {
0561:                            outQueueHead = buf.next;
0562:                            if (outQueueHead == null) {
0563:                                outQueueTail = null;
0564:                            }
0565:                            recycleBuffer(buf, false);
0566:                        }
0567:                    } // Closes "while (1)".
0568:
0569:                    // If we wrote some data while flushing in the background, we are done.
0570:                    // We can't finish the background flush until we run out of data and
0571:                    // the channel becomes writable again.  This ensures that all of the
0572:                    // pending data has been flushed at the system level.
0573:
0574:                    if (bgFlushScheduled) {
0575:                        if (wroteSome) {
0576:                            return errorCode;
0577:                        } else if (outQueueHead == null) {
0578:                            bgFlushScheduled = false;
0579:                            // FIXME: What is this watchProc?
0580:                            //(chanPtr->typePtr->watchProc)(chanPtr->instanceData,
0581:                            //        statePtr->interestMask);
0582:                        }
0583:                    }
0584:
0585:                    // If the channel is flagged as closed, delete it when the refCount
0586:                    // drops to zero, the output queue is empty and there is no output
0587:                    // in the current output buffer.
0588:
0589:                    if (closed
0590:                            && (refCount <= 0)
0591:                            && (outQueueHead == null)
0592:                            && ((curOut == null) || (curOut.nextAdded == curOut.nextRemoved))) {
0593:                        return closeChannel(interp, errorCode);
0594:                    }
0595:                    return errorCode;
0596:
0597:                } finally {
0598:                    output.flush();
0599:
0600:                    // In some implementations (Sun JDK 1.4 on Win32)
0601:                    // the flush method above does not actually sync
0602:                    // output data or files. Call sync when we know
0603:                    // the object is a file and not something else
0604:                    // like a socket stream.
0605:
0606:                    if (canSync) {
0607:                        FileOutputStream fos = (FileOutputStream) output;
0608:                        fos.getFD().sync();
0609:                    }
0610:                }
0611:            }
0612:
0613:            void setEncoding(String inEncoding) {
0614:                encoding = inEncoding;
0615:            }
0616:
0617:            void setEofChar(char inEofChar) {
0618:                eofChar = inEofChar;
0619:            }
0620:
0621:            void setTranslation(int inTranslation) {
0622:                translation = inTranslation;
0623:            }
0624:
0625:            void setBuffering(int inBuffering) {
0626:                buffering = inBuffering;
0627:            }
0628:
0629:            void setBufferSize(int inBufSize) {
0630:                bufSize = inBufSize;
0631:                outputStage = null;
0632:            }
0633:
0634:            void setBlocking(boolean inBlocking) {
0635:                blocking = inBlocking;
0636:            }
0637:
0638:            boolean isBlocked() {
0639:                return blocked;
0640:            }
0641:
0642:            // Helper class to implement integer pass by reference.
0643:
0644:            private class IntPtr {
0645:                int i;
0646:
0647:                IntPtr() {
0648:                }
0649:
0650:                IntPtr(int value) {
0651:                    i = value;
0652:                }
0653:            }
0654:
0655:            /**
0656:             * RecycleBuffer -> recycleBuffer
0657:             *
0658:             * Helper function to recycle output buffers. Ensures that
0659:             * that curOut is set to a buffer. Only if these conditions
0660:             * are met is the buffer released so that it can be
0661:             * garbage collected.
0662:             */
0663:
0664:            private void recycleBuffer(ChannelBuffer buf, boolean mustDiscard) {
0665:
0666:                if (mustDiscard)
0667:                    return;
0668:
0669:                // Only save buffers which are at least as big as the requested
0670:                // buffersize for the channel. This is to honor dynamic changes
0671:                // of the buffersize made by the user.
0672:
0673:                if ((buf.bufLength - buf.BUFFER_PADDING) < bufSize) {
0674:                    return;
0675:                }
0676:
0677:                if (curOut == null) {
0678:                    curOut = buf;
0679:                    buf.nextRemoved = buf.BUFFER_PADDING;
0680:                    buf.nextAdded = buf.BUFFER_PADDING;
0681:                    buf.next = null;
0682:                }
0683:            }
0684:
0685:            /**
0686:             * DiscardOutputQueued -> discardQueued
0687:             *
0688:             * Discards all output queued in the output queue of a channel.
0689:             */
0690:
0691:            private void discardQueued() {
0692:                ChannelBuffer buf;
0693:
0694:                while (outQueueHead != null) {
0695:                    buf = outQueueHead;
0696:                    outQueueHead = buf.next;
0697:                    recycleBuffer(buf, false);
0698:                }
0699:                outQueueHead = null;
0700:                outQueueTail = null;
0701:            }
0702:
0703:            /**
0704:             * UpdateInterest -> updateInterest
0705:             *
0706:             * Arrange for the notifier to call us back at appropriate times
0707:             * based on the current state of the channel.
0708:             */
0709:
0710:            void updateInterest() {
0711:                // FIXME: Currently unimplemented
0712:            }
0713:
0714:            /**
0715:             * Tcl_OutputBuffered -> getNumBufferedBytes
0716:             *
0717:             * Return the number of bytes that are current buffered.
0718:             */
0719:
0720:            int getNumBufferedBytes() {
0721:                ChannelBuffer buf;
0722:                int IOQueued = 0;
0723:                for (buf = outQueueHead; buf != null; buf = buf.next) {
0724:                    IOQueued += buf.nextAdded - buf.nextRemoved;
0725:                }
0726:                if ((curOut != null) && (curOut.nextAdded > curOut.nextRemoved)) {
0727:                    //bufferReady = true;
0728:                    IOQueued += curOut.nextAdded - curOut.nextRemoved;
0729:                }
0730:                return IOQueued;
0731:            }
0732:
0733:            /**
0734:             * seekCheckBuferReady
0735:             *
0736:             * This method is used by the seek command to check
0737:             * the channel for buffered output and mark the
0738:             * buffer as ready to flush if found.
0739:             */
0740:
0741:            void seekCheckBuferReady() {
0742:                if ((curOut != null) && (curOut.nextAdded > curOut.nextRemoved)) {
0743:                    bufferReady = true;
0744:                }
0745:            }
0746:
0747:            /**
0748:             * TranslateOutputEOL -> translateEOL
0749:             *
0750:             * Helper function for writeBytes() and writeChars().  Converts the
0751:             * '\n' characters in the source buffer into the appropriate EOL
0752:             * form specified by the output translation mode.
0753:             *
0754:             * EOL translation stops either when the source buffer is empty
0755:             * or the output buffer is full.
0756:             *
0757:             * When converting to CRLF mode and there is only 1 byte left in
0758:             * the output buffer, this routine stores the '\r' in the last
0759:             * byte and then stores the '\n' in the byte just past the end of the 
0760:             * buffer.  The caller is responsible for passing in a buffer that
0761:             * is large enough to hold the extra byte.
0762:             *
0763:             * Results:
0764:             *
0765:             * The return value is 1 if a '\n' was translated from the source
0766:             * buffer, or 0 otherwise -- this can be used by the caller to
0767:             * decide to flush a line-based channel even though the channel
0768:             * buffer is not full.
0769:             *
0770:             * dstLenPtr.i is filled with how many bytes of the output buffer
0771:             * were used.  As mentioned above, this can be one more that
0772:             * the output buffer's specified length if a CRLF was stored.
0773:             *
0774:             * srcLenPtr.i is filled with how many bytes of the source buffer
0775:             * were consumed.
0776:             *
0777:             * It may be obvious, but bears mentioning that when converting
0778:             * in CRLF mode (which requires two bytes of storage in the output
0779:             * buffer), the number of bytes consumed from the source buffer
0780:             * will be less than the number of bytes stored in the output buffer.
0781:             *
0782:             * @param dstArray, Output buffer to fill with translated bytes or chars.
0783:             * @param dstStart, First unused index in the dst output array.
0784:             * @param srcArray, Input buffer that holds the bytes or chars to translate
0785:             * @param srcStart, Index of first available byte in src array.
0786:
0787:             * @param dstLenPtr, On entry, the maximum length of output
0788:             *                   buffer in bytes or chars.  On exit, the number of
0789:             *                   bytes or chars actually used in output buffer.
0790:             * @param srcLenPtr, On entry, the length of source buffer.
0791:             *                   On exit, the number of bytes or chars read from
0792:             *                   the source buffer.
0793:             */
0794:
0795:            boolean translateEOL(Object dstArray, int dstStart,
0796:                    Object srcArray, int srcStart, IntPtr dstLenPtr,
0797:                    IntPtr srcLenPtr) {
0798:                final boolean debug = false;
0799:
0800:                // Figure out if the srcArray and dstArray buffers
0801:                // are byte or char arrays.
0802:                boolean isCharType;
0803:                char[] srcArrayChar, dstArrayChar;
0804:                byte[] srcArrayByte, dstArrayByte;
0805:
0806:                if ((srcArray instanceof  char[])
0807:                        && (dstArray instanceof  char[])) {
0808:                    isCharType = true;
0809:                    srcArrayChar = (char[]) srcArray;
0810:                    dstArrayChar = (char[]) dstArray;
0811:                    srcArrayByte = null;
0812:                    dstArrayByte = null;
0813:                } else if ((srcArray instanceof  byte[])
0814:                        && (dstArray instanceof  byte[])) {
0815:                    isCharType = false;
0816:                    srcArrayChar = null;
0817:                    dstArrayChar = null;
0818:                    srcArrayByte = (byte[]) srcArray;
0819:                    dstArrayByte = (byte[]) dstArray;
0820:                } else {
0821:                    throw new TclRuntimeError("unknown array argument types");
0822:                }
0823:
0824:                int src, dst, dstEnd, srcLen;
0825:                boolean newlineFound;
0826:
0827:                src = srcStart;
0828:                dst = dstStart;
0829:                newlineFound = false;
0830:                srcLen = srcLenPtr.i;
0831:
0832:                switch (translation) {
0833:                case TclIO.TRANS_LF: {
0834:                    if (isCharType) {
0835:                        for (dstEnd = dst + srcLen; dst < dstEnd;) {
0836:                            if (srcArrayChar[src] == '\n') {
0837:                                newlineFound = true;
0838:                            }
0839:                            dstArrayChar[dst++] = srcArrayChar[src++];
0840:                        }
0841:                    } else {
0842:                        for (dstEnd = dst + srcLen; dst < dstEnd;) {
0843:                            if (srcArrayByte[src] == '\n') {
0844:                                newlineFound = true;
0845:                            }
0846:                            dstArrayByte[dst++] = srcArrayByte[src++];
0847:                        }
0848:                    }
0849:                    dstLenPtr.i = srcLen;
0850:                    break;
0851:                }
0852:                case TclIO.TRANS_CR: {
0853:                    if (isCharType) {
0854:                        for (dstEnd = dst + srcLen; dst < dstEnd;) {
0855:                            if (srcArrayChar[src] == '\n') {
0856:                                dstArrayChar[dst++] = '\r';
0857:                                newlineFound = true;
0858:                                src++;
0859:                            } else {
0860:                                dstArrayChar[dst++] = srcArrayChar[src++];
0861:                            }
0862:                        }
0863:                    } else {
0864:                        for (dstEnd = dst + srcLen; dst < dstEnd;) {
0865:                            if (srcArrayByte[src] == '\n') {
0866:                                dstArrayByte[dst++] = (byte) '\r';
0867:                                newlineFound = true;
0868:                                src++;
0869:                            } else {
0870:                                dstArrayByte[dst++] = srcArrayByte[src++];
0871:                            }
0872:                        }
0873:                    }
0874:                    dstLenPtr.i = srcLen;
0875:                    break;
0876:                }
0877:                case TclIO.TRANS_CRLF: {
0878:                    // Since this causes the number of bytes to grow, we
0879:                    // start off trying to put 'srcLen' bytes into the
0880:                    // output buffer, but allow it to store more bytes, as
0881:                    // long as there's still source bytes and room in the
0882:                    // output buffer.
0883:
0884:                    int dstMax;
0885:                    //int dstStart, srcStart;
0886:
0887:                    //dstStart = dst;
0888:                    dstMax = dst + dstLenPtr.i;
0889:
0890:                    //srcStart = src;
0891:
0892:                    if (srcLen < dstLenPtr.i) {
0893:                        dstEnd = dst + srcLen;
0894:                    } else {
0895:                        dstEnd = dst + dstLenPtr.i;
0896:                    }
0897:
0898:                    if (isCharType) {
0899:                        while (dst < dstEnd) {
0900:                            if (srcArrayChar[src] == '\n') {
0901:                                if (dstEnd < dstMax) {
0902:                                    dstEnd++;
0903:                                }
0904:                                dstArrayChar[dst++] = '\r';
0905:                                newlineFound = true;
0906:                            }
0907:                            dstArrayChar[dst++] = srcArrayChar[src++];
0908:                        }
0909:                    } else {
0910:                        while (dst < dstEnd) {
0911:                            if (srcArrayByte[src] == '\n') {
0912:                                if (dstEnd < dstMax) {
0913:                                    dstEnd++;
0914:                                }
0915:                                dstArrayByte[dst++] = (byte) '\r';
0916:                                newlineFound = true;
0917:                            }
0918:                            dstArrayByte[dst++] = srcArrayByte[src++];
0919:                        }
0920:                    }
0921:
0922:                    srcLenPtr.i = src - srcStart;
0923:                    dstLenPtr.i = dst - dstStart;
0924:                    break;
0925:                }
0926:                default: {
0927:                    break;
0928:                }
0929:                }
0930:                return newlineFound;
0931:            }
0932:
0933:            /**
0934:             * Tcl_UtfToExternal -> unicodeToExternal
0935:             *
0936:             * Convert a source buffer from unicode characters to a specified encoding.
0937:             *
0938:             * FIXME: Add doc for return values
0939:             *
0940:             * @param src,         Source characters.
0941:             * @param srcOff,      First index in src input array.
0942:             * @param srcLen,      Number of characters in src buffer.
0943:             * @param dst,         Array to store encoded bytes in.
0944:             * @param dstOff,      First available index in dst array.
0945:             * @param dstLen,      Length of dst array.
0946:             * @param srcReadPtr,  Filled with the number of characters from
0947:             *                     the source string that were converted.
0948:             *                     This may be less than the original source
0949:             *                     length if there was a problem converting
0950:             *                     some source characters.
0951:             * @param dstWrotePtr, Filled with the number of bytes that were
0952:             *                     stored in the output buffer as a result of
0953:             *                     the conversion
0954:             * @param dstCharsPtr, Filled with the number of characters that
0955:             *                     correspond to the bytes stored in the
0956:             *                     output buffer.
0957:             */
0958:
0959:            int unicodeToExternal(char[] src, int srcOff, int srcLen,
0960:                    byte[] dst, int dstOff, int dstLen, IntPtr srcReadPtr,
0961:                    IntPtr dstWrotePtr, IntPtr dstCharsPtr) {
0962:                final boolean debug = false;
0963:                int result;
0964:
0965:                if (encoding == null) {
0966:                    throw new TclRuntimeError(
0967:                            "unicodeToExternal called with null encoding");
0968:                }
0969:
0970:                if (debug) {
0971:                    System.out.println("unicodeToExternal(" + srcLen + " "
0972:                            + dstLen + ")");
0973:                }
0974:
0975:                // If encoder was flushed already then return 0.
0976:
0977:                if ((srcLen == 0) && !encodingEnd) {
0978:                    srcReadPtr.i = 0;
0979:                    if (dstWrotePtr != null)
0980:                        dstWrotePtr.i = 0;
0981:                    if (dstCharsPtr != null)
0982:                        dstCharsPtr.i = 0;
0983:                    return 0;
0984:                }
0985:
0986:                if (debug) {
0987:                    System.out.println("now to encode char array of length "
0988:                            + srcLen);
0989:                    System.out.println("srcOff is " + srcOff);
0990:                    for (int i = srcOff; i < (srcOff + srcLen); i++) {
0991:                        System.out.println("(char) '" + src[i] + "'");
0992:                    }
0993:                    System.out.println("encoded as " + encoding);
0994:                }
0995:
0996:                if (cse == null) {
0997:                    // Note that UnsupportedCharsetException should never be raised
0998:                    // here since EncodingCmd.isSupported() should have already
0999:                    // returned true for this encoding.
1000:
1001:                    Charset chrset = Charset.forName(encoding);
1002:                    cse = chrset.newEncoder();
1003:                }
1004:
1005:                int chars_read, bytes_written;
1006:                int bytes_flushed = 0;
1007:
1008:                // A CharBuffer wraps the src char[] and
1009:                // handles buffer size issues. A ByteBuffer
1010:                // wraps the dst char[] and handles buffer
1011:                // size issues.
1012:
1013:                CharBuffer srcb = CharBuffer.wrap(src, srcOff, srcLen);
1014:                ByteBuffer dstb = ByteBuffer.wrap(dst, dstOff, dstLen);
1015:
1016:                int srcbStartPos = srcb.position();
1017:                int dstbStartPos = dstb.position();
1018:
1019:                // Pass atEOF flag as true when encodingEnd flag
1020:                // was set to true in close().
1021:
1022:                boolean atEOF = encodingEnd;
1023:
1024:                CoderResult cresult = cse.encode(srcb, dstb, atEOF);
1025:
1026:                chars_read = srcb.position() - srcbStartPos;
1027:                bytes_written = dstb.position() - dstbStartPos;
1028:
1029:                if (debug) {
1030:                    System.out.println("encoded " + bytes_written
1031:                            + " bytes from " + chars_read
1032:                            + " chars (EOF flag was " + atEOF + ")");
1033:                }
1034:
1035:                // For the case where an encoder needs to write bytes
1036:                // at the end of the data, the close() method passes
1037:                // an empty char[] and sets encodingEnd.
1038:
1039:                if (atEOF) {
1040:                    if (chars_read != 0 && bytes_written != 0) {
1041:                        throw new TclRuntimeError(
1042:                                "Should have encoded no chars at EOF, "
1043:                                        + chars_read + " " + bytes_written);
1044:                    }
1045:
1046:                    cresult = cse.flush(dstb);
1047:
1048:                    bytes_flushed = dstb.position() - dstbStartPos;
1049:                    bytes_written += bytes_flushed;
1050:
1051:                    if (debug) {
1052:                        System.out.println("flushed " + bytes_flushed
1053:                                + " bytes at EOF");
1054:                    }
1055:
1056:                    encodingEnd = false;
1057:                }
1058:
1059:                if (!atEOF && (chars_read == 0) && (bytes_written == 0)) {
1060:                    throw new TclRuntimeError("No characters converted");
1061:                }
1062:
1063:                srcReadPtr.i = chars_read;
1064:                if (dstWrotePtr != null)
1065:                    dstWrotePtr.i = bytes_written;
1066:                if (dstCharsPtr != null)
1067:                    dstCharsPtr.i = chars_read;
1068:
1069:                // FIXME: When do we return error codes?
1070:                result = 0;
1071:
1072:                return result;
1073:            }
1074:
1075:            /**
1076:             * WriteBytes -> writeBytes
1077:             *
1078:             * Write a sequence of bytes into an output buffer, may queue the
1079:             * buffer for output if it gets full, and also remembers whether the
1080:             * current buffer is ready e.g. if it contains a newline and we are in
1081:             * line buffering mode.
1082:             *
1083:             * The number of bytes written or -1 in case of error. If -1,
1084:             * Tcl_GetErrno will return the error code.
1085:             * 
1086:             * May buffer up output and may cause output to be produced on the
1087:             * channel.
1088:             *
1089:             * @param src          Bytes to write.
1090:             * @param srfOff       First index in src array.
1091:             * @param srfLen       Number of bytes to write.
1092:             */
1093:
1094:            int writeBytes(byte[] srcArray, int srcOff, int srcLen)
1095:                    throws IOException {
1096:                ChannelBuffer buf;
1097:                byte[] dstArray;
1098:                int dst, src, dstMax, sawLF, total, savedLF;
1099:                IntPtr dstLen = new IntPtr(), toWrite = new IntPtr();
1100:
1101:                total = 0;
1102:                sawLF = 0;
1103:                savedLF = 0;
1104:                src = srcOff;
1105:
1106:                // Loop over all bytes in src, storing them in output buffer with
1107:                // proper EOL translation.
1108:
1109:                while (srcLen + savedLF > 0) {
1110:                    buf = curOut;
1111:                    if (buf == null) {
1112:                        buf = new ChannelBuffer(bufSize);
1113:                        curOut = buf;
1114:                    }
1115:                    //dst = bufPtr->buf + bufPtr->nextAdded;
1116:                    dstArray = buf.buf;
1117:                    dst = buf.nextAdded;
1118:                    dstMax = buf.bufLength - buf.nextAdded;
1119:                    dstLen.i = dstMax;
1120:
1121:                    toWrite.i = dstLen.i;
1122:                    if (toWrite.i > srcLen) {
1123:                        toWrite.i = srcLen;
1124:                    }
1125:
1126:                    if (savedLF != 0) {
1127:                        // A '\n' was left over from last call to translateEOL()
1128:                        // and we need to store it in this buffer.  If the channel is
1129:                        // line-based, we will need to flush it.
1130:
1131:                        dstArray[dst++] = (byte) '\n';
1132:                        dstLen.i--;
1133:                        sawLF++;
1134:                    }
1135:                    if (translateEOL(dstArray, dst, srcArray, src, dstLen,
1136:                            toWrite)) {
1137:                        sawLF++;
1138:                    }
1139:                    dstLen.i += savedLF;
1140:                    savedLF = 0;
1141:
1142:                    if (dstLen.i > dstMax) {
1143:                        savedLF = 1;
1144:                        dstLen.i = dstMax;
1145:                    }
1146:                    buf.nextAdded += dstLen.i;
1147:                    if (checkFlush(buf, (sawLF != 0)) != 0) {
1148:                        return -1;
1149:                    }
1150:                    total += dstLen.i;
1151:                    src += toWrite.i;
1152:                    srcLen -= toWrite.i;
1153:                    sawLF = 0;
1154:                }
1155:                return total;
1156:            }
1157:
1158:            /**
1159:             * CheckFlush -> checkFlush
1160:             *
1161:             * Helper function for writeBytes() and writeChars().  If the
1162:             * channel buffer is ready to be flushed, flush it.
1163:             * 
1164:             * The return value is -1 if there was a problem flushing the
1165:             * channel buffer, or 0 otherwise.
1166:             *
1167:             * The buffer will be recycled if it is flushed.
1168:             *
1169:             * @param buf          Channel buffer to possibly flush.
1170:             * @param newlineFlag  True if a the channel buffer
1171:             *                     contains a newline.
1172:             */
1173:
1174:            int checkFlush(ChannelBuffer buf, boolean newlineFlag)
1175:                    throws IOException {
1176:                // The current buffer is ready for output:
1177:                // 1. if it is full.
1178:                // 2. if it contains a newline and this channel is line-buffered.
1179:                // 3. if it contains any output and this channel is unbuffered.
1180:
1181:                if (!bufferReady) {
1182:                    if (buf.nextAdded == buf.bufLength) {
1183:                        bufferReady = true;
1184:                    } else if (buffering == TclIO.BUFF_LINE) {
1185:                        if (newlineFlag) {
1186:                            bufferReady = true;
1187:                        }
1188:                    } else if (buffering == TclIO.BUFF_NONE) {
1189:                        bufferReady = true;
1190:                    }
1191:                }
1192:                if (bufferReady) {
1193:                    if (flushChannel(null, false) != 0) {
1194:                        return -1;
1195:                    }
1196:                }
1197:                return 0;
1198:            }
1199:
1200:            /**
1201:             * WriteChars -> writeChars
1202:             *
1203:             * Convert chars to the channel's external encoding and
1204:             * write the produced bytes into an output buffer, may queue the
1205:             * buffer for output if it gets full, and also remembers whether the
1206:             * current buffer is ready e.g. if it contains a newline and we are in
1207:             * line buffering mode.
1208:             *
1209:             * The number of bytes written or -1 in case of error. If -1,
1210:             * Tcl_GetErrno will return the error code.
1211:             *
1212:             * May buffer up output and may cause output to be produced on the
1213:             * channel.
1214:             *
1215:             * @param src          Chars to write.
1216:             * @param srfOff       First index in src array.
1217:             * @param srfLen       Number of chars to write.
1218:             */
1219:
1220:            int writeChars(char[] srcArray, int srcOff, int srcLen)
1221:                    throws IOException {
1222:                final boolean debug = false;
1223:                if (debug) {
1224:                    System.out.println("writeChars(" + srcLen + ")");
1225:                }
1226:
1227:                //ChannelState *statePtr = chanPtr->state;	// state info for channel
1228:                ChannelBuffer buf;
1229:                char[] stageArray;
1230:                byte[] dstArray;
1231:                int stage, src, dst;
1232:                int saved, savedLF, sawLF, total, dstLen, stageMax;
1233:                int endEncoding, result;
1234:                boolean consumedSomething;
1235:                //Tcl_Encoding encoding;
1236:                byte[] safe = new byte[ChannelBuffer.BUFFER_PADDING];
1237:                IntPtr stageLen = new IntPtr(), toWrite = new IntPtr();
1238:                IntPtr stageRead = new IntPtr(), dstWrote = new IntPtr();
1239:
1240:                total = 0;
1241:                sawLF = 0;
1242:                savedLF = 0;
1243:                saved = 0;
1244:                //encoding = statePtr->encoding;
1245:                src = 0;
1246:
1247:                // Write the terminated escape sequence even if srcLen is 0.
1248:
1249:                endEncoding = (encodingEnd ? 1 : 0);
1250:
1251:                // Loop over all characters in src, storing them in staging buffer
1252:                // with proper EOL translation.
1253:
1254:                consumedSomething = true;
1255:                while (consumedSomething
1256:                        && (srcLen + savedLF + endEncoding > 0)) {
1257:                    consumedSomething = false;
1258:                    if (outputStage == null) {
1259:                        outputStage = new char[bufSize + 2];
1260:                    }
1261:                    stageArray = outputStage;
1262:                    stage = 0;
1263:                    stageMax = bufSize;
1264:                    stageLen.i = stageMax;
1265:
1266:                    toWrite.i = stageLen.i;
1267:                    if (toWrite.i > srcLen) {
1268:                        toWrite.i = srcLen;
1269:                    }
1270:
1271:                    if (savedLF != 0) {
1272:                        // A '\n' was left over from last call to TranslateOutputEOL()
1273:                        // and we need to store it in the staging buffer.  If the
1274:                        // channel is line-based, we will need to flush the output
1275:                        // buffer (after translating the staging buffer).
1276:
1277:                        stageArray[stage++] = '\n';
1278:                        stageLen.i--;
1279:                        sawLF++;
1280:                    }
1281:                    if (translateEOL(stageArray, stage, srcArray, src,
1282:                            stageLen, toWrite)) {
1283:                        sawLF++;
1284:                    }
1285:
1286:                    stage -= savedLF;
1287:                    stageLen.i += savedLF;
1288:                    savedLF = 0;
1289:
1290:                    if (stageLen.i > stageMax) {
1291:                        savedLF = 1;
1292:                        stageLen.i = stageMax;
1293:                    }
1294:                    src += toWrite.i;
1295:                    srcLen -= toWrite.i;
1296:
1297:                    if (debug) {
1298:                        System.out.println("moved " + stageLen.i
1299:                                + " chars to stageArray");
1300:                    }
1301:
1302:                    // Loop over all characters in staging buffer, converting them
1303:                    // to external encoding, storing them in output buffer.
1304:
1305:                    while (stageLen.i + saved + endEncoding > 0) {
1306:                        buf = curOut;
1307:                        if (buf == null) {
1308:                            buf = new ChannelBuffer(bufSize);
1309:                            curOut = buf;
1310:                        }
1311:                        // dst = buf.buf + buf.nextAdded;
1312:                        dstArray = buf.buf;
1313:                        dst = buf.nextAdded;
1314:                        dstLen = buf.bufLength - buf.nextAdded;
1315:
1316:                        if (saved != 0) {
1317:                            // Here's some translated bytes left over from the last
1318:                            // buffer that we need to stick at the beginning of this
1319:                            // buffer.
1320:
1321:                            System.arraycopy(safe, 0, dstArray, dst, saved);
1322:                            buf.nextAdded += saved;
1323:                            dst += saved;
1324:                            dstLen -= saved;
1325:                            saved = 0;
1326:                        }
1327:
1328:                        if (debug) {
1329:                            System.out.println("invoking unicodeToExternal("
1330:                                    + stageLen.i + ")");
1331:                        }
1332:
1333:                        result = unicodeToExternal(stageArray, stage,
1334:                                stageLen.i, dstArray, dst, dstLen
1335:                                        + ChannelBuffer.BUFFER_PADDING,
1336:                                stageRead, dstWrote, null);
1337:
1338:                        // Fix for SF #506297, reported by Martin Forssen
1339:                        // <ruric@users.sourceforge.net>.
1340:                        //
1341:                        // The encoding chosen in the script exposing the bug writes out
1342:                        // three intro characters when TCL_ENCODING_START is set, but does
1343:                        // not consume any input as TCL_ENCODING_END is cleared. As some
1344:                        // output was generated the enclosing loop calls UtfToExternal
1345:                        // again, again with START set. Three more characters in the out
1346:                        // and still no use of input ... To break this infinite loop we
1347:                        // remove TCL_ENCODING_START from the set of flags after the first
1348:                        // call (no condition is required, the later calls remove an unset
1349:                        // flag, which is a no-op). This causes the subsequent calls to
1350:                        // UtfToExternal to consume and convert the actual input.
1351:
1352:                        encodingStart = false;
1353:
1354:                        // The following can never happen since we use unicode characters.
1355:                        //
1356:                        //if ((result != 0) && ((stageRead.i + dstWrote.i) == 0)) {
1357:                        //    // We have an incomplete UTF-8 character at the end of the
1358:                        //    // staging buffer.  It will get moved to the beginning of the
1359:                        //    // staging buffer followed by more bytes from src.
1360:                        //
1361:                        //    src -= stageLen.i;
1362:                        //    srcLen += stageLen.i;
1363:                        //    stageLen.i = 0;
1364:                        //    savedLF = 0;
1365:                        //    break;
1366:                        //}
1367:                        buf.nextAdded += dstWrote.i;
1368:                        if (buf.nextAdded > buf.bufLength) {
1369:                            // When translating from unicode to external encoding, we
1370:                            // allowed the translation to produce a character that
1371:                            // crossed the end of the output buffer, so that we would
1372:                            // get a completely full buffer before flushing it.  The
1373:                            // extra bytes will be moved to the beginning of the next
1374:                            // buffer.
1375:
1376:                            saved = buf.nextAdded - buf.bufLength;
1377:                            System.arraycopy(dstArray, dst + dstLen, safe, 0,
1378:                                    saved);
1379:                            buf.nextAdded = buf.bufLength;
1380:                        }
1381:                        if (checkFlush(buf, (sawLF != 0)) != 0) {
1382:                            return -1;
1383:                        }
1384:
1385:                        total += dstWrote.i;
1386:                        stage += stageRead.i;
1387:                        stageLen.i -= stageRead.i;
1388:                        sawLF = 0;
1389:
1390:                        consumedSomething = true;
1391:
1392:                        // If all translated characters are written to the buffer,
1393:                        // endEncoding is set to 0 because the escape sequence may be
1394:                        // output.
1395:
1396:                        if ((stageLen.i + saved == 0) && (result == 0)) {
1397:                            endEncoding = 0;
1398:                        }
1399:                    }
1400:                }
1401:
1402:                // If nothing was written and it happened because there was no progress
1403:                // in the UTF conversion, we throw an error.
1404:
1405:                if (!consumedSomething && (total == 0)) {
1406:                    //Tcl_SetErrno (EINVAL);
1407:                    return -1;
1408:                }
1409:                return total;
1410:            }
1411:
1412:            /**
1413:             * DoWriteChars -> doWriteChars
1414:             *
1415:             * Takes a sequence of characters and converts them for output
1416:             * using the channel's current encoding, may queue the buffer for
1417:             * output if it gets full, and also remembers whether the current
1418:             * buffer is ready e.g. if it contains a newline and we are in
1419:             * line buffering mode. Compensates stacking, i.e. will redirect the
1420:             * data from the specified channel to the topmost channel in a stack.
1421:             *
1422:             * The number of bytes written or -1 in case of error. If -1,
1423:             * Tcl_GetErrno will return the error code.
1424:             * 
1425:             * May buffer up output and may cause output to be produced on the
1426:             * channel.
1427:             *
1428:             * @param src          Chars to write.
1429:             * @param srfOff       First index in src array.
1430:             * @param srfLen       Number of chars to write.
1431:             */
1432:
1433:            int doWriteChars(char[] src, int srcOff, int srcLen) {
1434:                return -1;
1435:            }
1436:
1437:            /**
1438:             * Tcl_WriteObj -> writeObj
1439:             *
1440:             * Takes the Tcl object and queues its contents for output.  If the
1441:             * encoding of the channel is NULL, takes the byte-array representation
1442:             * of the object and queues those bytes for output.  Otherwise, takes
1443:             * the characters in the UTF-8 (string) representation of the object
1444:             * and converts them for output using the channel's current encoding.
1445:             * May flush internal buffers to output if one becomes full or is ready
1446:             * for some other reason, e.g. if it contains a newline and the channel
1447:             * is in line buffering mode.
1448:             *
1449:             * The number of bytes written or -1 in case of error. If -1,
1450:             * Tcl_GetErrno will return the error code.
1451:             * 
1452:             * May buffer up output and may cause output to be produced on the
1453:             * channel.
1454:             *
1455:             * @param obj          The object to write.
1456:             */
1457:
1458:            int writeObj(TclObject obj) throws IOException {
1459:                // Always use the topmost channel of the stack
1460:
1461:                //char *src;
1462:                int srcLen;
1463:
1464:                //statePtr = ((Channel *) chan)->state;
1465:                //chanPtr  = statePtr->topChanPtr;
1466:
1467:                //if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
1468:                //    return -1;
1469:                //}
1470:
1471:                if (encoding == null) {
1472:                    srcLen = TclByteArray.getLength(null, obj);
1473:                    byte[] bytes = TclByteArray.getBytes(null, obj);
1474:                    return writeBytes(bytes, 0, srcLen);
1475:                } else {
1476:                    String data = obj.toString();
1477:                    final int num_chars = data.length();
1478:                    // FIXME: Use outputStage here?
1479:                    char[] chars = new char[num_chars];
1480:                    data.getChars(0, num_chars, chars, 0);
1481:                    return writeChars(chars, 0, num_chars);
1482:                }
1483:            }
1484:
1485:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.