All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wycc.util.OptArg Maven / Gradle / Ivy

// Copyright 2011 The Whiley Project Developers
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// 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 wycc.util;

import java.io.File;
import java.io.PrintStream;
import java.util.*;

/**
 * A small utility for parsing command-line options. It helps to take some of
 * the hassle out of building the front-end of a Whiley compiler.
 *
 * @author David J. Pearce
 *
 */
public final class OptArg {
	/**
	 * The long form of the option. (e.g. for "-version", the long form is
	 * "version")
	 */
	public final String option;

	/**
	 * The short form of the option. (e.g. for "-version", the short form might
	 * be "v" as in "-v")
	 */
	public final String shortForm;

	/**
	 * The kind of argument accepted by this option (if any).
	 */
	public final Kind argument;

	/**
	 * A description of the option. This is used when printing out "usage"
	 * information.
	 */
	public final String description;

	/**
	 * A default value for the option (assuming it accepts an argument). This
	 * may be null if there is no default value.
	 */
	public final Object defaultValue;

	/**
	 * Construct an option object which does not accept an argument.
	 *
	 * @param option
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option,String description) {
		this.option = option;
		this.shortForm = null;
		this.argument = null;
		this.description = description;
		this.defaultValue = null;
	}

	/**
	 * Construct an option object with a short form which does not accept an argument.
	 *
	 * @param option
	 * @param shortForm
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option,String shortForm, String description) {
		this.option = option;
		this.shortForm = shortForm;
		this.argument = null;
		this.description = description;
		this.defaultValue = null;
	}

	/**
	 * Construct an option object which accepts an argument.
	 *
	 * @param option
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option, Kind argument,
			String description) {
		this.option = option;
		this.shortForm = null;
		this.argument = argument;
		this.description = description;
		this.defaultValue = null;
	}

	/**
	 * Construct an option object with a short form which accepts an argument.
	 *
	 * @param option
	 * @param shortForm
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option, String shortForm, Kind argument,
			String description) {
		this.option = option;
		this.shortForm = shortForm;
		this.argument = argument;
		this.description = description;
		this.defaultValue = null;
	}

	/**
	 * Construct an option object which accepts an argument and has a default value.
	 *
	 * @param option
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option, Kind argument,
			String description, Object defaultValue) {
		this.option = option;
		this.shortForm = null;
		this.argument = argument;
		this.description = description;
		this.defaultValue = defaultValue;
	}

	/**
	 * Construct an option object with a short form which accepts an argument and has a default value.
	 *
	 * @param option
	 * @param argument
	 * @param description
	 * @param defaultValue
	 */
	public OptArg(String option, String shortForm, Kind argument,
			String description, Object defaultValue) {
		this.option = option;
		this.shortForm = shortForm;
		this.argument = argument;
		this.description = description;
		this.defaultValue = defaultValue;
	}

	interface Kind {
		void process(String arg, String option, Map options);
	}

	public final static STRING STRING = new STRING();
	public final static STRINGARRAY STRINGARRAY = new STRINGARRAY();
	public final static INT INT = new INT();
	public final static LONG LONG  = new LONG();
	public final static FILE FILE = new FILE();
	public final static FILEDIR FILEDIR = new FILEDIR();
	public final static FILELIST FILELIST = new FILELIST();
	public final static OPTIONSMAP OPTIONSMAP = new OPTIONSMAP();

