001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 /* 021 * Copyright (C) 2012 eXo Platform SAS. 022 * 023 * This is free software; you can redistribute it and/or modify it 024 * under the terms of the GNU Lesser General Public License as 025 * published by the Free Software Foundation; either version 2.1 of 026 * the License, or (at your option) any later version. 027 * 028 * This software is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 031 * Lesser General Public License for more details. 032 * 033 * You should have received a copy of the GNU Lesser General Public 034 * License along with this software; if not, write to the Free 035 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 036 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 037 */ 038 039 package org.crsh.cli.descriptor; 040 041 import org.crsh.cli.impl.descriptor.IllegalParameterException; 042 import org.crsh.cli.impl.descriptor.IllegalValueTypeException; 043 import org.crsh.cli.impl.Multiplicity; 044 import org.crsh.cli.impl.ParameterType; 045 import org.crsh.cli.SyntaxException; 046 import org.crsh.cli.spi.Completer; 047 import org.crsh.cli.type.ValueType; 048 049 import java.io.IOException; 050 import java.lang.annotation.Annotation; 051 import java.util.ArrayList; 052 import java.util.BitSet; 053 import java.util.Collections; 054 import java.util.List; 055 056 public class OptionDescriptor extends ParameterDescriptor { 057 058 /** . */ 059 private static final BitSet A = new BitSet(256); 060 061 /** . */ 062 private static final BitSet B = new BitSet(256); 063 064 static { 065 for (char c = 'a';c <= 'z';c++) { 066 A.set(c); 067 A.set(c + 'A' - 'a'); 068 } 069 B.or(A); 070 B.set('-'); 071 } 072 073 private static void checkChar(String s, int index, BitSet authorized) throws IllegalParameterException { 074 if (!authorized.get(s.charAt(index))) { 075 throw new IllegalParameterException("Option name " + s + " cannot contain " + s.charAt(index) + " at position " + index); 076 } 077 } 078 079 /** . */ 080 private final int arity; 081 082 /** . */ 083 private final List<String> names; 084 085 public OptionDescriptor( 086 Object binding, 087 ParameterType<?> type, 088 List<String> names, 089 Description info, 090 boolean required, 091 boolean password, 092 boolean unquote, 093 Class<? extends Completer> completerType, 094 Annotation annotation) throws IllegalValueTypeException, IllegalParameterException { 095 super( 096 binding, 097 type, 098 info, 099 required, 100 password, 101 unquote, 102 completerType, 103 annotation); 104 105 // 106 if (getMultiplicity() == Multiplicity.MULTI && getType() == ValueType.BOOLEAN) { 107 throw new IllegalParameterException(); 108 } 109 110 // 111 names = new ArrayList<String>(names); 112 for (String name : names) { 113 if (name == null) { 114 throw new IllegalParameterException("Option name must not be null"); 115 } 116 int length = name.length(); 117 if (length == 0) { 118 throw new IllegalParameterException("Option name cannot be empty"); 119 } 120 if (!A.get(name.charAt(0))) { 121 throw new IllegalParameterException("Option name " + name + " cannot start with " + name.charAt(0)); 122 } 123 checkChar(name, 0, A); 124 checkChar(name, length - 1, A); 125 for (int i = 1;i < length - 1;i++) { 126 checkChar(name, i, B); 127 } 128 } 129 130 // 131 if (getType() == ValueType.BOOLEAN) { 132 arity = 0; 133 } else { 134 arity = 1; 135 } 136 137 // 138 this.names = Collections.unmodifiableList(names); 139 } 140 141 public int getArity() { 142 return arity; 143 } 144 145 public List<String> getNames() { 146 return names; 147 } 148 149 @Override 150 public Object parse(List<String> values) throws SyntaxException { 151 if (arity == 0) { 152 if (values.size() > 0) { 153 throw new SyntaxException("Too many values " + values + " for option " + names.get(0)); 154 } 155 // It's a boolean and it is true 156 return Boolean.TRUE; 157 } else { 158 if (getMultiplicity() == Multiplicity.SINGLE) { 159 if (values.size() > 1) { 160 throw new SyntaxException("Too many values " + values + " for option " + names.get(0)); 161 } 162 if (values.size() == 0) { 163 throw new SyntaxException("Missing option " + names.get(0) + " value"); 164 } 165 String value = values.get(0); 166 try { 167 return parse(value); 168 } catch (Exception e) { 169 throw new SyntaxException("Could not parse value <" + value + "> for option " + names.get(0)); 170 } 171 } else { 172 List<Object> v = new ArrayList<Object>(values.size()); 173 for (String value : values) { 174 try { 175 v.add(parse(value)); 176 } catch (Exception e) { 177 throw new SyntaxException("Could not parse value <" + value + "> for option " + names.get(0)); 178 } 179 } 180 return v; 181 } 182 } 183 } 184 185 /** 186 * Prints the option names as an alternative of switches surrounded by a square brace, 187 * for instance: "[-f --foo]" 188 * 189 * @param writer the writer to print to 190 * @throws IOException any io exception 191 */ 192 public void printUsage(Appendable writer) throws IOException { 193 writer.append("["); 194 boolean a = false; 195 for (String optionName : names) { 196 if (a) { 197 writer.append(" | "); 198 } 199 writer.append(optionName.length() == 1 ? "-" : "--").append(optionName); 200 a = true; 201 } 202 writer.append("]"); 203 } 204 205 @Override 206 public String toString() { 207 return "OptionDescriptor[" + names + "]"; 208 } 209 }