/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.civilian-framework.org/license.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.civilian.util; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; /** * An iterator for command line arguments. * Any argument prefixed by '@' is treated as argument file: Its content * is read, interpreted as arguments and inserted into the argument list. */ public class Arguments { /** * Creates a Arguments object. * @param args the string arguments to the main method */ public Arguments(String... args) { this(null, args); } /** * Creates a Arguments object. * @param loader if not null then it is used to open argument files * @param args the arguments */ public Arguments(ResourceLoader loader, String... args) { loader_ = loader; addArgs(args, null); } private ArrayList<String> addArgs(String[] args, ArrayList<String> files) { int len = args == null ? 0 : args.length; if (args_ == null) args_ = new ArrayList<>(len); else args_.ensureCapacity(args_.size() + len); for (int i=0; i<len; i++) { String arg = args[i]; // ignore null and empty args if ((arg != null) && (arg.length() > 0)) { if ((arg.charAt(0) == '@') && (arg.length() > 1)) files = insertArgumentFile(arg.substring(1), files); else args_.add(arg); } } return files; } private ArrayList<String> insertArgumentFile(String file, ArrayList<String> files) { if (files == null) files = new ArrayList<>(); if (files.contains(file)) throw new IllegalArgumentException("cyclic inclusion of argument file: " + file); files.add(file); try { try(InputStream in = loader_ == null ? new FileInputStream(file) : loader_.required().getResourceAsStream(file)) { String args[] = readArguments(in); files = addArgs(args, files); return files; } } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new IllegalArgumentException("cannot read argument file " + file, e); } } private String[] readArguments(InputStream in) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); String line; ArrayList<String> args = new ArrayList<>(); while((line = reader.readLine()) != null) { line = line.trim(); if (!line.startsWith("#")) { StringTokenizer st = new StringTokenizer(line); while(st.hasMoreTokens()) args.add(st.nextToken()); } } return args.toArray(new String[args.size()]); } /** * Returns the current argument. */ public String get() { return hasMore() ? args_.get(pos_) : null; } /** * Returns the next argument string and proceeds to the next argument. */ public String next() { return next(null); } /** * Returns the next argument string or throws an IllegalArgumentException if there * are no more arguments left. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. */ public String next(String what) { if (!hasMore()) { String message = what != null ? "missing argument: " + what : "no arguments left"; throw new IllegalArgumentException(message); } return args_.get(pos_++); } /** * Returns the next argument string as int. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. * @throws IllegalArgumentException if there are no more arguments left. */ public int nextInt(String what) { String s = next(what); try { return Integer.parseInt(s); } catch(NumberFormatException e) { throw createConvertException(what, "'" + s + "' is not a integer", e); } } /** * Returns the next argument string as boolean. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. * @throws IllegalArgumentException if there are no more arguments left. */ public boolean nextBoolean(String what) { String s = next(what); return Boolean.parseBoolean(s); } /** * Returns the next argument string as File. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. * @throws IllegalArgumentException if there are no more arguments left. */ public File nextFile(String what) { return nextFile(what, null); } /** * Returns the next argument string as File. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. * @param fileType the expected file type. * @throws IllegalArgumentException if there are no more arguments left or the file * does not match the expected file type */ public File nextFile(String what, FileType fileType) { File file = new File(next(what)); if (fileType != null) fileType.check(file, what); return file; } /** * Interprets the next argument string as class name and returns a * new instance of that class. * @param what describes the parameter. Used when a IllegalArgumentException is thrown. * @param superClass a super class of the class. */ public <T> T nextObject(String what, Class<T> superClass) { String className = next(what); try { return ClassUtil.createObject(className, superClass, null); } catch(Exception e) { throw createConvertException(what, e.getMessage(), e); } } /** * Returns if the next argument matches the string. If true, * the string is consumed. */ public boolean consume(String s) { if (hasMore() && args_.get(pos_).equals(s)) { pos_++; return true; } else return false; } /** * Replaces the current argument with the string. */ public void replace(String s) { if (hasMore()) args_.set(pos_, s); } /** * Returns if the next argument starts with the given string. */ public boolean startsWith(String s) { return hasMore() && args_.get(pos_).startsWith(s); } /** * Returns if there are more arguments left. */ public boolean hasMore() { return pos_ < args_.size(); } /** * Returns if there are at least n more arguments. */ public boolean hasMore(int amount) { return pos_ + amount <= args_.size(); } /** * Returns the remaining arguments. */ public List<String> getRestArgs() { return args_.subList(pos_, args_.size()); } private IllegalArgumentException createConvertException(String what, String message, Exception cause) { if (what != null) message = "reading " + what + ": " + message; return new IllegalArgumentException(message, cause); } private ArrayList<String> args_; private int pos_; private ResourceLoader loader_; }