mirror of
https://github.com/lucaspalomodevelop/txtmark.git
synced 2026-03-12 23:37:22 +00:00
Adding a more versatile command line interface.
This commit is contained in:
parent
315d9d0809
commit
b844c63736
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2015 René Jeschke <rene_jeschke@yahoo.de>
|
||||
*
|
||||
* 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 com.github.rjeschke.txtmark.cmd;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation for command line parsing.
|
||||
*
|
||||
* @author René Jeschke (rene_jeschke@yahoo.de)
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@interface CmdArgument
|
||||
{
|
||||
/**
|
||||
* Long name for argument. Default is 'none'. Either one or both of {@code l}, {@code s} need to be provided.
|
||||
*/
|
||||
String l() default "";
|
||||
|
||||
/**
|
||||
* Short name (character) for argument. Default is 'none'. Either one or both of {@code l}, {@code s} need to be provided.
|
||||
*/
|
||||
char s() default '\0';
|
||||
|
||||
/**
|
||||
* A description for this argument. Default is 'none'.
|
||||
*/
|
||||
String desc() default "";
|
||||
|
||||
/**
|
||||
* List item separator. Default is ','.
|
||||
*/
|
||||
char listSep() default ',';
|
||||
|
||||
/**
|
||||
* Class for List-type arguments. Default is {@code String.class}.
|
||||
*/
|
||||
Class<?> listType() default String.class;
|
||||
|
||||
/**
|
||||
* Set to {@code true} if this is a switch. Requires a {@code boolean} field which gets set to {@code true} when this argument is provided.
|
||||
*/
|
||||
boolean isSwitch() default false;
|
||||
|
||||
/**
|
||||
* Set to {@code true} if this is a required argument.
|
||||
*/
|
||||
boolean required() default false;
|
||||
|
||||
/**
|
||||
* Set to {@code true} to set this as a catch-all argument. Requires a {@code List} field and will parse all arguments following this switch into the list.
|
||||
*/
|
||||
boolean catchAll() default false;
|
||||
|
||||
/**
|
||||
* Set to {@code false} to disable automatic default value printing for this argument.
|
||||
*/
|
||||
boolean printDefault() default true;
|
||||
}
|
||||
691
src/main/java/com/github/rjeschke/txtmark/cmd/CmdLineParser.java
Normal file
691
src/main/java/com/github/rjeschke/txtmark/cmd/CmdLineParser.java
Normal file
@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2015 René Jeschke <rene_jeschke@yahoo.de>
|
||||
*
|
||||
* 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 com.github.rjeschke.txtmark.cmd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Generic command line parser.
|
||||
*
|
||||
* This is a copy from neetutils-base.
|
||||
*
|
||||
* @author René Jeschke (rene_jeschke@yahoo.de)
|
||||
*/
|
||||
final class CmdLineParser
|
||||
{
|
||||
private CmdLineParser()
|
||||
{
|
||||
// meh!
|
||||
}
|
||||
|
||||
enum Type
|
||||
{
|
||||
UNSUPPORTED, STRING, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, LIST, BOOL;
|
||||
}
|
||||
|
||||
final static HashMap<Class<?>, Type> TYPE_MAP = new HashMap<Class<?>, Type>();
|
||||
final static Class<?>[] TYPE_CLASS_LIST = Colls.<Class<?>> objArray(String.class, byte.class,
|
||||
Byte.class, short.class, Short.class, int.class,
|
||||
Integer.class, long.class, Long.class, float.class,
|
||||
Float.class, double.class, Double.class, List.class,
|
||||
Boolean.class, boolean.class);
|
||||
final static Type[] TYPE_TYPE_LIST = Colls.objArray(Type.STRING, Type.BYTE, Type.BYTE,
|
||||
Type.SHORT,
|
||||
Type.SHORT, Type.INT, Type.INT, Type.LONG, Type.LONG,
|
||||
Type.FLOAT, Type.FLOAT, Type.DOUBLE, Type.DOUBLE,
|
||||
Type.LIST, Type.BOOL, Type.BOOL);
|
||||
|
||||
final static HashSet<String> BOOL_TRUE = new HashSet<String>(Colls.list("on", "true", "yes"));
|
||||
final static HashSet<String> BOOL_FALSE = new HashSet<String>(Colls.list("off", "false", "no"));
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < TYPE_CLASS_LIST.length; i++)
|
||||
{
|
||||
TYPE_MAP.put(TYPE_CLASS_LIST[i], TYPE_TYPE_LIST[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static Type getTypeFor(final Class<?> clazz)
|
||||
{
|
||||
final Type type = TYPE_MAP.get(clazz);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
if (Classes.implementsInterface(clazz, List.class))
|
||||
{
|
||||
return Type.LIST;
|
||||
}
|
||||
|
||||
return Type.UNSUPPORTED;
|
||||
}
|
||||
|
||||
static String defaultToString(final Object value, final Type type, final Arg arg)
|
||||
{
|
||||
if (value == null || arg.isSwitch || arg.catchAll || !arg.printDefault)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type == Type.LIST)
|
||||
{
|
||||
final List<?> list = (List<?>)value;
|
||||
|
||||
if (list.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final Once<String> once = Once.of("", Character.toString(arg.itemSep));
|
||||
for (final Object o : list)
|
||||
{
|
||||
sb.append(once.get());
|
||||
sb.append(o.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static void parseArgs(final Object[] objs, final List<Arg> allArgs, final HashMap<String, Arg> shortArgs,
|
||||
final HashMap<String, Arg> longArgs)
|
||||
throws IOException
|
||||
{
|
||||
for (final Object obj : objs)
|
||||
{
|
||||
final Class<?> cl = obj.getClass();
|
||||
final Field[] fields = cl.getDeclaredFields();
|
||||
|
||||
for (final Field f : fields)
|
||||
{
|
||||
if (f.isAnnotationPresent(CmdArgument.class))
|
||||
{
|
||||
final Arg arg = new Arg(f.getAnnotation(CmdArgument.class), obj, f);
|
||||
|
||||
if (arg.type == Type.UNSUPPORTED)
|
||||
{
|
||||
throw new IOException("Unsupported parameter type: " + f.getType().getCanonicalName()
|
||||
+ " for: " + arg);
|
||||
}
|
||||
|
||||
if (arg.listType == Type.UNSUPPORTED || arg.listType == Type.LIST)
|
||||
{
|
||||
throw new IOException("Unsupported list type: " + f.getType().getCanonicalName() + " for: "
|
||||
+ arg);
|
||||
}
|
||||
|
||||
if (Strings.isEmpty(arg.s) && Strings.isEmpty(arg.l))
|
||||
{
|
||||
throw new IOException("Missing parameter name");
|
||||
}
|
||||
|
||||
if (!Strings.isEmpty(arg.s))
|
||||
{
|
||||
if (shortArgs.containsKey(arg.s))
|
||||
{
|
||||
throw new IOException("Duplicate short argument: -" + arg.s);
|
||||
}
|
||||
shortArgs.put(arg.s, arg);
|
||||
}
|
||||
|
||||
if (!Strings.isEmpty(arg.l))
|
||||
{
|
||||
if (longArgs.containsKey(arg.l))
|
||||
{
|
||||
throw new IOException("Duplicate long argument: --" + arg.l);
|
||||
}
|
||||
longArgs.put(arg.l, arg);
|
||||
}
|
||||
|
||||
if (arg.isCatchAll() && arg.type != Type.LIST)
|
||||
{
|
||||
throw new IOException("Parameter '" + arg + "' requires a List field.");
|
||||
}
|
||||
|
||||
if (arg.isSwitch && arg.type != Type.BOOL)
|
||||
{
|
||||
throw new IOException("Parameter '" + arg + "' requires a Boolean/boolean field.");
|
||||
}
|
||||
|
||||
allArgs.add(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a formatted help (Unix-style) for the given argument objects.
|
||||
*
|
||||
* @param columnWidth
|
||||
* Maximum column width. Words get wrapped at spaces.
|
||||
* @param sort
|
||||
* Set {@code true} to sort arguments before printing.
|
||||
* @param objs
|
||||
* One or more objects with annotated public fields.
|
||||
* @return The formatted argument help text.
|
||||
* @throws IOException
|
||||
* if a parsing error occurred.
|
||||
* @see CmdArgument
|
||||
*/
|
||||
public static String generateHelp(final int columnWidth, final boolean sort, final Object... objs)
|
||||
throws IOException
|
||||
{
|
||||
final List<Arg> allArgs = Colls.list();
|
||||
final HashMap<String, Arg> shortArgs = new HashMap<String, Arg>();
|
||||
final HashMap<String, Arg> longArgs = new HashMap<String, Arg>();
|
||||
|
||||
parseArgs(objs, allArgs, shortArgs, longArgs);
|
||||
|
||||
int minArgLen = 0;
|
||||
|
||||
for (final Arg a : allArgs)
|
||||
{
|
||||
int len = a.toString().length();
|
||||
if (!a.isSwitch)
|
||||
{
|
||||
++len;
|
||||
len += a.getResolvedType().toString().length();
|
||||
if (a.isCatchAll())
|
||||
{
|
||||
++len;
|
||||
}
|
||||
else if (a.isList())
|
||||
{
|
||||
len += 6;
|
||||
}
|
||||
}
|
||||
minArgLen = Math.max(minArgLen, len);
|
||||
}
|
||||
minArgLen += 2;
|
||||
if (sort)
|
||||
{
|
||||
Collections.sort(allArgs);
|
||||
}
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final Arg a : allArgs)
|
||||
{
|
||||
final StringBuilder line = new StringBuilder();
|
||||
line.append(' ');
|
||||
line.append(a);
|
||||
if (!a.isSwitch)
|
||||
{
|
||||
line.append(' ');
|
||||
line.append(a.getResolvedType().toString().toLowerCase());
|
||||
if (a.isCatchAll())
|
||||
{
|
||||
line.append('s');
|
||||
}
|
||||
else if (a.isList())
|
||||
{
|
||||
line.append('[');
|
||||
line.append(a.itemSep);
|
||||
line.append("...]");
|
||||
}
|
||||
}
|
||||
while (line.length() < minArgLen)
|
||||
{
|
||||
line.append(' ');
|
||||
}
|
||||
|
||||
line.append(':');
|
||||
|
||||
final StringBuilder desc = new StringBuilder(a.desc.trim());
|
||||
|
||||
final String defVal = defaultToString(a.safeFieldGet(), a.type, a);
|
||||
|
||||
if (defVal != null)
|
||||
{
|
||||
desc.append(" Default is: '");
|
||||
desc.append(defVal);
|
||||
desc.append("'.");
|
||||
}
|
||||
|
||||
final List<String> toks = Strings.split(desc.toString(), ' ');
|
||||
|
||||
for (final String s : toks)
|
||||
{
|
||||
if (line.length() + s.length() + 1 > columnWidth)
|
||||
{
|
||||
sb.append(line);
|
||||
sb.append('\n');
|
||||
line.setLength(0);
|
||||
while (line.length() <= minArgLen)
|
||||
{
|
||||
line.append(' ');
|
||||
}
|
||||
line.append(' ');
|
||||
}
|
||||
line.append(' ');
|
||||
line.append(s);
|
||||
}
|
||||
|
||||
if (line.length() > minArgLen)
|
||||
{
|
||||
sb.append(line);
|
||||
sb.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses command line arguments.
|
||||
*
|
||||
* @param args
|
||||
* Array of arguments, like the ones provided by
|
||||
* {@code void main(String[] args)}
|
||||
* @param objs
|
||||
* One or more objects with annotated public fields.
|
||||
* @return A {@code List} containing all unparsed arguments (i.e. arguments
|
||||
* that are no switches)
|
||||
* @throws IOException
|
||||
* if a parsing error occurred.
|
||||
* @see CmdArgument
|
||||
*/
|
||||
public static List<String> parse(final String[] args, final Object... objs) throws IOException
|
||||
{
|
||||
final List<String> ret = Colls.list();
|
||||
|
||||
final List<Arg> allArgs = Colls.list();
|
||||
final HashMap<String, Arg> shortArgs = new HashMap<String, Arg>();
|
||||
final HashMap<String, Arg> longArgs = new HashMap<String, Arg>();
|
||||
|
||||
parseArgs(objs, allArgs, shortArgs, longArgs);
|
||||
|
||||
for (int i = 0; i < args.length; i++)
|
||||
{
|
||||
final String s = args[i];
|
||||
|
||||
final Arg a;
|
||||
|
||||
if (s.startsWith("--"))
|
||||
{
|
||||
a = longArgs.get(s.substring(2));
|
||||
if (a == null)
|
||||
{
|
||||
throw new IOException("Unknown switch: " + s);
|
||||
}
|
||||
}
|
||||
else if (s.startsWith("-"))
|
||||
{
|
||||
a = shortArgs.get(s.substring(1));
|
||||
if (a == null)
|
||||
{
|
||||
throw new IOException("Unknown switch: " + s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a = null;
|
||||
ret.add(s);
|
||||
}
|
||||
|
||||
if (a != null)
|
||||
{
|
||||
if (a.isSwitch)
|
||||
{
|
||||
a.setField("true");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + 1 >= args.length)
|
||||
{
|
||||
System.out.println("Missing parameter for: " + s);
|
||||
}
|
||||
if (a.isCatchAll())
|
||||
{
|
||||
final List<String> ca = Colls.list();
|
||||
for (++i; i < args.length; ++i)
|
||||
{
|
||||
ca.add(args[i]);
|
||||
}
|
||||
a.setCatchAll(ca);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
a.setField(args[i]);
|
||||
}
|
||||
}
|
||||
a.setPresent();
|
||||
}
|
||||
}
|
||||
|
||||
for (final Arg a : allArgs)
|
||||
{
|
||||
if (!a.isOk())
|
||||
{
|
||||
throw new IOException("Missing mandatory argument: " + a);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static class Arg implements Comparable<Arg>
|
||||
{
|
||||
final String s;
|
||||
final String l;
|
||||
final String id;
|
||||
final String desc;
|
||||
final char itemSep;
|
||||
final boolean isSwitch;
|
||||
final boolean required;
|
||||
final boolean catchAll;
|
||||
final boolean printDefault;
|
||||
final Type type;
|
||||
final Type listType;
|
||||
boolean present = false;
|
||||
final Object object;
|
||||
final Field field;
|
||||
|
||||
public Arg(final CmdArgument arg, final Object obj, final Field field)
|
||||
{
|
||||
this.s = arg.s() == 0 ? "" : Character.toString(arg.s());
|
||||
this.l = arg.l();
|
||||
this.desc = arg.desc();
|
||||
this.isSwitch = arg.isSwitch();
|
||||
this.required = arg.required();
|
||||
this.catchAll = arg.catchAll();
|
||||
this.itemSep = arg.listSep();
|
||||
this.printDefault = arg.printDefault();
|
||||
this.id = this.s + "/" + this.l;
|
||||
|
||||
this.object = obj;
|
||||
this.field = field;
|
||||
this.type = getTypeFor(this.field.getType());
|
||||
this.listType = getTypeFor(arg.listType());
|
||||
}
|
||||
|
||||
public Type getResolvedType()
|
||||
{
|
||||
return this.isList() ? this.listType : this.type;
|
||||
}
|
||||
|
||||
public boolean isCatchAll()
|
||||
{
|
||||
return this.catchAll;
|
||||
}
|
||||
|
||||
public boolean isList()
|
||||
{
|
||||
return this.type == Type.LIST;
|
||||
}
|
||||
|
||||
public void setCatchAll(final List<String> list) throws IOException
|
||||
{
|
||||
this.setListField(list);
|
||||
}
|
||||
|
||||
public void setListField(final List<String> list) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.listType == Type.STRING)
|
||||
{
|
||||
this.field.set(this.object, list);
|
||||
}
|
||||
else
|
||||
{
|
||||
final List<Object> temp = Colls.list();
|
||||
for (final String i : list)
|
||||
{
|
||||
temp.add(this.toObject(i, this.listType));
|
||||
}
|
||||
this.field.set(this.object, temp);
|
||||
}
|
||||
}
|
||||
catch (final IllegalArgumentException e)
|
||||
{
|
||||
throw new IOException("Failed to write value", e);
|
||||
}
|
||||
catch (final IllegalAccessException e)
|
||||
{
|
||||
throw new IOException("Failed to write value", e);
|
||||
}
|
||||
}
|
||||
|
||||
Object safeFieldGet()
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.field.get(this.object);
|
||||
}
|
||||
catch (final Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object toObject(final String value, final Type type) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case STRING:
|
||||
return value;
|
||||
case BYTE:
|
||||
return Byte.parseByte(value);
|
||||
case SHORT:
|
||||
return Short.parseShort(value);
|
||||
case INT:
|
||||
return Integer.parseInt(value);
|
||||
case LONG:
|
||||
return Long.parseLong(value);
|
||||
case FLOAT:
|
||||
return Float.parseFloat(value);
|
||||
case DOUBLE:
|
||||
return Double.parseDouble(value);
|
||||
case BOOL:
|
||||
if (BOOL_TRUE.contains(value.toLowerCase()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (BOOL_FALSE.contains(value.toLowerCase()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
throw new IOException("Illegal bool value for:" + this.toString());
|
||||
default:
|
||||
throw new IOException("Illegal type: " + type.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
catch (final Throwable t)
|
||||
{
|
||||
throw new IOException("Parsing error for: " + this.toString() + "; '" + value + "'", t);
|
||||
}
|
||||
}
|
||||
|
||||
public void setField(final String value) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.isList())
|
||||
{
|
||||
this.setListField(Strings.split(value, this.itemSep));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.field.set(this.object, this.toObject(value, this.type));
|
||||
}
|
||||
}
|
||||
catch (final IllegalArgumentException e)
|
||||
{
|
||||
throw new IOException("Failed to write field: " + this.field.getName(), e);
|
||||
}
|
||||
catch (final IllegalAccessException e)
|
||||
{
|
||||
throw new IOException("Failed to write field: " + this.field.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPresent()
|
||||
{
|
||||
this.present = true;
|
||||
}
|
||||
|
||||
public boolean isOk()
|
||||
{
|
||||
return !this.required || this.present;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return this.id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj)
|
||||
{
|
||||
if (obj instanceof Arg)
|
||||
{
|
||||
return this.id.equals(((Arg)obj).id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (Strings.isEmpty(this.s))
|
||||
{
|
||||
return " --" + this.l;
|
||||
}
|
||||
if (Strings.isEmpty(this.l))
|
||||
{
|
||||
return "-" + this.s;
|
||||
}
|
||||
return "-" + this.s + ", --" + this.l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Arg o)
|
||||
{
|
||||
final String a = Strings.isEmpty(this.s) ? this.l : this.s;
|
||||
final String b = Strings.isEmpty(o.s) ? o.l : o.s;
|
||||
return a.compareTo(b);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Once<T>
|
||||
{
|
||||
private final T first;
|
||||
private final T next;
|
||||
private boolean isFirst = true;
|
||||
|
||||
public Once(final T first, final T next)
|
||||
{
|
||||
this.first = first;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public static <T> Once<T> of(final T first, final T next)
|
||||
{
|
||||
return new Once<T>(first, next);
|
||||
}
|
||||
|
||||
public T get()
|
||||
{
|
||||
if (this.isFirst)
|
||||
{
|
||||
this.isFirst = false;
|
||||
return this.first;
|
||||
}
|
||||
|
||||
return this.next;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Colls
|
||||
{
|
||||
final static <T> T[] objArray(final T... ts)
|
||||
{
|
||||
return ts;
|
||||
}
|
||||
|
||||
final static <A> List<A> list(final A... coll)
|
||||
{
|
||||
final List<A> ret = new ArrayList<A>(coll.length);
|
||||
for (int i = 0; i < coll.length; i++)
|
||||
{
|
||||
ret.add(coll[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Classes
|
||||
{
|
||||
final static boolean implementsInterface(final Class<?> clazz, final Class<?> interfce)
|
||||
{
|
||||
for (final Class<?> c : clazz.getInterfaces())
|
||||
{
|
||||
if (c.equals(interfce))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class Strings
|
||||
{
|
||||
public final static boolean isEmpty(final String str)
|
||||
{
|
||||
return str == null || str.isEmpty();
|
||||
}
|
||||
|
||||
public final static List<String> split(final String str, final char ch)
|
||||
{
|
||||
final List<String> ret = Colls.list();
|
||||
|
||||
if (str != null)
|
||||
{
|
||||
int s = 0, e = 0;
|
||||
while (e < str.length())
|
||||
{
|
||||
if (str.charAt(e) == ch)
|
||||
{
|
||||
ret.add(str.substring(s, e));
|
||||
s = e + 1;
|
||||
}
|
||||
e++;
|
||||
}
|
||||
ret.add(str.substring(s, e));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/main/java/com/github/rjeschke/txtmark/cmd/Run.java
Normal file
142
src/main/java/com/github/rjeschke/txtmark/cmd/Run.java
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2015 René Jeschke <rene_jeschke@yahoo.de>
|
||||
*
|
||||
* 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 com.github.rjeschke.txtmark.cmd;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.rjeschke.txtmark.Configuration;
|
||||
import com.github.rjeschke.txtmark.Processor;
|
||||
|
||||
public class Run
|
||||
{
|
||||
public static void printUsage()
|
||||
{
|
||||
try
|
||||
{
|
||||
System.out.println("Usage: txtmark [options] [input-file]");
|
||||
System.out.println("Options:");
|
||||
System.out.println(CmdLineParser.generateHelp(80, false, new TxtmarkArguments()));
|
||||
}
|
||||
catch (final IOException e)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(final String[] args)
|
||||
{
|
||||
final TxtmarkArguments ta = new TxtmarkArguments();
|
||||
List<String> rest = new ArrayList<String>();
|
||||
|
||||
boolean parseError = false;
|
||||
try
|
||||
{
|
||||
rest = CmdLineParser.parse(args, ta);
|
||||
}
|
||||
catch (final IOException e)
|
||||
{
|
||||
parseError = true;
|
||||
}
|
||||
|
||||
if (ta.printHelp || parseError)
|
||||
{
|
||||
printUsage();
|
||||
System.exit(parseError ? 1 : 0);
|
||||
}
|
||||
|
||||
final Configuration.Builder cfgBuilder = Configuration.builder();
|
||||
cfgBuilder.setEncoding(ta.encoding)
|
||||
.setEnablePanicMode(ta.panicMode)
|
||||
.setSafeMode(ta.safeMode);
|
||||
|
||||
if (ta.forceExtendedProfile)
|
||||
{
|
||||
cfgBuilder.forceExtentedProfile();
|
||||
}
|
||||
|
||||
final Configuration config = cfgBuilder.build();
|
||||
boolean processOk = true;
|
||||
InputStream input = null;
|
||||
Writer output = null;
|
||||
try
|
||||
{
|
||||
final String inFile = rest.isEmpty() ? "--" : rest.get(0);
|
||||
final String outFile = ta.outFile;
|
||||
|
||||
if (inFile.equals("--"))
|
||||
{
|
||||
input = System.in;
|
||||
}
|
||||
else
|
||||
{
|
||||
input = new FileInputStream(inFile);
|
||||
}
|
||||
|
||||
final String result = Processor.process(input, config);
|
||||
|
||||
if (outFile == null)
|
||||
{
|
||||
output = new OutputStreamWriter(System.out, ta.encoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = new OutputStreamWriter(new FileOutputStream(outFile), ta.encoding);
|
||||
}
|
||||
|
||||
output.write(result);
|
||||
}
|
||||
catch (final IOException e)
|
||||
{
|
||||
processOk = false;
|
||||
System.err.println("Exception: " + e.toString());
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (input != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
input.close();
|
||||
}
|
||||
catch (final IOException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (output != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
output.close();
|
||||
}
|
||||
catch (final IOException e)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(processOk ? 0 : 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2015 René Jeschke <rene_jeschke@yahoo.de>
|
||||
*
|
||||
* 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 com.github.rjeschke.txtmark.cmd;
|
||||
|
||||
class TxtmarkArguments
|
||||
{
|
||||
@CmdArgument(l = "help", s = 'h', isSwitch = true, desc = "prints a summary of command line arguments.")
|
||||
public boolean printHelp = false;
|
||||
|
||||
@CmdArgument(l = "extended", isSwitch = true, desc = "forces extended profile")
|
||||
public boolean forceExtendedProfile = false;
|
||||
|
||||
@CmdArgument(l = "panic-mode", isSwitch = true, desc = "enables panic mode")
|
||||
public boolean panicMode = false;
|
||||
|
||||
@CmdArgument(l = "safe-mode", isSwitch = true, desc = "enables safe mode")
|
||||
public boolean safeMode = false;
|
||||
|
||||
@CmdArgument(l = "encoding", desc = "sets the IO encoding.")
|
||||
public String encoding = "UTF-8";
|
||||
|
||||
@CmdArgument(l = "out-file", s = 'o', desc = "specifies output filename")
|
||||
public String outFile = null;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user