OSDN Git Service

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