1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 52270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.io.*; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * An abstract reader of words, with the possibility to include other readers. 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Words are separated by spaces or broken off at delimiters. Words containing 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * spaces or delimiters can be quoted with single or double quotes. 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Comments (everything starting with '#' on a single line) are ignored. 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @noinspection TailRecursion 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic abstract class WordReader 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static final char COMMENT_CHARACTER = '#'; 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private File baseDir; 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private WordReader includeWordReader; 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private String currentLine; 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int currentLineLength; 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int currentIndex; 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private String currentWord; 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private String currentComments; 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Creates a new WordReader with the given base directory. 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected WordReader(File baseDir) 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.baseDir = baseDir; 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Sets the base directory of this reader. 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void setBaseDir(File baseDir) 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (includeWordReader != null) 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader.setBaseDir(baseDir); 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.baseDir = baseDir; 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the base directory of this reader, if any. 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public File getBaseDir() 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return includeWordReader != null ? 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader.getBaseDir() : 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato baseDir; 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Specifies to start reading words from the given WordReader. When it is 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * exhausted, this WordReader will continue to provide its own words. 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @param newIncludeWordReader the WordReader that will start reading words. 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void includeWordReader(WordReader newIncludeWordReader) 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (includeWordReader == null) 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader = newIncludeWordReader; 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader.includeWordReader(newIncludeWordReader); 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Reads a word from this WordReader, or from one of its active included 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * WordReader objects. 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 108b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang * @param isFileName return a complete line (or argument), if the word 109b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang * isn't an option (it doesn't start with '-'). 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @return the read word. 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 112b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang public String nextWord(boolean isFileName) throws IOException 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentWord = null; 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // See if we have an included reader to produce a word. 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (includeWordReader != null) 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Does the included word reader still produce a word? 120b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentWord = includeWordReader.nextWord(isFileName); 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (currentWord != null) 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Return it if so. 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return currentWord; 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Otherwise close and ditch the word reader. 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader.close(); 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader = null; 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Get a word from this reader. 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 134b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Skip any whitespace and comments left on the current line. 135b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (currentLine != null) 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 137b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Skip any leading whitespace. 138b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang while (currentIndex < currentLineLength && 139b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang Character.isWhitespace(currentLine.charAt(currentIndex))) 140b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 141b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex++; 142b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 143b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 144b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Skip any comments. 145b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (currentIndex < currentLineLength && 146b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang isComment(currentLine.charAt(currentIndex))) 147b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 148b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex = currentLineLength; 149b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Make sure we have a non-blank line. 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (currentLine == null || currentIndex == currentLineLength) 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentLine = nextLine(); 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (currentLine == null) 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return null; 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 161b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentLineLength = currentLine.length(); 162b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 163b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Skip any leading whitespace. 164b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex = 0; 165b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang while (currentIndex < currentLineLength && 166b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang Character.isWhitespace(currentLine.charAt(currentIndex))) 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 168b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex++; 169b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 171b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Remember any leading comments. 172b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (currentIndex < currentLineLength && 173b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang isComment(currentLine.charAt(currentIndex))) 174b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the comments. 176b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang String comment = currentLine.substring(currentIndex + 1); 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentComments = currentComments == null ? 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato comment : 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentComments + '\n' + comment; 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 181b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Skip the comments. 182b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex = currentLineLength; 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Find the word starting at the current index. 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int startIndex = currentIndex; 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int endIndex; 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato char startChar = currentLine.charAt(startIndex); 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 192b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (isQuote(startChar)) 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The next word is starting with a quote character. 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Skip the opening quote. 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato startIndex++; 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The next word is a quoted character string. 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Find the closing quote. 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato do 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentIndex++; 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (currentIndex == currentLineLength) 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentWord = currentLine.substring(startIndex-1, currentIndex); 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw new IOException("Missing closing quote for "+locationDescription()); 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (currentLine.charAt(currentIndex) != startChar); 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato endIndex = currentIndex++; 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 214b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang else if (isFileName && 215b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang !isOption(startChar)) 216b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 217b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // The next word is a (possibly optional) file name. 218b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Find the end of the line, the first path separator, the first 219b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // option, or the first comment. 220b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang while (currentIndex < currentLineLength) 221b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 222b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang char currentCharacter = currentLine.charAt(currentIndex); 223b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (isFileDelimiter(currentCharacter) || 224b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang ((isOption(currentCharacter) || 225b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang isComment(currentCharacter)) && 226b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang Character.isWhitespace(currentLine.charAt(currentIndex-1)))) { 227b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang break; 228b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 229b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 230b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang currentIndex++; 231b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 232b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 233b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang endIndex = currentIndex; 234b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 235b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // Trim any trailing whitespace. 236b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang while (endIndex > startIndex && 237b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang Character.isWhitespace(currentLine.charAt(endIndex-1))) 238b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 239b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang endIndex--; 240b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 241b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 242b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang else if (isDelimiter(startChar)) 243b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 244b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang // The next word is a single delimiting character. 245b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang endIndex = ++currentIndex; 246b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The next word is a simple character string. 250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Find the end of the line, the first delimiter, or the first 251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // white space. 252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (currentIndex < currentLineLength) 253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato char currentCharacter = currentLine.charAt(currentIndex); 255b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (isDelimiter(currentCharacter) || 256b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang Character.isWhitespace(currentCharacter) || 257b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang isComment(currentCharacter)) { 258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break; 259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentIndex++; 262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato endIndex = currentIndex; 265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember and return the parsed word. 268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentWord = currentLine.substring(startIndex, endIndex); 269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return currentWord; 271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 275b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the comments collected before returning the last word. 276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Starts collecting new comments. 277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @return the collected comments, or <code>null</code> if there weren't any. 279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public String lastComments() throws IOException 281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (includeWordReader == null) 283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 284b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String comments = currentComments; 285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato currentComments = null; 286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return comments; 287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return includeWordReader.lastComments(); 291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Constructs a readable description of the current position in this 297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * WordReader and its included WordReader objects. 298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @return the description. 300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public String locationDescription() 302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return 304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (includeWordReader == null ? 305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (currentWord == null ? 306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato "end of " : 307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato "'" + currentWord + "' in " ) : 308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato (includeWordReader.locationDescription() + ",\n" + 309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato " included from ")) + 310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato lineLocationDescription(); 311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Reads a line from this WordReader, or from one of its active included 316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * WordReader objects. 317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @return the read line. 319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected abstract String nextLine() throws IOException; 321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns a readable description of the current WordReader position. 325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @return the description. 327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato protected abstract String lineLocationDescription(); 329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 331b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Closes the FileWordReader. 333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void close() throws IOException 335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Close and ditch the included word reader, if any. 337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (includeWordReader != null) 338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 339b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader.close(); 340b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato includeWordReader = null; 341b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 342b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Small utility methods. 346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 347b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang private boolean isOption(char character) 348b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 349b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang return character == '-'; 350b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 351b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 352b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 353b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang private boolean isComment(char character) 354b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 355b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang return character == COMMENT_CHARACTER; 356b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 357b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 358b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 359b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean isDelimiter(char character) 360b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 361b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return character == '@' || 362b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == '{' || 363b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == '}' || 364b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == '(' || 365b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == ')' || 366b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == ',' || 367b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == ';' || 368b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == File.pathSeparatorChar; 369b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 370b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 371b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 372b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang private boolean isFileDelimiter(char character) 373b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang { 374b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang return character == '(' || 375b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang character == ')' || 376b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang character == ',' || 377b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang character == ';' || 378b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang character == File.pathSeparatorChar; 379b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang } 380b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 381b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang 382b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean isQuote(char character) 383b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 384b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return character == '\'' || 385b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato character == '"'; 386b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 387b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 388