001    /**
002     *
003     * Copyright 2005 Jeremy Rayner
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.codehaus.groovy.antlr;
019    
020    import java.util.List;
021    import java.util.ArrayList;
022    
023    /**
024     * A simple buffer that provides line/col access to chunks of source code
025     * held within itself.
026     *
027     * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
028     * @version $Revision: 1.4 $
029     */
030    public class SourceBuffer {
031        private List lines;
032        private StringBuffer current;
033    
034        public SourceBuffer() {
035            lines = new ArrayList();
036            //lines.add(new StringBuffer()); // dummy row for position [0] in the List
037    
038            current = new StringBuffer();
039            lines.add(current);
040        }
041    
042        /**
043         * Obtains a snippet of the source code within the bounds specified
044         * @param start (inclusive line/ inclusive column)
045         * @param end (inclusive line / exclusive column)
046         * @return specified snippet of source code as a String, or null if no source available
047         */
048        public String getSnippet(LineColumn start, LineColumn end) {
049            // preconditions
050            if (start == null || end == null) { return null; } // no text to return
051            if (start.equals(end)) { return null; } // no text to return
052            if (lines.size() == 1 && current.length() == 0) { return null; } // buffer hasn't been filled yet
053    
054            // working variables
055            int startLine = start.getLine();
056            int startColumn = start.getColumn();
057            int endLine = end.getLine();
058            int endColumn = end.getColumn();
059    
060            // reset any out of bounds requests
061            if (startLine < 1) { startLine = 1;}
062            if (endLine < 1) { endLine = 1;}
063            if (startColumn < 1) { startColumn = 1;}
064            if (endColumn < 1) { endColumn = 1;}
065            if (startLine > lines.size()) { startLine = lines.size(); }
066            if (endLine > lines.size()) { endLine = lines.size(); }
067    
068            // obtain the snippet from the buffer within specified bounds
069            StringBuffer snippet = new StringBuffer();
070            for (int i = startLine - 1; i < endLine;i++) {
071                String line = ((StringBuffer)lines.get(i)).toString();
072                if (startLine == endLine) {
073                    // reset any out of bounds requests (again)
074                    if (startColumn > line.length()) { startColumn = line.length();}
075                    if (startColumn < 1) { startColumn = 1;}
076                    if (endColumn > line.length()) { endColumn = line.length() + 1;}
077                    if (endColumn < 1) { endColumn = 1;}
078    
079                    line = line.substring(startColumn - 1, endColumn - 1);
080                } else {
081                    if (i == startLine - 1) {
082                        if (startColumn - 1 < line.length()) {
083                            line = line.substring(startColumn - 1);
084                        }
085                    }
086                    if (i == endLine - 1) {
087                        if (endColumn - 1 < line.length()) {
088                            line = line.substring(0,endColumn - 1);
089                        }
090                    }
091                }
092                snippet.append(line);
093            }
094            return snippet.toString();
095        }
096    
097        /**
098         * Writes the specified character into the buffer
099         * @param c
100         */
101        public void write(int c) {
102            if (c != -1) {
103                current.append((char)c);
104            }
105            if (c == '\n') {
106                current = new StringBuffer();
107                lines.add(current);
108            }
109        }
110    }