	private static final class STRING implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			options.put(arg,option);
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class STRINGARRAY implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			String[] array = option.split(":");
			options.put(arg,array);
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class INT implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			options.put(arg,Integer.parseInt(option));
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class LONG implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			options.put(arg,Long.parseLong(option));
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class FILE implements Kind {
		@Override
		public void process(String arg, String option,
				Map options) {
			options.put(arg, new File(option));
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class FILEDIR implements Kind {
		@Override
		public void process(String arg, String option,
				Map options) {
			File dir = new File(option);
			if(!dir.isDirectory()) {
				throw new IllegalArgumentException("invalid path --- " + arg);
			}
			options.put(arg, dir);
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class FILELIST implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			ArrayList rs = new ArrayList<>();
			for(String r : option.split(File.pathSeparator)) {
				rs.add(new File(r));
			}
			options.put(arg, rs);
		}
		@Override
		public String toString() {
			return "";
		}
	}

	private static final class OPTIONSMAP implements Kind {
		@Override
		public void process(String arg, String option, Map options) {
			String[] name = option.split(":");
			Map config = Collections.EMPTY_MAP;
			if (name.length > 1) {
				config = splitConfig(name[1]);
			}
			Map> values = (Map>) options.get(arg);

			if(values == null) {
				values = new HashMap<>();
				options.put(arg, values);
			}

			Map attributes = values.get(name[0]);

			if(attributes == null) {
				values.put(name[0], config);
			} else {
				attributes.putAll(config);
			}
		}
		@Override
		public String toString() {
			return "name:[attribute=value]+";
		}
	}

	/**
	 * Parse options from the list of arguments, removing those which are
	 * recognised. Anything which is not recognised is left as is.
	 *
	 * @param args
	 *            --- the list of argument strings. This is modified by removing
	 *            those which are processed.
	 * @param options
	 *            --- the list of OptArg defining which options should be
	 *            processed
	 * @throws --- a RuntimeException if an unrecognised option is
	 *         encountered (that is, a token starting with '-')..
	 */
	public static Map parseOptions(List args, OptArg... options) {
		HashMap result = new HashMap<>();
		HashMap soptmap = new HashMap<>();
		HashMap loptmap = new HashMap<>();

		for(OptArg opt : options) {
			if(opt.defaultValue != null) {
				result.put(opt.option, opt.defaultValue);
			}
			loptmap.put(opt.option, opt);
			soptmap.put(opt.shortForm, opt);
		}

		Iterator iter = args.iterator();
		while(iter.hasNext()) {
			String arg = iter.next();
			OptArg opt;
			String param;
			if (arg.startsWith("--")) {
				Object[] p = parseLongForm(arg, iter, loptmap);
				opt = (OptArg) p[0];
				param = (String) p[1];
			} else if(arg.startsWith("-")) {
				Object[] p = parseShortForm(arg, iter, soptmap);
				opt = (OptArg) p[0];
				param = (String) p[1];
			} else {
				continue;
			}
			// Process option
			Kind k = opt.argument;
			if (k != null) {
				k.process(opt.option, param, result);
			} else {
				result.put(opt.option, null);
			}
		}

		return result;
	}

	private static Object[] parseLongForm(String arg, Iterator iter, Map opts) {
		arg = arg.substring(2,arg.length());
		String[] _args = arg.split("=");
		OptArg opt = opts.get(_args[0]);
		String param;
		if(opt != null) {
			// matched
			iter.remove(); // remove option from args list
			switch(_args.length) {
			case 1:
				param = null;
				break;
			case 2:
				param = _args[1];
				break;
			default:
				throw new IllegalArgumentException("error parsing \"" + arg + "\"");
			}
		} else {
			throw new RuntimeException("unknown command-line option: -" + arg);
		}
		return new Object[] {opt,param};
	}

	private static Object[] parseShortForm(String arg, Iterator iter, Map opts) {
		arg = arg.substring(1,arg.length());
		OptArg opt = opts.get(arg);
		String param;
		if(opt != null) {
			// matched
			iter.remove(); // remove option from args list
			//
			if(opt.argument != null) {
				param = iter.next();
				iter.remove(); // remove option from args list
			} else {
				param = null;
			}
		} else {
			throw new RuntimeException("unknown command-line option: -" + arg);
		}
		return new Object[] {opt,param};
	}

	public static void usage(PrintStream output, OptArg...options) {
		// first, work out gap information
		int gap = 0;
		ArrayList opts = new ArrayList<>();
		for (OptArg opt : options) {
			opts.add(opt);
			int len = opt.option.length();
			if(opt.argument != null) {
				len = len + opt.argument.toString().length();
			}
			if(opt.shortForm != null) {
				len = len + opt.shortForm.length();
				opts.add(new OptArg(opt.shortForm,opt.argument,opt.description + " [short form]"));
			}
			gap = Math.max(gap, len);
		}

		gap = gap + 1;

		// now, print the information
		for (OptArg opt : opts) {
			output.print("  -" + opt.option);
			int rest = gap - opt.option.length();
			output.print(" ");
			if(opt.argument != null) {
				String arg = opt.argument.toString();
				rest -= arg.length();
				output.print(arg);
			}
			for (int i = 0; i < rest; ++i) {
				output.print(" ");
			}
			output.println(opt.description);
		}
	}

	/**
	 * This splits strings of the form "x=y,v=w" into distinct components and
	 * puts them into a map. In the case of a string like "x,y=z" then x is
	 * loaded with the empty string.
	 *
	 * @param str
	 * @return
	 */
	private static Map splitConfig(String str) {
		HashMap options = new HashMap<>();
		String[] splits = str.split(",");
		for (String s : splits) {
			String[] p = s.split("=");
			options.put(p[0], parseValue(p[1]));
		}
		return options;
	}

	private static Object parseValue(String str) {
		if(str.equals("true")) {
			return Boolean.TRUE;
		} else if(str.equals("false")) {
			return Boolean.FALSE;
		} else if(Character.isDigit(str.charAt(0))) {
			if(str.charAt(str.length()-1) == 'L') {
				return Long.parseLong(str.substring(0,str.length()-1));
			} else {
				return Integer.parseInt(str);
			}
		} else  {
			return str;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy