package com.atolsystems.atolutilities;
import com.atolsystems.atolutilities.ArgSpec;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* ACommandLineUtilities contains a set of helper function to process command line arguments.
* It supports expansion of command line from files and basic checking of arguments presence and number of occurence.
*
* @author atol systems
*/
@Deprecated
public class ACommandLineUtilities implements Serializable{
static final long serialVersionUID = 4808784752483418528L;
public static final int ARG_UNSUPPORTED_ID = 0xFFFFFFFF;
public static final int ID_NEED_INPUT_FILE = 0x40000000;
public static final int ID_NEED_OUTPUT_FILE = 0x20000000;
public static final int ID_PERSISTENT_ARG= 0x10000000;
public static final String ARG_ARGFILE = "-argFile:";
public static final int ARG_ARGFILE_ID = 0x0000FFFF | ID_NEED_INPUT_FILE;
public static final String ARG_PUSH_ARG_DIRECTORY = "-pushArgDirectory";
public static final int ARG_PUSH_ARG_DIRECTORY_ID = 0x0000FFFE |ID_PERSISTENT_ARG;
public static final String ARG_SET_ARG_DIRECTORY = "-argDirectory:";
public static final int ARG_SET_ARG_DIRECTORY_ID = 0x0000FFFD | ID_NEED_INPUT_FILE|ID_PERSISTENT_ARG;
public static final String ARG_POP_ARG_DIRECTORY = "-popArgDirectory";
public static final int ARG_POP_ARG_DIRECTORY_ID = 0x0000FFFC|ID_PERSISTENT_ARG;
public static final String ARG_SKIP = "-skip:";
public static final int ARG_SKIP_ID = 0x0000FFFB;
File argDirectory;
LinkedList<File> argDirectories;
ArrayList<String> args;
int curArgIndex = 0;
Arg curArg = null;
ArgProcessor argProcessor;
LinkedHashSet<ArgSpec> argSpecs;
File inputFile = null;
File outputFile = null;
ArrayList<File> argFiles = new ArrayList<File>();
Throwable throwable;
boolean allowUnprocessedArgs;
void init(File argDirectory, String args[], ArgSpec[] argSpecs, ArgProcessor argProcessor, boolean allowUnprocessedArgs){
argDirectories=new LinkedList<File>();
this.allowUnprocessedArgs=allowUnprocessedArgs;
if(null!=argDirectory)
this.argDirectory=argDirectory;
else{
File temp=new File("a");
System.out.println(temp.getAbsolutePath());
this.argDirectory=temp.getParentFile();
}
if(null!=argProcessor)
this.argProcessor=argProcessor;
else
this.argProcessor=new defaultArgProcessor();
if(null!=args)
setArgs(args);
if(null!=argSpecs){
this.argSpecs=ACommandLineUtilities.addArgFileArgSpecs(argSpecs);
checkArgs();
}else{
this.argSpecs=ACommandLineUtilities.getArgFileArgSpecs();
}
}
@Override
public ACommandLineUtilities clone() {
ACommandLineUtilities copy=new ACommandLineUtilities(this);
return copy;
}
public ACommandLineUtilities(ACommandLineUtilities toCopy){
this.init(toCopy.argDirectory, toCopy.getArgsAsArray(), toCopy.getArgSpecsAsArray(), toCopy.argProcessor, toCopy.allowUnprocessedArgs);
argDirectories=(LinkedList<File>) AListUtilities.fileListDeepCopy(toCopy.argDirectories);
curArgIndex=toCopy.curArgIndex;
curArg = toCopy.curArg;
//ArgProcessor argProcessor;
//LinkedHashSet<ArgSpec> argSpecs;
//File inputFile = null;
//File outputFile = null;
argFiles=(ArrayList<File>) AListUtilities.fileListDeepCopy(toCopy.argFiles);
//throwable
}
public ACommandLineUtilities(String args[]){
this.init(null, args, null, null, false);
}
public ACommandLineUtilities(File argDirectory, String args[], ArgSpec[] argSpecs){
this.init(argDirectory, args, argSpecs, new defaultArgProcessor(), false);
}
public ACommandLineUtilities(File argFile, ArgSpec[] argSpecs, ArgProcessor argProcessor) throws FileNotFoundException, IOException{
args = ACommandLineUtilities.processArgFile(argFile);
this.init(argFile.getParentFile(), null, argSpecs, argProcessor, false);
}
public ACommandLineUtilities(File argDirectory, String args[], ArgSpec[] argSpecs, ArgProcessor argProcessor){
this.init(argDirectory, args, argSpecs, argProcessor, false);
}
public ACommandLineUtilities(File argDirectory, String args[], ArgSpec[] argSpecs, ArgProcessor argProcessor, boolean allowUnprocessedArgs){
this.init(argDirectory, args, argSpecs, argProcessor, allowUnprocessedArgs);
}
public boolean isAllowUnprocessedArgs() {
return allowUnprocessedArgs;
}
public void setAllowUnprocessedArgs(boolean allowUnprocessedArgs) {
this.allowUnprocessedArgs = allowUnprocessedArgs;
}
public ArgProcessor getArgProcessor() {
return argProcessor;
}
public void setArgProcessor(ArgProcessor argProcessor) {
this.argProcessor = argProcessor;
}
public void setArgSpecs(ArgSpec[] argSpecs) {
this.argSpecs=ACommandLineUtilities.addArgFileArgSpecs(argSpecs);
}
public void setArgSpecs(Collection<? extends ArgSpec> argSpecs) {
this.argSpecs=ACommandLineUtilities.addArgFileArgSpecs(argSpecs);
}
public String[] getArgsAsArray() {
String out[]=new String[args.size()];
return args.toArray(out);
}
public File[] getArgDirectoriesAsArray() {
File out[]=new File[argDirectories.size()];
return argDirectories.toArray(out);
}
public ArgSpec[] getArgSpecsAsArray() {
ArgSpec out[]=new ArgSpec[argSpecs.size()];
return argSpecs.toArray(out);
}
public void addArgSpecs(Collection<? extends ArgSpec> argSpecs) {
this.argSpecs.addAll(argSpecs);
}
public void addArgSpecs(ArgSpec[] argSpecs) {
for(int i=0;i<argSpecs.length;i++)
this.argSpecs.add(argSpecs[i]);
}
public ArrayList<String> getArgs() {
return args;
}
public void setArgs(String[] args) {
this.args=new ArrayList<String>();
for(int i=0;i<args.length;i++){
this.args.add(args[i]);
}
}
public void setArgs(Collection<? extends String> args) {
this.args=new ArrayList<String>();
this.args.addAll(args);
}
public Arg getCurArg() {
return curArg;
}
public void setCurArg(Arg curArg) {
this.curArg = curArg;
}
public int getCurArgIndex() {
return curArgIndex;
}
public void setCurArgIndex(int curArgIndex) {
this.curArgIndex = curArgIndex;
}
public File consumeInputFile(){
File out=inputFile;
inputFile=null;
return out;
}
public File consumeOutputFile(){
File out=outputFile;
outputFile=null;
return out;
}
public void reset() {
curArgIndex=0;
curArg=null;
inputFile=null;
outputFile=null;
}
class defaultArgProcessor implements ArgProcessor{
public boolean processArg(ACommandLineUtilities argContext) {
return true;
}
public File getFileFromUser(int argId, boolean isOutputFile) {
return null;
}
public File getOutputFileFromInputFile(int argId, File inputFile) {
return null;
}
}
public void pushArgDirectory(){
argDirectories.push(argDirectory);
}
public void popArgDirectory(){
this.argDirectory=argDirectories.pop();
}
public void setArgDirectory(File argDirectory){
this.argDirectory=argDirectory;
}
public File getArgDirectory(){
return argDirectory;
}
public File getFileFromCurArgValue(){
File f = new File(curArg.value);
if(false==f.isAbsolute()){
f=new File(argDirectory, curArg.value);
}
return f;
}
public void processArgs(){
while(processArg()){
//do nothing
}
}
public void processArgs(int nArgs){
for(int i=0;i<nArgs;i++)
processArg();
}
public boolean processArg(){
boolean status=true;
try{
do {
if (curArgIndex >= args.size()) {
if(false==allowUnprocessedArgs){
String detail="";
boolean parametersConsumed = true;
if (null != inputFile) {
parametersConsumed = false;
detail="\nInput file \""+inputFile.getCanonicalPath()+"\" not used";
}
if (null != outputFile) {
parametersConsumed = false;
detail="\nOutput file \""+outputFile.getCanonicalPath()+"\" not used";
}
//TODO: check if all non null entries in args are "persitent" args
if (false==parametersConsumed) {
throw new InvalidCommandLineException("Operation completed but not all arguments have been used"+detail);
}
}
//System.out.println("No more arguments to process, exit.");
return false;
}
//curArg = ACommandLineUtilities.getArg(args, argSpecs, curArgIndex, null);
curArg = getArg(curArgIndex);
if(null!=curArg){
//if(false==curArg.persistent())
// args.set(curArgIndex,null);
break;
}
curArgIndex++;
} while (true);
//System.out.println("DEBUG INFO: this="+this+", curArgIndex="+curArgIndex+" --> "+curArg);
boolean curArgValueIsInputFile = false;
if (0 != (curArg.id & ACommandLineUtilities.ID_NEED_INPUT_FILE)) {
if (null == inputFile) {
if (false == curArg.value.isEmpty()) {
//inputFile = AFileUtilities.newFile(curArg.value);
inputFile=getFileFromCurArgValue();
curArgValueIsInputFile = true;
}
if (null == inputFile) {
inputFile = argProcessor.getFileFromUser(curArg.id, false);
}
if (null == inputFile) {
curArg = new Arg("", ACommandLineUtilities.ARG_SKIP_ID, "0");
} else {
if (inputFile.exists() == false) {
throw new InvalidCommandLineException(new FileNotFoundException("impossible to open " + inputFile.getAbsolutePath()));
}
}
}
}
if (0 != (curArg.id & ACommandLineUtilities.ID_NEED_OUTPUT_FILE)) {
if (null == outputFile) {
if ((false == curArgValueIsInputFile) & (false == curArg.value.isEmpty())) {
outputFile=getFileFromCurArgValue();
} else {
if(null!=inputFile){
outputFile=argProcessor.getOutputFileFromInputFile(curArg.id, inputFile);
//outputFile = new File(inputFile.getCanonicalPath() + "_" + ATimeUtilities.getTimeTagSecond() + ".out");
if ((null!=outputFile) && outputFile.exists()) {
outputFile = null;//ask user
}
}
}
if (null == outputFile) {
outputFile = argProcessor.getFileFromUser(curArg.id, true);
}
if (null == outputFile) {
curArg = new Arg("", ACommandLineUtilities.ARG_SKIP_ID, "0");
}
}
}
switch(curArg.id){
case ARG_ARGFILE_ID:{
ArrayList<String> temp = new ArrayList<String>();
int deltaIndex=0;
args.set(curArgIndex,null);
for (int index = 0; index < args.size(); index++) {
String arg=args.get(index);
if ((null!=arg) && (false == arg.isEmpty())) {
temp.add(arg);
}else{
if(index<curArgIndex)
deltaIndex++;
}
}
String fileName = curArg.value;
File testFile=inputFile;
if (argFiles.contains(testFile)) {
throw new InvalidCommandLineException("Circular reference to file in command line:\n" + fileName + "\nAbsolute path:\n" + testFile.getAbsolutePath());
}
argFiles.add(testFile);
//temp.remove(curArgIndex);
temp.addAll(curArgIndex-deltaIndex,processArgFile(testFile));
args=temp;
curArgIndex=curArgIndex-deltaIndex-1;
inputFile=null;
break;}
case ARG_SET_ARG_DIRECTORY_ID:{
String fileName = curArg.value;
File testFile = new File(fileName);
if(false==testFile.isAbsolute())
testFile=new File(argDirectory, fileName);
setArgDirectory(testFile);
inputFile = null;
break;}
case ARG_PUSH_ARG_DIRECTORY_ID:
pushArgDirectory();
break;
case ARG_POP_ARG_DIRECTORY_ID:
popArgDirectory();
break;
case ARG_SKIP_ID: {
String toSkipStr = curArg.value;
int toSkip;
if (toSkipStr.isEmpty()) {
toSkip = 1;
} else {
toSkip = Integer.parseInt(toSkipStr);
}
for (int i = 0; i < toSkip+1; i++) {
args.set(curArgIndex+i,null);
}
curArgIndex+=toSkip;
break;}
default:
status=argProcessor.processArg(this);
}
//if(status && (false==curArg.persistent()) && (curArgIndex>-1))
// args.set(curArgIndex,null);
} catch (StopRequestFromUserException ex){
throw ex;
} catch(Throwable e){
String msg="Exception \""+e.getClass()+ "\" happened during processing of following argument:\n";
msg+=curArg.toString();
throw new RuntimeException(msg,e);
}
curArgIndex++;
return status;
}
public void consumeCurArg(){
args.set(curArgIndex,null);
}
public void setThrowable(Throwable ex) {
throwable=ex;
}
public void throwIfError() throws Throwable {
if(null!=throwable)
throw throwable;
}
/**
* Indicates if an argument is present in the command line
* @param mark the identifier of the requested argument. for example "-f:"
* @return the index of the argument which has been found or -1 if not found
*/
public int getArgIndex(String mark) {
return getArgIndex(mark, 0);
}
/**
* Indicates if an argument is present in the command line
* @param mark the identifier of the requested argument. for example "-f:"
* @param offset offset from the search will start
* @return the index of the argument which has been found or -1 if not found
*/
public int getArgIndex(String mark, int offset) {
for(int index=0;index<args.size();index++){
String arg=args.get(index);
if(null!=arg){
if (arg.startsWith(mark))
return index;
}
}
return -1;
}
/**
* Return the value of an argument in the command line
* @param mark the identifier of the requested argument. for example "-f:"
* @return the value of the argument or null if not found
*/
public String getArgValue(String mark) {
return getArgValue(mark,null, false);
}
/**
* Return the value of an argument in the command line
* @param mark the identifier of the requested argument. for example "-f:"
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the value of the argument or null if not found
*/
public String getArgValue(String mark, String replacement) {
return getArgValue(mark,replacement,true);
}
public String getArgValue(String mark, String replacement, boolean replace) {
for(int index=0;index<args.size();index++){
String arg=args.get(index);
if(null!=arg){
if (arg.startsWith(mark)){
String out=arg.substring(mark.length());
if(replace)
args.set(index, replacement);
return out;
}
}
}
return null;
}
/**
* Return the value of the argument
* @param mark the identifier of the requested argument. for example "-f:"
* @param index the index of the argument (see <code>getArgIndex</code>)
* @return the value of the argument
*/
public String getArgValue(String mark, int index) {
String arg=args.get(index);
if ((null!=arg) && arg.startsWith(mark)) {
return arg.substring(mark.length());
} else {
throw new RuntimeException("incorrect index or mark");
}
}
/**
* Return the id of the argument at a given index
* @param index the index of the argument
* @return the id of the argument or -1 if not supported
*/
public int getArgId(int index) {
String arg=args.get(index);
if(null!=arg){
for(ArgSpec spec:argSpecs) {
if (arg.startsWith(spec.mark))
return spec.id;
}
}
return -1;
}
/**
* Return the id of the argument at a given index
* @param index the index of the argument
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the id of the argument or -1 if not supported
*/
public int getArgId(int index, String replacement) {
String arg=args.get(index);
if(null!=arg){
for(ArgSpec spec:argSpecs) {
if (arg.startsWith(spec.mark)){
args.set(index, replacement);
return spec.id;
}
}
}
return -1;
}
/**
* Return the argument at a given index
* @param index the index of the argument in args
* @return the argument or null if not supported
*/
public Arg getArg(int index) {
return getArg(index, null, false);
}
/**
* Return the argument at a given index
* @param index the index of the argument in args
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the argument or null if not supported
*/
public Arg getArg(int index, String replacement) {
return getArg(index, replacement, true);
}
/**
* Return the argument at a given index
* @param index the index of the argument in args
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @param replace indicate if the arg should be replaced or left as is
* @return the argument or null if not supported
*/
Arg getArg(int index, String replacement, boolean replace) {
String arg=args.get(index);
if(null!=arg){
for(ArgSpec spec:argSpecs){
if (arg.startsWith(spec.mark)){
String mark=spec.mark;
int id=spec.id;
String value=arg.substring(spec.mark.length());
if(replace)
args.set(index,replacement);
return new Arg(mark, id, value);
}
}
}
return null;
}
/**
* Return the value of all occurences of a given argument
* @param mark the mark of the desired argument
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return a list of values
*/
public List<String> getArgValues(String mark, String replacement) {
List<String> out=new LinkedList<String>();
for(int index=0;index<args.size();index++){
String arg=args.get(index);
if ((null!=arg) && (arg.startsWith(mark))){
out.add(arg.substring(mark.length()));
args.set(index,replacement);
}
}
return out;
}
/**
* Check command line argument specification
* @throws IllegalArgumentException
* @see <code>ArgSpec</code>
*/
public void checkArgs() throws IllegalArgumentException {
checkArgs(curArgIndex, args.size(), allowUnprocessedArgs);
}
public void checkArgs(int nArgs) throws IllegalArgumentException {
checkArgs(curArgIndex, nArgs, allowUnprocessedArgs);
}
public void checkArgs(int offset, int nArgs) throws IllegalArgumentException {
checkArgs(offset, nArgs, allowUnprocessedArgs);
}
public int countValidArgs(){
return checkArgs(0, args.size(),true);
}
protected int checkArgs(int offset, int nArgs, boolean allowUnprocessedArgs) throws IllegalArgumentException {
int nValid=0;
List<String> argsToCheck=args.subList(offset, offset+nArgs);
boolean valid[] = new boolean[argsToCheck.size()];
for(ArgSpec spec:argSpecs) {
int count = 0;
for(int index=0;index<argsToCheck.size();index++) {
String arg=argsToCheck.get(index);
if ((null!=arg) && (arg.startsWith(spec.mark))) {
count++;
valid[index] = true;
}
}
if (0 == count) {
if (false == spec.optional) {
throw new RuntimeException("command line argument " + spec.mark + "is missing.");
}
}else{
if(ArgSpec.NO_OCCURENCE==spec.occurenceSpec)
throw new RuntimeException("command line argument " + spec.mark + "is not supported.");
}
if (spec.strictOccurenceSpec) {
if (spec.occurenceSpec != count) {
throw new RuntimeException("command line argument " + spec.mark + "must appear exactly " + spec.occurenceSpec + " times.\n" + "It has been found " + count + " times.");
}
} else {
if(ArgSpec.UNLIMITED_OCCURENCE!=spec.occurenceSpec){
if (spec.occurenceSpec < count) {
throw new RuntimeException("command line argument " + spec.mark + "must appear at most " + spec.occurenceSpec + " times." + "It has been found " + count + " times.");
}
}
}
}
for(int index=0;index<argsToCheck.size();index++) {
if (false == valid[index]) {
if(null!=argsToCheck.get(index)){
if(false==allowUnprocessedArgs)
throw new IllegalArgumentException("argument " + (offset+index) + " is not recognized: "+argsToCheck.get(index));
}else
nValid++;
}else
nValid++;
}
return nValid;
}
/**
* Indicates if an argument is present or not in the command line
* @param mark the identifier of the requested argument.
* @return true if mark is found in args
*/
public boolean hasArg(String mark) {
if (getArgValue(mark) != null) {
return true;
}
return false;
}
/**
* Indicates if an argument is present or not in the command line
* @param mark the identifier of the requested argument.
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return true if mark is found in args (and has been replaced by replacement)
*/
public boolean hasArg(String mark, String replacement) {
int i=getArgIndex(mark);
if (i != -1) {
args.set(i, replacement);
return true;
}
return false;
}
/*public void markCurArgProcessed(){
args.set(curArgIndex, null);
}*/
public interface ArgProcessor{
/**
* inspect and eventually process the argument return by argContext.getCurArg()
* if it process the argument, it should invoke argContext.consumeCurArg();
* @param argContext
* @return true if the argument was recognized by this ArgProcessor (but not necessarily processed yet)
*/
public boolean processArg(ACommandLineUtilities argContext);
/**
* When an argument specify that it requires an input and/or an output file, if no parameter is provided to
* it, the argContext object invoke this method to set the inputFile and/or outputFile
* This happens before calling processArg
* @param argId
* @param isOutputFile
* @return File selected by user
*/
public File getFileFromUser(int argId, boolean isOutputFile) throws IOException;
/**
* When an argument specify that it requires an output file, if no parameter is provided to
* it and inputFile is set, the argContext object invoke this method to set the outputFile
* This happens before calling processArg.
* If this method returns null, then getFileFromUser is invoked.
* @param argId
* @param inputFile
* @return File selected by user
*/
public File getOutputFileFromInputFile(int argId, File inputFile) throws IOException;
}
/*
* Static methods
*/
static public LinkedHashSet<ArgSpec> getArgFileArgSpecs() {
LinkedHashSet<ArgSpec> out = new LinkedHashSet<ArgSpec>();
out.add(new ArgSpec(ARG_ARGFILE, ARG_ARGFILE_ID, ArgSpec.UNLIMITED_OCCURENCE));
out.add(new ArgSpec(ARG_PUSH_ARG_DIRECTORY, ARG_PUSH_ARG_DIRECTORY_ID, ArgSpec.UNLIMITED_OCCURENCE));
out.add(new ArgSpec(ARG_SET_ARG_DIRECTORY, ARG_SET_ARG_DIRECTORY_ID, ArgSpec.UNLIMITED_OCCURENCE));
out.add(new ArgSpec(ARG_POP_ARG_DIRECTORY, ARG_POP_ARG_DIRECTORY_ID, ArgSpec.UNLIMITED_OCCURENCE));
out.add(new ArgSpec(ARG_SKIP, ARG_SKIP_ID, ArgSpec.UNLIMITED_OCCURENCE));
return out;
}
static public LinkedHashSet<ArgSpec> addArgFileArgSpecs(Collection<? extends ArgSpec> argSpecs) {
LinkedHashSet<ArgSpec> out=getArgFileArgSpecs();
out.addAll(argSpecs);
return out;
}
static public LinkedHashSet<ArgSpec> addArgFileArgSpecs(ArgSpec[] argSpecs) {
LinkedHashSet<ArgSpec> out=getArgFileArgSpecs();
for(int i=0;i<argSpecs.length;i++)
out.add(argSpecs[i]);
return out;
}
static public class Arg implements Serializable{
static final long serialVersionUID = 7269042090249856383L;
final public String mark;
final public int id;
final public String value;
public Arg(String mark, int id, String value) {
this.mark = mark;
this.id=id;
this.value=value;
}
public Arg(String mark, int id) {
this.mark = mark;
this.id=id;
this.value=null;
}
public boolean needInputFile(){
if(0 != (id & ID_NEED_INPUT_FILE))
return true;
return false;
}
public boolean needOutputFile(){
if(0 != (id & ID_NEED_OUTPUT_FILE))
return true;
return false;
}
public boolean persistent(){
if(0 != (id & ID_PERSISTENT_ARG))
return true;
return false;
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append("Arg id=0x");
sb.append(Integer.toHexString(id));
sb.append(": \"");
sb.append(mark);
sb.append(value);
sb.append("\"");
return sb.toString();
}
}
/**
* Dump the arguments passed in command line
* @param stream the destination stream, typicaly System.out
* @param args the argument list
*/
public static void dispArgs(PrintStream stream, String[] args) {
if (args.length == 0) {
stream.println("No argument found in command line.");
} else {
stream.print(args.length + " argument");
if (args.length > 1) {
stream.print("s");
}
stream.println(" found in command line:");
for (int i = 0; i < args.length; i++) {
stream.println("\targs[" + i + "] " + args[i]);
}
}
stream.println();
}
/**
* Dump the arguments passed in command line
* @param args the argument list
*/
public static void dispArgs(String[] args) {
dispArgs(System.out, args);
}
/**
* Indicates if an argument is present in the command line
* @param args command line arg list
* @param mark the identifier of the requested argument. for example "-f:"
* @return the index of the argument which has been found or -1 if not found
*/
public static int getArgIndex(String[] args, String mark) {
return getArgIndex(args, mark, 0);
}
/**
* Indicates if an argument is present in the command line
* @param args command line arg list
* @param mark the identifier of the requested argument. for example "-f:"
* @param index offset from the search will start
* @return the index of the argument which has been found or -1 if not found
*/
public static int getArgIndex(String[] args, String mark, int index) {
for (int i = index; i < args.length; i++) {
if(null!=args[i]){
if (args[i].startsWith(mark))
return i;
}
}
return -1;
}
/**
* Return the value of an argument in the command line
* @param args command line arg list
* @param mark the identifier of the requested argument. for example "-f:"
* @return the value of the argument or null if not found
*/
public static String getArgValue(String[] args, String mark) {
return getArgValue(args,mark,null, false);
}
/**
* Return the value of an argument in the command line
* @param args command line arg list
* @param mark the identifier of the requested argument. for example "-f:"
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the value of the argument or null if not found
*/
public static String getArgValue(String[] args, String mark, String replacement) {
return getArgValue(args,mark,replacement,true);
}
public static String getArgValue(String[] args, String mark, String replacement, boolean replace) {
for (int i = 0; i < args.length; i++) {
if(null!=args[i]){
if (args[i].startsWith(mark)){
String out=getArgValue(args, mark, i);
if(replace)
args[i]=replacement;
return out;
}
}
}
return null;
}
/**
* Return the value of the argument
* @param args command line arg list
* @param mark the identifier of the requested argument. for example "-f:"
* @param index the index of the argument (see <code>getArgIndex</code>)
* @return the value of the argument
*/
public static String getArgValue(String[] args, String mark, int index) {
if (args[index].startsWith(mark)) {
return args[index].substring(mark.length());
} else {
throw new RuntimeException("incorrect index or mark");
}
}
/**
* Return the id of the argument at a given index
* @param index the index of the argument
* @return the id of the argument or -1 if not supported
*/
public static int getArgId(List<? extends String> args, Collection<? extends ArgSpec> argSpecs, int index) {
String arg=args.get(index);
if(null!=arg){
for(ArgSpec spec:argSpecs) {
if (arg.startsWith(spec.mark))
return spec.id;
}
}
return -1;
}
/**
* Return the id of the argument at a given index
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param index the index of the argument
* @return the id of the argument or -1 if not supported
*/
public static int getArgId(String[] args, ArgSpec[] argSpec, int index) {
for (int i = 0; i < argSpec.length; i++) {
if(null!=args[index]){
if (args[index].startsWith(argSpec[i].mark))
return argSpec[i].id;
}
}
return -1;
}
/**
* Return the id of the argument at a given index
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param index the index of the argument
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the id of the argument or -1 if not supported
*/
public static int getArgId(String[] args, ArgSpec[] argSpec, int index, String replacement) {
for (int i = 0; i < argSpec.length; i++) {
if(null!=args[index]){
if (args[index].startsWith(argSpec[i].mark)){
args[index]=replacement;
return argSpec[i].id;
}
}
}
return -1;
}
/**
* Return the argument at a given index
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param index the index of the argument in args
* @return the argument or null if not supported
*/
public static Arg getArg(String[] args, ArgSpec[] argSpec, int index) {
return getArg(args,argSpec, index, null, false);
}
/**
* Return the argument at a given index
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param index the index of the argument in args
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return the argument or null if not supported
*/
public static Arg getArg(String[] args, ArgSpec[] argSpec, int index, String replacement) {
return getArg(args,argSpec, index, replacement, true);
}
/**
* Return the argument at a given index
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param index the index of the argument in args
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @param replace indicate if the arg should be replaced or left as is
* @return the argument or null if not supported
*/
static Arg getArg(String[] args, ArgSpec[] argSpec, int index, String replacement, boolean replace) {
for (int i = 0; i < argSpec.length; i++) {
if(null!=args[index]){
if (args[index].startsWith(argSpec[i].mark)){
String mark=argSpec[i].mark;
int id=argSpec[i].id;
String value=args[index].substring(argSpec[i].mark.length());
if(replace)
args[index]=replacement;
return new Arg(mark, id, value);
}
}
}
return null;
}
/**
* Return the value of all occurences of a given argument
* @param args command line arg list
* @param argSpec the specification of supported arguments
* @param mark the mark of the desired argument
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return a list of values
*/
public static List<String> getArgValues(String[] args, ArgSpec[] argSpec, String mark, String replacement) {
List<String> out=new LinkedList<String>();
for(int i=0;i<args.length;i++){
if ((null!=args[i]) && (args[i].startsWith(mark))){
out.add(args[i].substring(mark.length()));
args[i]=replacement;
}
}
return out;
}
/**
* Check command line argument specification
* @param args the command line arguments, after expansion of arg files if supported
* @param argSpec the specification of supported arguments
* @throws IllegalArgumentException
* @see <code>ArgSpec</code>
*/
public static void checkArgs(String[] args, ArgSpec[] argSpec) throws IllegalArgumentException {
boolean valid[] = new boolean[args.length];
for (int i = 0; i < argSpec.length; i++) {
int count = 0;
for (int j = 0; j < args.length; j++) {
if ((null!=args[j]) && (args[j].startsWith(argSpec[i].mark))) {
count++;
valid[j] = true;
}
}
if (0 == count) {
if (false == argSpec[i].optional) {
throw new RuntimeException("command line argument " + argSpec[i].mark + "is missing.");
}
}else{
if(ArgSpec.NO_OCCURENCE==argSpec[i].occurenceSpec)
throw new RuntimeException("command line argument " + argSpec[i].mark + "is not supported.");
}
if (argSpec[i].strictOccurenceSpec) {
if (argSpec[i].occurenceSpec != count) {
throw new RuntimeException("command line argument " + argSpec[i].mark + "must appear exactly " + argSpec[i].occurenceSpec + " times.\n" + "It has been found " + count + " times.");
}
} else {
if(ArgSpec.UNLIMITED_OCCURENCE!=argSpec[i].occurenceSpec){
if (argSpec[i].occurenceSpec < count) {
throw new RuntimeException("command line argument " + argSpec[i].mark + "must appear at most " + argSpec[i].occurenceSpec + " times." + "It has been found " + count + " times.");
}
}
}
}
for (int j = 0; j < args.length; j++) {
if (false == valid[j]) {
if(null!=args[j])
throw new IllegalArgumentException("argument " + j + " is not recognized: "+args[j]);
}
}
}
/**
* Indicates if an argument is present or not in the command line
* @param args the command line arguments, after expansion of arg files if supported
* @param mark the identifier of the requested argument.
* @return true if mark is found in args
*/
public static boolean hasArg(String[] args, String mark) {
if (getArgValue(args, mark) != null) {
return true;
}
return false;
}
/**
* Indicates if an argument is present or not in the command line
* @param args the command line arguments, after expansion of arg files if supported
* @param mark the identifier of the requested argument.
* @param replacement a value to write in place of the argument (if not found, no replacement occurs)
* @return true if mark is found in args (and has been replaced by replacement)
*/
public static boolean hasArg(String[] args, String mark, String replacement) {
int i=getArgIndex(args, mark);
if (i != -1) {
args[i]=replacement;
return true;
}
return false;
}
/**
* Read an argfile
* @param fileName
* @return the arg list contain in the argfile
* @throws FileNotFoundException
* @throws IOException
*/
public static ArrayList<String> processArgFile(String fileName) throws FileNotFoundException, IOException {
File argFile = new File(fileName);
return processArgFile(argFile);
}
public static ArrayList<String> processArgFile(File argFile) throws FileNotFoundException, IOException {
ArrayList<String> out = new ArrayList<String>();
//File argFile = AFileUtilities.newFile(fileName);
argFile=argFile.getCanonicalFile();
FileInputStream argStream = null;
try {
argStream = new FileInputStream(argFile);
} catch (FileNotFoundException e) {
throw new FileNotFoundException(argFile.getCanonicalPath() + "\n" + e.getMessage());
}
try{
BufferedReader argReader = new BufferedReader(new InputStreamReader(argStream, "UTF-8"));
String argLine = argReader.readLine();
while (null != argLine) {
if (false == argLine.isEmpty()) {
out.add(argLine);
}
argLine = argReader.readLine();
}
argReader.close();
if(false==out.isEmpty()){
//processSkipArgs(out);
ArrayList<String> temp = new ArrayList<String>();
temp.add(ARG_PUSH_ARG_DIRECTORY);
File parent=argFile.getParentFile();
String parentPath=ARG_SET_ARG_DIRECTORY+parent.getCanonicalPath();
temp.add(parentPath);
temp.addAll(out);
temp.add(ARG_POP_ARG_DIRECTORY);
out=temp;
}
}finally{
argStream.close();
}
return out;
}
public static void processSkipArgs(List<String> args){
int toSkip=0;
for(int i=0;i<args.size();i++){
if(null!=args.get(i)){
if (args.get(i).startsWith(ARG_SKIP)){
toSkip=Integer.decode(args.get(i).substring(ARG_SKIP.length()));
args.set(i, null);
}
}
for(;toSkip>0;toSkip--){
args.set(++i, null);
}
}
}
public static void processSkipArgs(String[] args){
int toSkip=0;
for(int i=0;i<args.length;i++){
if(null!=args[i]){
if (args[i].startsWith(ARG_SKIP)){
toSkip=Integer.decode(args[i].substring(ARG_SKIP.length()));
args[i]=null;
}
}
for(;toSkip>0;toSkip--){
args[++i]=null;
}
}
}
/**
* Expand command line when it includes "arg files" reference.
* This method also process the <code>ARG_SKIP</code> arguments.
* "arg files" are simple text files which contain one argument at each line, they are UTF-8 encoded.
* an "arg file" may reference another one but circular reference are forbidden since it would create an infinite loop.
* Each time an "arg file" argument is found, it is replaced by the content of the referenced file
* @param argFileDirectory directory to use as base when an arg file is indicated using relative path
* @param args the command line arguments
* @return the command line after "arg files" expansion. ("arg files" argument and empty ones are removed)
* @throws FileNotFoundException
* @throws IOException
*/
public static String[] processArgFile(File argFileDirectory,String[] args) throws FileNotFoundException, IOException {
ArrayList<File> argFiles = new ArrayList<File>();
//processSkipArgs(args);
ArrayList<String> temp = new ArrayList<String>();
for (int i = 0; i < args.length; i++) {
if (false == args[i].isEmpty()) {
temp.add(args[i]);
}
}
ACommandLineUtilities directoryContext=new ACommandLineUtilities(argFileDirectory,null,null, null);
int argFileIndex=0;
while(temp.size()>argFileIndex){
switch(getArgId(temp, getArgFileArgSpecs(), argFileIndex)){
case ARG_ARGFILE_ID:{
String fileName = getArgValue(temp.toArray(args), ARG_ARGFILE, argFileIndex);
File testFile = new File(fileName);
if(false==testFile.isAbsolute())
testFile=new File(directoryContext.argDirectory, fileName);
if (argFiles.contains(testFile)) {
throw new IllegalArgumentException("Circular reference to file in command line:\n" + fileName + "\nAbsolute path:\n" + testFile.getAbsolutePath());
}
argFiles.add(testFile);
temp.remove(argFileIndex);
temp.addAll(argFileIndex,processArgFile(testFile));
argFileIndex--;
break;}
case ARG_SET_ARG_DIRECTORY_ID:{
String fileName = getArgValue(temp.toArray(args), ARG_SET_ARG_DIRECTORY, argFileIndex);
File testFile = new File(fileName);
if(false==testFile.isAbsolute())
testFile=new File(directoryContext.argDirectory, fileName);
directoryContext.setArgDirectory(testFile);
break;}
case ARG_PUSH_ARG_DIRECTORY_ID:
directoryContext.pushArgDirectory();
break;
case ARG_POP_ARG_DIRECTORY_ID:
directoryContext.popArgDirectory();
break;
case ACommandLineUtilities.ARG_SKIP_ID: {
String toSkipStr = getArgValue(temp.toArray(args), ARG_SKIP, argFileIndex);
int toSkip;
if (toSkipStr.isEmpty()) {
toSkip = 0;
} else {
toSkip = Integer.parseInt(toSkipStr);
}
for (int i = 0; i < toSkip+1; i++) {
temp.set(argFileIndex+i,null);
}
break;}
}
argFileIndex++;
}
return temp.toArray(args);
}
}