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.CLIBRARY;
021    
022    import java.io.FilterOutputStream;
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.io.PrintStream;
026    
027    import org.fusesource.jansi.internal.CLibrary;
028    
029    /**
030     * Provides consistent access to an ANSI aware console PrintStream.
031     * 
032     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
033     * @since 1.0
034     */
035    public class AnsiConsole {
036    
037            public static final PrintStream system_out = System.out;
038        public static final PrintStream out = new PrintStream(wrapOutputStream(system_out));
039    
040        public static final PrintStream system_err = System.err;
041        public static final PrintStream err = new PrintStream(wrapOutputStream(system_err));
042    
043        private static int installed;
044    
045            public static OutputStream wrapOutputStream(final OutputStream stream) {
046                    String os = System.getProperty("os.name");
047                    if( os.startsWith("Windows") ) {
048                            
049                            // On windows we know the console does not interpret ANSI codes..
050                            try {
051                                    return new WindowsAnsiOutputStream(stream);
052                            } catch (Throwable ignore) {
053                                    // this happens when JNA is not in the path.. or
054                                    // this happens when the stdout is being redirected to a file.
055                            }
056                            
057                            // Use the ANSIOutputStream to strip out the ANSI escape sequences.
058                            return new AnsiOutputStream(stream);
059                    }
060                    
061                    // We must be on some unix variant..
062                    try {
063                            // If we can detect that stdout is not a tty.. then setup
064                            // to strip the ANSI sequences..
065                            int rc = CLIBRARY.isatty(CLibrary.STDOUT_FILENO);
066                            if( rc==0 ) {
067                                    return new AnsiOutputStream(stream);
068                            }
069                    } catch (Throwable ignore) {
070                    }
071    
072                    // By default we assume your Unix tty can handle ANSI codes.
073                    // Just wrap it up so that when we get closed, we reset the 
074                    // attributes.
075                    return new FilterOutputStream(stream) {
076                        @Override
077                        public void close() throws IOException {
078                            write(AnsiOutputStream.REST_CODE);
079                            flush();
080                            super.close();
081                        }
082                    };
083            }
084    
085            /**
086             * If the standard out natively supports ANSI escape codes, then this just 
087             * returns System.out, otherwise it will provide an ANSI aware PrintStream
088             * which strips out the ANSI escape sequences or which implement the escape
089             * sequences.
090             * 
091             * @return a PrintStream which is ANSI aware.
092             */
093            public static PrintStream out() {
094                    return out;
095            }
096    
097        /**
098             * If the standard out natively supports ANSI escape codes, then this just
099             * returns System.err, otherwise it will provide an ANSI aware PrintStream
100             * which strips out the ANSI escape sequences or which implement the escape
101             * sequences.
102             *
103             * @return a PrintStream which is ANSI aware.
104             */
105        public static PrintStream err() {
106            return err;
107        }
108            
109            /**
110             * Install Console.out to System.out.
111             */
112            synchronized static public void systemInstall() {
113                    installed++;
114                    if( installed==1 ) {
115                            System.setOut(out);
116                System.setErr(err);
117                    }
118            }
119            
120            /**
121             * undo a previous {@link #systemInstall()}.  If {@link #systemInstall()} was called 
122             * multiple times, it {@link #systemUninstall()} must call the same number of times before
123             * it is actually uninstalled.
124             */
125            synchronized public static void systemUninstall() {
126                    installed--;
127                    if( installed==0 ) {
128                            System.setOut(system_out);
129                System.setErr(system_err);
130                    }
131            }
132            
133    }