001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 import java.util.*; 032 033 aspect AddOptionsToProgram { 034 public Options Program.options = new Options(); 035 public Options Program.options() { 036 return options; 037 } 038 039 inh Program ASTNode.program(); 040 eq Program.getChild().program() = this; 041 } 042 043 public class Options { 044 static class Option { 045 public String name; 046 public boolean hasValue; 047 public boolean isCollection; 048 public Option(String name, boolean hasValue, boolean isCollection) { 049 this.name = name; 050 this.hasValue = hasValue; 051 this.isCollection = isCollection; 052 } 053 } 054 private final Map<String,Object> options = new HashMap<String,Object>(); 055 private final Map<String,Option> optionDescriptions = new HashMap<String,Option>(); 056 057 private final Set<String> files = new LinkedHashSet<String>(); 058 059 public Collection<String> files() { 060 return files; 061 } 062 063 public void initOptions() { 064 options.clear(); 065 optionDescriptions.clear(); 066 files.clear(); 067 } 068 069 public void addKeyOption(String name) { 070 if (optionDescriptions.containsKey(name)) { 071 throw new Error("Command line definition error: option description for " + name + " is multiply declared"); 072 } 073 optionDescriptions.put(name, new Option(name, false, false)); 074 } 075 076 public void addKeyValueOption(String name) { 077 if (optionDescriptions.containsKey(name)) { 078 throw new Error("Command line definition error: option description for " + name + " is multiply declared"); 079 } 080 optionDescriptions.put(name, new Option(name, true, false)); 081 } 082 083 public void addKeyCollectionOption(String name) { 084 if (optionDescriptions.containsKey(name)) { 085 throw new Error("Command line definition error: option description for " + name + " is multiply declared"); 086 } 087 optionDescriptions.put(name, new Option(name, true, true)); 088 } 089 090 public void addOptionDescription(String name, boolean value) { 091 if (optionDescriptions.containsKey(name)) { 092 throw new Error("Command line definition error: option description for " + name + " is multiply declared"); 093 } 094 optionDescriptions.put(name, new Option(name, value, false)); 095 } 096 public void addOptionDescription(String name, boolean value, boolean isCollection) { 097 if (optionDescriptions.containsKey(name)) { 098 throw new Error("Command line definition error: option description for " + name + " is multiply declared"); 099 } 100 optionDescriptions.put(name, new Option(name, value, isCollection)); 101 } 102 103 /** 104 * Parse options from command-line arguments. 105 * Options starting with the at-sign are treated as argument files. 106 * The argument file is expanded in place before parsing other arguments. 107 * 108 * @param args command-line arguments 109 */ 110 public void addOptions(String[] args) { 111 java.util.List<String> argList = new ArrayList<String>(); 112 113 // expand argument files 114 for (int i = 0; i < args.length; i++) { 115 String arg = args[i]; 116 if (arg.length() > 1 && arg.startsWith("@")) { 117 if (arg.startsWith("@@")) { 118 // escape the double at 119 argList.add(arg.substring(1)); 120 } else { 121 String fileName = arg.substring(1); 122 try { 123 java.io.StreamTokenizer tokenizer = new java.io.StreamTokenizer(new java.io.FileReader(fileName)); 124 tokenizer.resetSyntax(); 125 tokenizer.whitespaceChars(' ',' '); 126 tokenizer.whitespaceChars('\t','\t'); 127 tokenizer.whitespaceChars('\f','\f'); 128 tokenizer.whitespaceChars('\n','\n'); 129 tokenizer.whitespaceChars('\r','\r'); 130 tokenizer.wordChars(33,255); 131 tokenizer.commentChar('#'); 132 tokenizer.quoteChar('"'); 133 tokenizer.quoteChar('\''); 134 while (tokenizer.nextToken() != tokenizer.TT_EOF) { 135 argList.add(tokenizer.sval); 136 } 137 } catch (java.io.FileNotFoundException e) { 138 System.err.println("Argument file not found: " + fileName); 139 } catch (java.io.IOException e) { 140 System.err.println("Exception: "+e.getMessage()); 141 } 142 } 143 } else { 144 argList.add(arg); 145 } 146 } 147 148 Iterator<String> all = argList.iterator(); 149 while (all.hasNext()) { 150 String arg = all.next(); 151 if (arg.startsWith("-")) { 152 if (!optionDescriptions.containsKey(arg)) { 153 throw new Error("Command line argument error: option " + arg + " is not defined"); 154 } 155 Option o = (Option) optionDescriptions.get(arg); 156 157 if (!o.isCollection && options.containsKey(arg)) { 158 throw new Error("Command line argument error: option " + arg + " is multiply defined"); 159 } 160 161 if (o.hasValue) { 162 String value = null; 163 if (!all.hasNext()) { 164 throw new Error("Command line argument error: value missing for key " + arg); 165 } 166 value = all.next(); 167 if (value.startsWith("-")) { 168 throw new Error("Command line argument error: expected value for key " + arg 169 + ", but found option " + value); 170 } 171 172 if (o.isCollection) { 173 Collection<String> c = (Collection<String>) options.get(arg); 174 if (c == null) { 175 c = new ArrayList<String>(); 176 } 177 c.add(value); 178 options.put(arg, c); 179 } else { 180 options.put(arg, value); 181 } 182 } else { 183 options.put(arg, null); 184 } 185 } else { 186 files.add(arg); 187 } 188 } 189 } 190 191 public boolean hasOption(String name) { 192 return options.containsKey(name); 193 } 194 public void setOption(String name) { 195 options.put(name, null); 196 } 197 public boolean hasValueForOption(String name) { 198 return options.containsKey(name) && options.get(name) != null; 199 } 200 public String getValueForOption(String name) { 201 if (!hasValueForOption(name)) { 202 throw new Error("Command line argument error: key " + name + " does not have a value"); 203 } 204 return (String) options.get(name); 205 } 206 public void setValueForOption(String value, String option) { 207 options.put(option, value); 208 } 209 public Collection getValueCollectionForOption(String name) { 210 if (!hasValueForOption(name)) { 211 throw new Error("Command line argument error: key " + name + " does not have a value"); 212 } 213 return (Collection) options.get(name); 214 } 215 216 public boolean verbose() { 217 return hasOption("-verbose"); 218 } 219 }