java/rozsirene-atributy/src/cz/frantovo/rozsireneatributy/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Fri, 15 Dec 2023 01:36:17 +0100
branchv_0
changeset 31 1ab5ce94a146
permissions -rw-r--r--
konfigurace, parser CLI parametrů
     1 /**
     2  * Rozšířené atributy – program na správu rozšířených atributů souborů
     3  * Copyright © 2023 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  */
    17 package cz.frantovo.rozsireneatributy;
    18 
    19 import cz.frantovo.rozsireneatributy.Konfigurace.DefiniceAtributu;
    20 import cz.frantovo.rozsireneatributy.Konfigurace.DefiniceHodnoty;
    21 import java.io.File;
    22 import java.util.Arrays;
    23 import java.util.Collection;
    24 import java.util.ResourceBundle;
    25 
    26 /**
    27  * Converts command line arguments from String array to object. Checks basic
    28  * constraints (if only supported options are used and if they have correct
    29  * number of parameters)
    30  *
    31  * @author Ing. František Kučera (frantovo.cz)
    32  */
    33 public class CLIParser {
    34 
    35 	private static final ResourceBundle překlady = ResourceBundle
    36 		.getBundle(Atribut.class.getPackageName() + ".Překlady");
    37 
    38 	public Konfigurace parsujParametry(String[] parametry)
    39 		throws CLIParserException {
    40 		Konfigurace k = new Konfigurace();
    41 
    42 		for (int i = 0; i < parametry.length; i++) {
    43 			String parametr = parametry[i];
    44 
    45 			boolean odpovídá = false;
    46 
    47 			for (Token t : Token.values()) {
    48 				if (t.odpovídá(parametr)) {
    49 					int parsedArgs = t.parsuj(parametry, i, k);
    50 					i = i + parsedArgs;
    51 					odpovídá = true;
    52 				}
    53 			}
    54 
    55 			if (!odpovídá) {
    56 				throw new CLIParserException(
    57 					překlady.getString("chyba.cli.neznámýParametr") + parametr);
    58 			}
    59 		}
    60 
    61 		if (k.getSoubor() == null)
    62 			throw new CLIParserException(
    63 					překlady.getString("chyba.cli.chybíSoubor"));
    64 		
    65 		return k;
    66 	}
    67 
    68 	private static String načtiDalší(String[] parametry, int index)
    69 		throws CLIParserException {
    70 		if (index < parametry.length) {
    71 			return parametry[index];
    72 		} else {
    73 			throw new CLIParserException("Expecting value for option: "
    74 				+ parametry[index - 1]);
    75 		}
    76 	}
    77 
    78 	private static boolean načtiDalšíBoolean(String[] parametry, int index)
    79 		throws CLIParserException {
    80 		String s = načtiDalší(parametry, index);
    81 		switch (s) {
    82 			case "true":
    83 			case "ano":
    84 				return true;
    85 			case "false":
    86 			case "ne":
    87 				return false;
    88 			default:
    89 				throw new CLIParserException("Neplatná logická hodnota: " + s);
    90 		}
    91 	}
    92 
    93 	private static enum Token {
    94 
    95 		SOUBOR("--soubor", "--file") {
    96 			@Override
    97 			public int parsuj(String[] parametry, int index, Konfigurace k)
    98 				throws CLIParserException {
    99 				int originalIndex = index;
   100 				k.setSoubor(new File(načtiDalší(parametry, ++index)));
   101 				return index - originalIndex;
   102 			}
   103 		},
   104 		POVINNÉ_ZAMYKÁNÍ("--povinné-zamykání", "--mandatory-locking") {
   105 			@Override
   106 			public int parsuj(String[] parametry, int index, Konfigurace k)
   107 				throws CLIParserException {
   108 				int originalIndex = index;
   109 				k.setPovinnéZamykání(načtiDalšíBoolean(parametry, ++index));
   110 				return index - originalIndex;
   111 			}
   112 		},
   113 		DEFINICE_ATRIBUTU("--definice-atributu", "--attribute-definition") {
   114 			@Override
   115 			public int parsuj(String[] parametry, int index, Konfigurace k)
   116 				throws CLIParserException {
   117 				int originalIndex = index;
   118 				String název = načtiDalší(parametry, ++index);
   119 				String popis = načtiDalší(parametry, ++index);
   120 				k.addAtribut(new DefiniceAtributu(název, popis));
   121 				return index - originalIndex;
   122 			}
   123 		},
   124 		HODNOTA_ATRIBUTU("--hodnota", "--value") {
   125 			@Override
   126 			public int parsuj(String[] parametry, int index, Konfigurace k)
   127 				throws CLIParserException {
   128 				int originalIndex = index;
   129 				String hodnota = načtiDalší(parametry, ++index);
   130 				String popis = načtiDalší(parametry, ++index);
   131 
   132 				if (k.getAtributy().isEmpty())
   133 					throw new CLIParserException(
   134 						překlady.getString("chyba.cli.chybíDefiniceAtributu"));
   135 
   136 				k.getAtributy()
   137 					.get(k.getAtributy().size() - 1)
   138 					.addHodnota(new DefiniceHodnoty(hodnota, popis));
   139 
   140 				return index - originalIndex;
   141 			}
   142 		};
   143 
   144 		private final Collection<String> parametry;
   145 
   146 		private Token(String... parametry) {
   147 			this.parametry = Arrays.asList(parametry);
   148 		}
   149 
   150 		/**
   151 		 * @param parametr e.g. „--input-file“
   152 		 * @return whether option is this token
   153 		 */
   154 		public boolean odpovídá(String parametr) {
   155 			return parametry.contains(parametr);
   156 		}
   157 
   158 		/**
   159 		 * Parse String arguments and fill values into the options object.
   160 		 *
   161 		 * @param parametry CLI arguments
   162 		 * @param index index of the option matched by this token, like
   163 		 * „--input-file“
   164 		 * @param k object to be filled
   165 		 * @return number of parsed arguments – if option has no arguments (just
   166 		 * boolean flag), return 0, otherwise return positive integer: number of
   167 		 * eaten arguments.
   168 		 * @throws CLIParserException
   169 		 */
   170 		public abstract int parsuj(String[] parametry, int index, Konfigurace k)
   171 			throws CLIParserException;
   172 	}
   173 }