OSDN Git Service

use JRE1.6 runtime static members
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / config / OptionInfo.java
1 /*
2  * option argument information
3  *
4  * License : The MIT License
5  * Copyright(c) 2009 olyutorskii
6  */
7
8 package jp.sfjp.jindolf.config;
9
10 import java.text.MessageFormat;
11 import java.util.Collections;
12 import java.util.EnumMap;
13 import java.util.Iterator;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 /**
21  * コマンドラインオプション情報。
22  *
23  * <p>public static void main()の引数から展開される。
24  */
25 public class OptionInfo{
26
27     private static final String REGEX_DIMNO =
28             "([1-9][0-9]{0,5})";
29     private static final String REGEX_SIGN =
30             "(?:\\+|(\\-))";
31     private static final String REGEX_LOCNO =
32             REGEX_SIGN + REGEX_DIMNO;
33     private static final String REGEX_GEOMETRY =
34               REGEX_DIMNO + "x" + REGEX_DIMNO
35             + "(?:" + REGEX_LOCNO + REGEX_LOCNO + ")?";
36     private static final Pattern PATTERN_GEOMETRY =
37             Pattern.compile(REGEX_GEOMETRY);
38
39     private static final String ERRFORM_UKNOWN =
40             "未定義の起動オプション[{0}]が指定されました。";
41     private static final String ERRFORM_NOARG =
42             "起動オプション[{0}]に引数がありません。";
43     private static final String ERRFORM_GEOM =
44               "起動オプション[{0}]のジオメトリ指定[{1}]が不正です。"
45             + "WIDTHxHEIGHT[(+|-)XPOS(+|-)YPOS]の形式で指定してください";
46     private static final String ERRFORM_BOOL =
47               "起動オプション[{0}]の真偽指定[{1}]が不正です。"
48             + "on, off, yes, no, true, falseのいずれかを指定してください。";
49     private static final String ERRFORM_NONBOOL =
50             "起動オプション[{0}]は真偽を指定するオプションではありません。";
51
52
53     private Integer frameWidth  = null;
54     private Integer frameHeight = null;
55     private Integer frameXpos   = null;
56     private Integer frameYpos   = null;
57
58     private final List<String> invokeArgs = new LinkedList<>();
59     private final List<CmdOption> optionList = new LinkedList<>();
60     private final Map<CmdOption, Boolean> boolOptionMap =
61             new EnumMap<>(CmdOption.class);
62     private final Map<CmdOption, String> stringOptionMap =
63             new EnumMap<>(CmdOption.class);
64
65
66     /**
67      * コンストラクタ。
68      */
69     protected OptionInfo(){
70         super();
71         return;
72     }
73
74
75     /**
76      * 文字列が可変引数のいずれかと英字大小無視で等しいか判定する。
77      *
78      * @param text 文字列
79      * @param names 文字列の可変引数
80      * @return 等しい物があればtrue
81      */
82     private static boolean equalsIgnoreCase(String text, String ... names){
83         for(String name : names){
84             if(text.equalsIgnoreCase(name)) return true;
85         }
86         return false;
87     }
88
89     /**
90      * 真偽二値をとるオプション解析の下請け。
91      *
92      * @param info オプション情報格納先
93      * @param option オプション種別
94      * @param optTxt オプション名文字列
95      * @param onoff オプション引数
96      * @throws IllegalArgumentException 引数の構文エラー
97      */
98     private static void parseBooleanSwitch(OptionInfo info,
99                                               CmdOption option,
100                                               String optTxt,
101                                               String onoff )
102             throws IllegalArgumentException{
103         Boolean flag;
104
105         if(equalsIgnoreCase(onoff, "on", "yes", "true")){
106             flag = Boolean.TRUE;
107         }else if(equalsIgnoreCase(onoff, "off", "no", "false")){
108             flag = Boolean.FALSE;
109         }else{
110             String errmsg =
111                     MessageFormat.format(ERRFORM_BOOL, optTxt, onoff);
112             throw new IllegalArgumentException(errmsg);
113         }
114
115         info.boolOptionMap.put(option, flag);
116
117         return;
118     }
119
120     /**
121      * ウィンドウジオメトリオプション解析。
122      *
123      * <p>例) WIDTHxHEIGHT+XPOS+YPOS
124      *
125      * @param info オプション情報格納先
126      * @param optTxt オプション名文字列
127      * @param geometry オプション引数
128      * @throws IllegalArgumentException 引数の構文エラー
129      */
130     private static void parseGeometry(OptionInfo info,
131                                         String optTxt,
132                                         String geometry )
133             throws IllegalArgumentException{
134         Matcher matcher = PATTERN_GEOMETRY.matcher(geometry);
135         if( ! matcher.matches() ){
136             String errmsg = MessageFormat.format(ERRFORM_GEOM,
137                                                  optTxt, geometry);
138             throw new IllegalArgumentException(errmsg);
139         }
140
141         int gpos = 1;
142         String width  = matcher.group(gpos++);
143         String height = matcher.group(gpos++);
144         String xMinus = matcher.group(gpos++);
145         String xPos   = matcher.group(gpos++);
146         String yMinus = matcher.group(gpos++);
147         String yPos   = matcher.group(gpos++);
148
149         info.frameWidth  = Integer.parseInt(width);
150         info.frameHeight = Integer.parseInt(height);
151
152         if(xPos != null){
153             info.frameXpos = Integer.parseInt(xPos);
154             if(xMinus != null){
155                 info.frameXpos = -info.frameXpos;
156             }
157         }
158
159         if(yPos != null){
160             info.frameYpos = Integer.parseInt(yPos);
161             if(yMinus != null){
162                 info.frameYpos = -info.frameYpos;
163             }
164         }
165
166         return;
167     }
168
169     /**
170      * 引数付きオプションを解析する。
171      *
172      * @param info オプション情報
173      * @param optTxt オプション文字列
174      * @param option オプション種別
175      * @param iterator コマンドライン引数並び
176      * @throws IllegalArgumentException オプションの引数がない
177      */
178     private static void parseOptionArg(OptionInfo info,
179                                          String optTxt,
180                                          CmdOption option,
181                                          Iterator<String> iterator )
182             throws IllegalArgumentException {
183         String nextArg;
184         if(iterator.hasNext()){
185             nextArg = iterator.next();
186         }else{
187             String errMsg = MessageFormat.format(ERRFORM_NOARG, optTxt);
188             throw new IllegalArgumentException(errMsg);
189         }
190
191         if(option == CmdOption.OPT_GEOMETRY){
192             parseGeometry(info, optTxt, nextArg);
193         }else if(option.isBooleanOption()){
194             parseBooleanSwitch(info, option, optTxt, nextArg);
195         }else if(   option == CmdOption.OPT_INITFONT
196                  || option == CmdOption.OPT_CONFDIR ){
197             info.stringOptionMap.put(option, nextArg);
198         }else{
199             assert false;
200         }
201
202         return;
203     }
204
205     /**
206      * オプション文字列を解析する。
207      *
208      * @param args main()に渡されるオプション文字列
209      * @return 解析済みのオプション情報。
210      * @throws IllegalArgumentException 構文エラー
211      */
212     public static OptionInfo parseOptions(String ... args)
213             throws IllegalArgumentException{
214         OptionInfo result = new OptionInfo();
215
216         for(String arg : args){
217             if(arg == null) continue;
218             result.invokeArgs.add(arg);
219         }
220         Iterator<String> iterator = result.invokeArgs.iterator();
221
222         while(iterator.hasNext()){
223             String arg = iterator.next();
224
225             CmdOption option = CmdOption.parseCmdOption(arg);
226             if(option == null){
227                 String errmsg = MessageFormat.format(ERRFORM_UKNOWN, arg);
228                 throw new IllegalArgumentException(errmsg);
229             }
230             result.optionList.add(option);
231
232             if( ! option.isIndepOption() ){
233                 parseOptionArg(result, arg, option, iterator);
234             }
235         }
236
237         return result;
238     }
239
240
241     /**
242      * 全引数のリストを返す。
243      *
244      * @return 全引数のリスト
245      */
246     public List<String> getInvokeArgList(){
247         return Collections.unmodifiableList(this.invokeArgs);
248     }
249
250     /**
251      * オプションが指定されていたか否か判定する。
252      *
253      * @param option オプション
254      * @return 指定されていたらtrue
255      */
256     public boolean hasOption(CmdOption option){
257         if(this.optionList.contains(option)) return true;
258         return false;
259     }
260
261     /**
262      * 真偽値をとるオプション値を返す。
263      *
264      * <p>複数回指定された場合は最後の値。
265      *
266      * @param option オプション
267      * @return 真偽値。オプション指定がなかった場合はnull
268      * @throws IllegalArgumentException 真偽値を取るオプションではない。
269      */
270     public Boolean getBooleanArg(CmdOption option)
271             throws IllegalArgumentException{
272         if( ! option.isBooleanOption() ){
273             String errMsg =
274                     MessageFormat.format(ERRFORM_NONBOOL, option.toString());
275             throw new IllegalArgumentException(errMsg);
276         }
277         Boolean result = this.boolOptionMap.get(option);
278         return result;
279     }
280
281     /**
282      * 文字列引数をとるオプション値を返す。
283      *
284      * <p>複数回指定された場合は最後の値。
285      *
286      * @param option オプション
287      * @return 文字列。オプション指定がなかった場合はnull
288      */
289     public String getStringArg(CmdOption option){
290         String result = this.stringOptionMap.get(option);
291         return result;
292     }
293
294     /**
295      * 排他的オプションのいずれかが指定されたか判定する。
296      *
297      * <p>後から指定された方が有効となる。
298      *
299      * @param options 排他的オプション群
300      * @return いずれかのオプション。どれも指定されなければnull
301      */
302     public CmdOption getExclusiveOption(CmdOption... options){
303         CmdOption result = null;
304         for(CmdOption option : this.optionList){
305             for(CmdOption excOption : options){
306                 if(option == excOption){
307                     result = option;
308                     break;
309                 }
310             }
311         }
312         return result;
313     }
314
315     /**
316      * 初期のフレーム幅を返す。
317      *
318      * @return 初期のフレーム幅。オプション指定されてなければnull
319      */
320     public Integer initialFrameWidth(){
321         return this.frameWidth;
322     }
323
324     /**
325      * 初期のフレーム高を返す。
326      *
327      * @return 初期のフレーム高。オプション指定されてなければnull
328      */
329     public Integer initialFrameHeight(){
330         return this.frameHeight;
331     }
332
333     /**
334      * 初期のフレーム位置のX座標を返す。
335      *
336      * @return 初期のフレーム位置のX座標。オプション指定されてなければnull
337      */
338     public Integer initialFrameXpos(){
339         return this.frameXpos;
340     }
341
342     /**
343      * 初期のフレーム位置のY座標を返す。
344      *
345      * @return 初期のフレーム位置のY座標。オプション指定されてなければnull
346      */
347     public Integer initialFrameYpos(){
348         return this.frameYpos;
349     }
350
351 }