Package com.atolsystems.atolutilities

Source Code of com.atolsystems.atolutilities.ACommandLineUtilities

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);
    }
}
TOP

Related Classes of com.atolsystems.atolutilities.ACommandLineUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.