| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 jena.cmd; |
| |
| import static java.nio.file.Files.readAllBytes; |
| |
| import java.io.IOException; |
| import java.nio.file.Paths; |
| import java.util.ArrayList ; |
| import java.util.Arrays ; |
| import java.util.Collections ; |
| import java.util.HashMap ; |
| import java.util.Iterator ; |
| import java.util.List ; |
| import java.util.Map ; |
| |
| import org.apache.jena.atlas.logging.Log ; |
| |
| /** |
| * Command line, using the common named/positional arguments paradigm |
| * (also called options/arguments). |
| */ |
| public class CmdLineArgs extends CommandLineBase { |
| public CmdLineArgs(String[] args) { |
| super(args) ; |
| } |
| |
| private boolean processedArgs = false ; |
| protected Map<String, ArgDecl> argMap = new HashMap<>() ; // Map from string name to ArgDecl |
| protected Map<String, Arg> args = new HashMap<>() ; // Name to Arg |
| protected List<String> positionals = new ArrayList<>() ; // Positional arguments as strings. |
| |
| public void process() throws IllegalArgumentException |
| { |
| processedArgs = true ; |
| apply(new ArgProcessor()) ; |
| } |
| |
| // ---- Setting the ArgDecls |
| |
| /** Add an argument to those to be accepted on the command line. |
| * @param argName Name |
| * @param hasValue True if the command takes a (string) value |
| * @return The CommandLine processor object |
| */ |
| |
| public CmdLineArgs add(String argName, boolean hasValue) { |
| return add(new ArgDecl(hasValue, argName)) ; |
| } |
| |
| /** Add an argument to those to be accepted on the command line. |
| * Argument order reflects ArgDecl. |
| * @param hasValue True if the command takes a (string) value |
| * @param argName Name |
| * @return The CommandLine processor object |
| */ |
| |
| public CmdLineArgs add(boolean hasValue, String argName) { |
| return add(new ArgDecl(hasValue, argName)) ; |
| } |
| |
| /** Add an argument object |
| * @param arg Argument to add |
| * @return The CommandLine processor object |
| */ |
| |
| public CmdLineArgs add(ArgDecl arg) { |
| for (Iterator<String> iter = arg.names(); iter.hasNext();) { |
| String name = iter.next() ; |
| if ( argMap.containsKey(name) ) |
| Log.warn(this, "Argument '" + name + "' already added") ; |
| argMap.put(name, arg) ; |
| } |
| return this ; |
| } |
| |
| /** |
| * Add a positional parameter |
| * @param value |
| * @return this object |
| */ |
| public CmdLineArgs addPositional(String value) { |
| positionals.add(value) ; |
| return this ; |
| } |
| |
| /** |
| * Add a named argument which has no value. |
| * @param name |
| * @return this |
| */ |
| public CmdLineArgs addArg(String name) { |
| return addArg(name, null) ; |
| } |
| |
| /** |
| * Add a named argument/value pair |
| * @param name |
| * @param value |
| * @return this object |
| */ |
| public CmdLineArgs addArg(String name, String value) { |
| if ( !args.containsKey(name) ) |
| args.put(name, new Arg(name)) ; |
| Arg arg = args.get(name) ; |
| return addArgWorker(arg, value) ; |
| } |
| |
| private CmdLineArgs addArgWorker(Arg arg, String value) { |
| ArgDecl argDecl = argMap.get(arg.getName()) ; |
| |
| if ( !argDecl.takesValue() && value != null ) |
| throw new IllegalArgumentException("No value for argument: " + arg.getName()) ; |
| |
| if ( argDecl.takesValue() ) { |
| if ( value == null ) |
| throw new IllegalArgumentException("No value for argument: " + arg.getName()) ; |
| |
| arg.setValue(value) ; |
| arg.addValue(value) ; |
| } |
| |
| return this ; |
| } |
| |
| // ---- Indirection |
| |
| static final String DefaultIndirectMarker = "@" ; |
| |
| public boolean matchesIndirect(String s) { return matchesIndirect(s, DefaultIndirectMarker) ; } |
| public boolean matchesIndirect(String s, String marker) { return s.startsWith(marker) ; } |
| |
| public String indirect(String s) { return indirect(s, DefaultIndirectMarker) ; } |
| |
| public String indirect(String s, String marker) { |
| if ( !matchesIndirect(s, marker) ) |
| return s ; |
| s = s.substring(marker.length()) ; |
| try { |
| return new String(readAllBytes(Paths.get(s))); |
| } catch (IOException e) { |
| throw new CmdException("Could not read from: " + s, e); |
| } |
| } |
| |
| // ---- Argument access |
| |
| /** Test whether an argument was seen. */ |
| |
| public boolean contains(ArgDecl argDecl) { return getArg(argDecl) != null ; } |
| |
| /** Test whether an argument was seen. */ |
| |
| public boolean contains(String s) { return getArg(s) != null ; } |
| |
| /** Test whether an argument was seen more than once */ |
| public boolean containsMultiple(String s) { return getValues(s).size() > 1 ; } |
| |
| /** Test whether an argument was seen more than once */ |
| public boolean containsMultiple(ArgDecl argDecl) { return getValues(argDecl).size() > 1 ; } |
| |
| public boolean hasArgs() { return args.size() > 0 ; } |
| |
| /** Test whether the command line had a particular argument |
| * |
| * @param argName |
| * @return this object |
| */ |
| public boolean hasArg(String argName) { return getArg(argName) != null ; } |
| |
| /** Test whether the command line had a particular argument |
| * |
| * @param argDecl |
| * @return true or false |
| */ |
| |
| public boolean hasArg(ArgDecl argDecl) { return getArg(argDecl) != null ; } |
| |
| |
| /** Get the argument associated with the argument declaration. |
| * Actually returns the LAST one seen |
| * @param argDecl Argument declaration to find |
| * @return Last argument that matched. |
| */ |
| |
| public Arg getArg(ArgDecl argDecl) { |
| Arg arg = null ; |
| for ( Arg a : args.values() ) |
| { |
| if ( argDecl.matches( a ) ) |
| { |
| arg = a; |
| } |
| } |
| return arg ; |
| } |
| |
| /** Get the argument associated with the argument name. |
| * Actually returns the LAST one seen |
| * @param argName Argument name |
| * @return Last argument that matched. |
| */ |
| public Arg getArg(String argName) { |
| argName = ArgDecl.canonicalForm(argName) ; |
| return args.get(argName) ; |
| } |
| |
| /** |
| * Returns the value (a string) for an argument with a value - |
| * returns null for no argument and no value. |
| * @param argDecl |
| * @return String |
| */ |
| public String getValue(ArgDecl argDecl) { |
| Arg arg = getArg(argDecl) ; |
| if ( arg == null ) |
| return null ; |
| if ( arg.hasValue() ) |
| return arg.getValue() ; |
| return null ; |
| } |
| |
| /** |
| * Returns the value (a string) for an argument with a value - |
| * returns null for no argument and no value. |
| * @param argName |
| * @return String |
| */ |
| public String getValue(String argName) { |
| Arg arg = getArg(argName) ; |
| if ( arg == null ) |
| return null ; |
| return arg.getValue() ; |
| } |
| |
| /** Is the value something that looks like "true" or "yes"? */ |
| public boolean hasValueOfTrue(ArgDecl argDecl) { |
| String x = getValue(argDecl) ; |
| if ( x == null ) |
| return false ; |
| if ( x.equalsIgnoreCase("true") || x.equalsIgnoreCase("t") || |
| x.equalsIgnoreCase("yes") || x.equalsIgnoreCase("y") ) |
| return true ; |
| return false ; |
| } |
| |
| /** Is the value something that looks like "false" or "no"? */ |
| public boolean hasValueOfFalse(ArgDecl argDecl) { |
| String x = getValue(argDecl) ; |
| if ( x == null ) |
| return false ; |
| if ( x.equalsIgnoreCase("false") || x.equalsIgnoreCase("f") || |
| x.equalsIgnoreCase("no") || x.equalsIgnoreCase("n") ) |
| return true ; |
| return false ; |
| } |
| |
| /** |
| * Returns all the values (0 or more strings) for an argument. |
| * @param argDecl |
| * @return List |
| */ |
| public List<String> getValues(ArgDecl argDecl) { |
| Arg arg = getArg(argDecl) ; |
| if ( arg == null ) |
| return new ArrayList<>() ; |
| return arg.getValues() ; |
| } |
| |
| /** |
| * Returns all the values (0 or more strings) for an argument. |
| * @param argName |
| * @return List |
| */ |
| public List<String> getValues(String argName) { |
| Arg arg = getArg(argName) ; |
| if ( arg == null ) |
| return new ArrayList<>() ; |
| return arg.getValues() ; |
| } |
| |
| // ---- Positional |
| /** Get the i'th positional argument (indexed from 0)*/ |
| public String getPositionalArg(int i) { |
| return positionals.get(i) ; |
| } |
| |
| /** Return the number of positional arguments */ |
| public int getNumPositional() { |
| return positionals.size() ; |
| } |
| |
| public boolean hasPositional() { |
| return positionals.size() > 0 ; |
| } |
| |
| public List<String> getPositional() { |
| return positionals ; |
| } |
| |
| /** Return the positional arguments or "-" to indicate stdin */ |
| public List<String> getPositionalOrStdin() { |
| if ( !positionals.isEmpty() ) |
| return Collections.unmodifiableList(positionals) ; |
| List<String> x = Arrays.asList("-") ; |
| return Collections.unmodifiableList(x) ; |
| } |
| |
| // ---- |
| |
| /** |
| * Handle an unrecognised argument; default is to throw an exception |
| * @param argStr The string image of the unrecognised argument |
| */ |
| protected void handleUnrecognizedArg( String argStr ) { |
| throw new CmdException("Unknown argument: "+argStr) ; |
| } |
| |
| @Override |
| public String toString() { |
| if ( !processedArgs ) |
| return super.toString() ; |
| String str = "" ; |
| String sep = "" ; |
| for ( String k : args.keySet() ) |
| { |
| Arg a = args.get( k ); |
| str = str + sep + a; |
| sep = " "; |
| } |
| sep = " -- " ; |
| for ( String v : positionals ) |
| { |
| str = str + sep + v; |
| sep = " "; |
| } |
| return str ; |
| } |
| |
| // ---- Process arguments after low level parsing and after ArgDecls added. |
| class ArgProcessor implements ArgProc { |
| boolean nextArgProcessed = false ; |
| boolean positionalArgsStarted = false ; |
| |
| @Override |
| public void startArgs() { |
| nextArgProcessed = false ; |
| positionalArgsStarted = false ; |
| } |
| |
| @Override |
| public void finishArgs() {} |
| |
| @Override |
| public void arg(String argStr, int i) { |
| if ( nextArgProcessed ) { |
| nextArgProcessed = false ; |
| return ; |
| } |
| |
| if ( positionalArgsStarted ) { |
| addPositional(argStr) ; |
| return ; |
| } |
| |
| if ( argStr.equals("-") || argStr.equals("--") ) { |
| positionalArgsStarted = true ; |
| return ; |
| } |
| |
| if ( !argStr.startsWith("-") ) { |
| // End of flags, start of positional arguments |
| positionalArgsStarted = true ; |
| addPositional(argStr) ; |
| return ; |
| } |
| |
| argStr = ArgDecl.canonicalForm(argStr) ; |
| if ( !argMap.containsKey(argStr) ) { |
| handleUnrecognizedArg(argStr) ; |
| return ; |
| } |
| |
| // Recognized flag |
| ArgDecl argDecl = argMap.get(argStr) ; |
| |
| if ( argDecl.takesValue() ) { |
| String val = getArg(i + 1) ; |
| // Use first name as the canonical one. |
| String x = argDecl.getKeyName() ; |
| addArg(x, val) ; |
| nextArgProcessed = true ; |
| } else |
| addArg(argStr) ; |
| } |
| } |
| } |