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