001    /**
002     * Copyright (C) 2009, Progress Software Corporation and/or its 
003     * subsidiaries or affiliates.  All rights reserved.
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.fusesource.jansi;
019    
020    import static org.fusesource.jansi.internal.CLibrary.STDOUT_FILENO;
021    import static org.fusesource.jansi.internal.CLibrary.isatty;
022    
023    import java.io.FilterOutputStream;
024    import java.io.IOException;
025    import java.io.OutputStream;
026    import java.io.PrintStream;
027    
028    /**
029     * Provides consistent access to an ANSI aware console PrintStream.
030     * 
031     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
032     * @since 1.0
033     */
034    public class AnsiConsole {
035    
036            public static final PrintStream system_out = System.out;
037        public static final PrintStream out = new PrintStream(wrapOutputStream(system_out));
038    
039        public static final PrintStream system_err = System.err;
040        public static final PrintStream err = new PrintStream(wrapOutputStream(system_err));
041    
042        private static int installed;
043    
044            public static OutputStream wrapOutputStream(final OutputStream stream) {
045                    String os = System.getProperty("os.name");
046                    if( os.startsWith("Windows") ) {
047                            
048                            // On windows we know the console does not interpret ANSI codes..
049                            try {
050                                    return new WindowsAnsiOutputStream(stream);
051                            } catch (Throwable ignore) {
052                                    // this happens when JNA is not in the path.. or
053                                    // this happens when the stdout is being redirected to a file.
054                            }
055                            
056                            // Use the ANSIOutputStream to strip out the ANSI escape sequences.
057                            return new AnsiOutputStream(stream);
058                    }
059                    
060                    // We must be on some unix variant..
061                    try {
062                            // If we can detect that stdout is not a tty.. then setup
063                            // to strip the ANSI sequences..
064                            int rc = isatty(STDOUT_FILENO);
065                            if( rc==0 ) {
066                                    return new AnsiOutputStream(stream);
067                            }
068                            
069            // These erros happen if the JNI lib is not available for your platform.
070            } catch (NoClassDefFoundError ignore) {
071                    } catch (UnsatisfiedLinkError ignore) {
072                    }
073    
074                    // By default we assume your Unix tty can handle ANSI codes.
075                    // Just wrap it up so that when we get closed, we reset the 
076                    // attributes.
077                    return new FilterOutputStream(stream) {
078                        @Override
079                        public void close() throws IOException {
080                            write(AnsiOutputStream.REST_CODE);
081                            flush();
082                            super.close();
083                        }
084                    };
085            }
086    
087            /**
088             * If the standard out natively supports ANSI escape codes, then this just 
089             * returns System.out, otherwise it will provide an ANSI aware PrintStream
090             * which strips out the ANSI escape sequences or which implement the escape
091             * sequences.
092             * 
093             * @return a PrintStream which is ANSI aware.
094             */
095            public static PrintStream out() {
096                    return out;
097            }
098    
099        /**
100             * If the standard out natively supports ANSI escape codes, then this just
101             * returns System.err, otherwise it will provide an ANSI aware PrintStream
102             * which strips out the ANSI escape sequences or which implement the escape
103             * sequences.
104             *
105             * @return a PrintStream which is ANSI aware.
106             */
107        public static PrintStream err() {
108            return err;
109        }
110            
111            /**
112             * Install Console.out to System.out.
113             */
114            synchronized static public void systemInstall() {
115                    installed++;
116                    if( installed==1 ) {
117                            System.setOut(out);
118                System.setErr(err);
119                    }
120            }
121            
122            /**
123             * undo a previous {@link #systemInstall()}.  If {@link #systemInstall()} was called 
124             * multiple times, it {@link #systemUninstall()} must call the same number of times before
125             * it is actually uninstalled.
126             */
127            synchronized public static void systemUninstall() {
128                    installed--;
129                    if( installed==0 ) {
130                            System.setOut(system_out);
131                System.setErr(system_err);
132                    }
133            }
134            
135    }