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.impl.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 ParameterType<?> type, 087 List<String> names, 088 Description info, 089 boolean required, 090 boolean password, 091 boolean unquote, 092 Class<? extends Completer> completerType, 093 Annotation annotation) throws IllegalValueTypeException, IllegalParameterException { 094 super( 095 type, 096 info, 097 required, 098 password, 099 unquote, 100 completerType, 101 annotation); 102 103 // 104 if (getMultiplicity() == Multiplicity.MULTI && getType() == ValueType.BOOLEAN) { 105 throw new IllegalParameterException(); 106 } 107 108 // 109 names = new ArrayList<String>(names); 110 for (String name : names) { 111 if (name == null) { 112 throw new IllegalParameterException("Option name must not be null"); 113 } 114 int length = name.length(); 115 if (length == 0) { 116 throw new IllegalParameterException("Option name cannot be empty"); 117 } 118 if (!A.get(name.charAt(0))) { 119 throw new IllegalParameterException("Option name " + name + " cannot start with " + name.charAt(0)); 120 } 121 checkChar(name, 0, A); 122 checkChar(name, length - 1, A); 123 for (int i = 1;i < length - 1;i++) { 124 checkChar(name, i, B); 125 } 126 } 127 128 // 129 if (getType() == ValueType.BOOLEAN) { 130 arity = 0; 131 } else { 132 arity = 1; 133 } 134 135 // 136 this.names = Collections.unmodifiableList(names); 137 } 138 139 public int getArity() { 140 return arity; 141 } 142 143 public List<String> getNames() { 144 return names; 145 } 146 147 @Override 148 public Object parse(List<String> values) throws SyntaxException { 149 if (arity == 0) { 150 if (values.size() > 0) { 151 throw new SyntaxException("Too many values " + values + " for option " + names.get(0)); 152 } 153 // It's a boolean and it is true 154 return Boolean.TRUE; 155 } else { 156 if (getMultiplicity() == Multiplicity.SINGLE) { 157 if (values.size() > 1) { 158 throw new SyntaxException("Too many values " + values + " for option " + names.get(0)); 159 } 160 if (values.size() == 0) { 161 throw new SyntaxException("Missing option " + names.get(0) + " value"); 162 } 163 String value = values.get(0); 164 try { 165 return parse(value); 166 } catch (Exception e) { 167 throw new SyntaxException("Could not parse value <" + value + "> for option " + names.get(0)); 168 } 169 } else { 170 List<Object> v = new ArrayList<Object>(values.size()); 171 for (String value : values) { 172 try { 173 v.add(parse(value)); 174 } catch (Exception e) { 175 throw new SyntaxException("Could not parse value <" + value + "> for option " + names.get(0)); 176 } 177 } 178 return v; 179 } 180 } 181 } 182 183 /** 184 * Prints the option names as an alternative of switches surrounded by a square brace, 185 * for instance: "[-f --foo]" 186 * 187 * @param writer the writer to print to 188 * @throws IOException any io exception 189 */ 190 public void printUsage(Appendable writer) throws IOException { 191 writer.append("["); 192 boolean a = false; 193 for (String optionName : names) { 194 if (a) { 195 writer.append(" | "); 196 } 197 writer.append(optionName.length() == 1 ? "-" : "--").append(optionName); 198 a = true; 199 } 200 writer.append("]"); 201 } 202 203 @Override 204 public String toString() { 205 return "OptionDescriptor[" + names + "]"; 206 } 207 }