| 6 | 1 /** | 
|  | 2  * | 
|  | 3  * Copyright INRA-URGI 2009-2010 | 
|  | 4  * | 
|  | 5  * This software is governed by the CeCILL license under French law and | 
|  | 6  * abiding by the rules of distribution of free software. You can use, | 
|  | 7  * modify and/ or redistribute the software under the terms of the CeCILL | 
|  | 8  * license as circulated by CEA, CNRS and INRIA at the following URL | 
|  | 9  * "http://www.cecill.info". | 
|  | 10  * | 
|  | 11  * As a counterpart to the access to the source code and rights to copy, | 
|  | 12  * modify and redistribute granted by the license, users are provided only | 
|  | 13  * with a limited warranty and the software's author, the holder of the | 
|  | 14  * economic rights, and the successive licensors have only limited | 
|  | 15  * liability. | 
|  | 16  * | 
|  | 17  * In this respect, the user's attention is drawn to the risks associated | 
|  | 18  * with loading, using, modifying and/or developing or reproducing the | 
|  | 19  * software by the user in light of its specific status of free software, | 
|  | 20  * that may mean that it is complicated to manipulate, and that also | 
|  | 21  * therefore means that it is reserved for developers and experienced | 
|  | 22  * professionals having in-depth computer knowledge. Users are therefore | 
|  | 23  * encouraged to load and test the software's suitability as regards their | 
|  | 24  * requirements in conditions enabling the security of their systems and/or | 
|  | 25  * data to be ensured and, more generally, to use and operate it in the | 
|  | 26  * same conditions as regards security. | 
|  | 27  * | 
|  | 28  * The fact that you are presently reading this means that you have had | 
|  | 29  * knowledge of the CeCILL license and that you accept its terms. | 
|  | 30  * | 
|  | 31  */ | 
|  | 32 import java.util.*; | 
|  | 33 import java.io.File; | 
|  | 34 import java.io.*; | 
|  | 35 import java.util.regex.*; | 
|  | 36 | 
|  | 37 public class PythonHelperReader { | 
|  | 38 | 
|  | 39   String         fileName; | 
|  | 40   Program        program; | 
|  | 41   BufferedReader reader; | 
|  | 42   String         message; | 
|  | 43 | 
|  | 44   public PythonHelperReader(String fileName) { | 
|  | 45     this.fileName = fileName; | 
|  | 46     this.reader   = reader; | 
|  | 47     this.message  = null; | 
|  | 48   } | 
|  | 49 | 
|  | 50   public void setReader(BufferedReader reader) { | 
|  | 51     this.reader = reader; | 
|  | 52   } | 
|  | 53 | 
|  | 54   public void run() { | 
|  | 55     this.program                     = new Program(); | 
|  | 56     boolean         inBeginning      = true; | 
|  | 57     boolean         inUsage          = false; | 
|  | 58     boolean         afterUsage       = false; | 
|  | 59     boolean         inDescription    = false; | 
|  | 60     boolean         afterDescription = false; | 
|  | 61     boolean         inOptions        = false; | 
|  | 62     boolean         inOptionBlank    = false; | 
|  | 63     boolean         inError          = false; | 
|  | 64     String          usage            = null; | 
|  | 65     String          description      = null; | 
|  | 66     String          option           = null; | 
|  | 67     Vector <String> options          = new Vector < String > (); | 
|  | 68     String[]        optionSplitted; | 
|  | 69 | 
|  | 70     // Parse file | 
|  | 71     try { | 
|  | 72       String line = null; | 
|  | 73 | 
|  | 74       while ((line = reader.readLine()) != null) { | 
|  | 75         line = line.trim(); | 
|  | 76         if (line.startsWith("Traceback")) { | 
|  | 77           this.message     = "Problem with header of '" + this.fileName + "':\n" + line + "\n"; | 
|  | 78           inError          = true; | 
|  | 79           inBeginning      = false; | 
|  | 80           inUsage          = false; | 
|  | 81           afterUsage       = false; | 
|  | 82           inDescription    = false; | 
|  | 83           afterDescription = false; | 
|  | 84           inOptions        = false; | 
|  | 85           inOptionBlank    = false; | 
|  | 86         } | 
|  | 87         else if (inError) { | 
|  | 88           this.message += line + "\n"; | 
|  | 89         } | 
|  | 90         else if (inBeginning) { | 
|  | 91           if (line.startsWith("Usage:")) { | 
|  | 92             inUsage     = true; | 
|  | 93             inBeginning = false; | 
|  | 94             usage       = line; | 
|  | 95           } | 
|  | 96         } | 
|  | 97         else if (inUsage) { | 
|  | 98           if ("".equals(line)) { | 
|  | 99             inUsage    = false; | 
|  | 100             afterUsage = true; | 
|  | 101           } | 
|  | 102           else { | 
|  | 103             usage += " " + line; | 
|  | 104           } | 
|  | 105         } | 
|  | 106         else if (afterUsage) { | 
|  | 107           if (! "".equals(line)) { | 
|  | 108             description   = line; | 
|  | 109             afterUsage    = false; | 
|  | 110             inDescription = true; | 
|  | 111           } | 
|  | 112         } | 
|  | 113         else if (inDescription) { | 
|  | 114           if ("".equals(line)) { | 
|  | 115             inDescription    = false; | 
|  | 116             afterDescription = true; | 
|  | 117           } | 
|  | 118           else { | 
|  | 119             description += " " + line; | 
|  | 120           } | 
|  | 121         } | 
|  | 122         else if (afterDescription) { | 
|  | 123           if (! "".equals(line)) { | 
|  | 124             afterDescription = false; | 
|  | 125             inOptions        = true; | 
|  | 126           } | 
|  | 127         } | 
|  | 128         else if (inOptions) { | 
|  | 129           if ("".equals(line)) { | 
|  | 130             inOptions     = false; | 
|  | 131             inOptionBlank = true; | 
|  | 132           } | 
|  | 133           else { | 
|  | 134             if (option == null) { | 
|  | 135               option = line; | 
|  | 136             } | 
|  | 137             else { | 
|  | 138               if (line.charAt(0) == '-') { | 
|  | 139                 options.add(option); | 
|  | 140                 option = line; | 
|  | 141               } | 
|  | 142               else { | 
|  | 143                 option += " " + line; | 
|  | 144               } | 
|  | 145             } | 
|  | 146           } | 
|  | 147         } | 
|  | 148         else if (inOptionBlank) { | 
|  | 149           if (! "".equals(line)) { | 
|  | 150             inOptionBlank = false; | 
|  | 151             inOptions     = true; | 
|  | 152           } | 
|  | 153         } | 
|  | 154         else { | 
|  | 155           this.message = "Something is wrong in the file '" + this.fileName + "'."; | 
|  | 156           return; | 
|  | 157         } | 
|  | 158       } | 
|  | 159 | 
|  | 160       reader.close(); | 
|  | 161     } | 
|  | 162     catch (FileNotFoundException e) { | 
|  | 163       this.message = "File " + this.fileName + " not found"; | 
|  | 164       return; | 
|  | 165     } | 
|  | 166     catch (IOException e) { | 
|  | 167       this.message = "IOException while reading file " + this.fileName; | 
|  | 168       return; | 
|  | 169     } | 
|  | 170 | 
|  | 171     if (inError) { | 
|  | 172       return; | 
|  | 173     } | 
|  | 174 | 
|  | 175     if (option != null) { | 
|  | 176       options.add(option); | 
|  | 177     } | 
|  | 178 | 
|  | 179     HashMap < String, ProgramOption > identifierToOptions = new HashMap < String, ProgramOption > (); | 
|  | 180     HashMap < ProgramOption, String > associatedOption    = new HashMap < ProgramOption, String > (); | 
|  | 181 | 
|  | 182     if (usage == null) { | 
|  | 183       this.message = "Cannot read the usage of file " + this.fileName; | 
|  | 184       return; | 
|  | 185     } | 
|  | 186     program.setShortName(usage.split(" ")[1].trim()); | 
|  | 187     program.setName(description.split(":")[0].trim()); | 
|  | 188 | 
|  | 189     Pattern pattern = Pattern.compile("\\[Category: .*\\]"); | 
|  | 190     Matcher matcher = pattern.matcher(description); | 
|  | 191     if (matcher.find()) { | 
|  | 192       program.setSection(description.substring(matcher.start() + "[Category: ".length(), matcher.end() - 1)); | 
|  | 193       program.setDescription(description.substring(0, matcher.start() - 1).trim()); | 
|  | 194     } | 
|  | 195     else { | 
|  | 196       this.message = "Cannot find category in description '" + description + "' in file " + this.fileName; | 
|  | 197       return; | 
|  | 198     } | 
|  | 199     for (int i = 0; i < options.size(); i++) { | 
|  | 200       option         = options.get(i).replace("\t", " "); | 
|  | 201       optionSplitted = option.split(" "); | 
|  | 202       option         = ""; | 
|  | 203       for (int j = 3; j < optionSplitted.length; j++) { | 
|  | 204         option += optionSplitted[j] + " "; | 
|  | 205       } | 
|  | 206 | 
|  | 207       String identifier = optionSplitted[0].replace("-", "").replace(",", ""); | 
|  | 208       // Skip -h and -v options | 
|  | 209       if (("h".equals(identifier)) || ("v".equals(identifier))) | 
|  | 210         continue; | 
|  | 211 | 
|  | 212       ProgramOption programOption = new ProgramOption(); | 
|  | 213       programOption.setIdentifier("-" + identifier); | 
|  | 214       programOption.setComment(option.substring(0, option.indexOf("[")).trim()); | 
|  | 215       identifierToOptions.put(identifier, programOption); | 
|  | 216 | 
|  | 217       pattern = Pattern.compile("\\[[^\\]]*\\]"); | 
|  | 218       matcher = pattern.matcher(option); | 
|  | 219       while (matcher.find()) { | 
|  | 220         String inner = option.substring(matcher.start()+1, matcher.end()-1); | 
|  | 221         if (inner.contains(":")) { | 
|  | 222           String type  = inner.substring(0, inner.indexOf(":")).trim(); | 
|  | 223           String value = inner.substring(inner.indexOf(":")+1).trim(); | 
|  | 224           // Types of the options | 
|  | 225           if ("format".compareToIgnoreCase(type) == 0) { | 
|  | 226             String currentWord = ""; | 
|  | 227             String rest        = ""; | 
|  | 228             if (value.contains(" ")) { | 
|  | 229               int pos     = value.indexOf(" "); | 
|  | 230               currentWord = value.substring(0, pos); | 
|  | 231               rest        = value.substring(pos+1); | 
|  | 232             } | 
|  | 233             else { | 
|  | 234               currentWord = value; | 
|  | 235             } | 
|  | 236             // Output file type | 
|  | 237             if ("output".compareToIgnoreCase(currentWord) == 0) { | 
|  | 238               programOption.setInput(false); | 
|  | 239               int pos     = rest.indexOf(" "); | 
|  | 240               currentWord = rest.substring(0, pos).trim(); | 
|  | 241               rest        = rest.substring(pos+1).trim(); | 
|  | 242             } | 
|  | 243             // File (input or output file) | 
|  | 244             if ("file".compareToIgnoreCase(currentWord) == 0) { | 
|  | 245               programOption.setType("file"); | 
|  | 246               // Format given by an associated option (to be found later) | 
|  | 247               if (rest.startsWith("in format given by ")) { | 
|  | 248                 associatedOption.put(programOption, rest.substring(rest.indexOf("format given by ") + "format given by ".length() + 1).trim()); | 
|  | 249               } | 
|  | 250               else { | 
|  | 251                 if (! rest.startsWith("in ")) { | 
|  | 252                   this.message = "Descriptor " + option + " does not have a proper format."; | 
|  | 253                   return; | 
|  | 254                 } | 
|  | 255                 rest = rest.substring("in ".length()); | 
|  | 256                 int pos = rest.indexOf(" format"); | 
|  | 257                 if (pos == -1) { | 
|  | 258                   this.message = "Descriptor " + option + " does not have a proper format."; | 
|  | 259                   return; | 
|  | 260                 } | 
|  | 261                 programOption.setFormat(rest.substring(0, pos).trim().toLowerCase().split(" or ")); | 
|  | 262               } | 
|  | 263             } | 
|  | 264             // Format type | 
|  | 265             else if (rest.endsWith("file format")) { | 
|  | 266               programOption.setFormat((currentWord + " " + rest.substring(0, rest.indexOf("file format"))).trim().toLowerCase().split(" or ")); | 
|  | 267               programOption.setType("format"); | 
|  | 268             } | 
|  | 269             // Choice type | 
|  | 270             else if ("choice".compareToIgnoreCase(currentWord) == 0) { | 
|  | 271               programOption.setChoices(rest.replace("(", "").replace(")", "").split(", ")); | 
|  | 272               programOption.setType("choice"); | 
|  | 273             } | 
|  | 274             // Boolean type | 
|  | 275             else if ("bool".compareToIgnoreCase(currentWord) == 0) { | 
|  | 276               programOption.setType("boolean"); | 
|  | 277             } | 
|  | 278             // Other type | 
|  | 279             else { | 
|  | 280               programOption.setType(currentWord); | 
|  | 281             } | 
|  | 282           } | 
|  | 283           // Default value | 
|  | 284           else if ("default".compareToIgnoreCase(type) == 0) { | 
|  | 285             programOption.setDefault(value); | 
|  | 286           } | 
|  | 287           else { | 
|  | 288             this.message = "Do not understand option descriptor '" + inner + "'."; | 
|  | 289             return; | 
|  | 290           } | 
|  | 291         } | 
|  | 292         else { | 
|  | 293           // Compulsory option | 
|  | 294           if ("compulsory".compareToIgnoreCase(inner) == 0) { | 
|  | 295             programOption.setCompulsory(true); | 
|  | 296           } | 
|  | 297           else { | 
|  | 298             this.message = "Do not understand option descriptor '" + inner + "'."; | 
|  | 299             return; | 
|  | 300           } | 
|  | 301         } | 
|  | 302       } | 
|  | 303       program.addOption(programOption); | 
|  | 304     } | 
|  | 305 | 
|  | 306     // Set associated option | 
|  | 307     Iterator it = associatedOption.keySet().iterator(); | 
|  | 308     while (it.hasNext()) { | 
|  | 309       ProgramOption programOption = (ProgramOption) it.next(); | 
|  | 310       programOption.setAssociatedOption(identifierToOptions.get(associatedOption.get(programOption))); | 
|  | 311     } | 
|  | 312   } | 
|  | 313 | 
|  | 314   public String getMessage () { | 
|  | 315     return this.message; | 
|  | 316   } | 
|  | 317 | 
|  | 318   public Program getProgram () { | 
|  | 319     return this.program; | 
|  | 320   } | 
|  | 321 } | 
|  | 322 | 
|  | 323 |