Index: test/uk/me/parabola/mkgmap/CommandArgsTest.java =================================================================== --- test/uk/me/parabola/mkgmap/CommandArgsTest.java (revision 1035) +++ test/uk/me/parabola/mkgmap/CommandArgsTest.java (working copy) @@ -44,7 +44,7 @@ private static final String FILE3 = "00000003.osm"; private final ArgCollector proc = new ArgCollector(); - private final CommandArgs carg = new CommandArgs(proc); + private final CommandArgsReader carg = new CommandArgsReader(proc); /** * Test that the default mapnames are correct. Should start with 63240001 Index: src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java =================================================================== --- src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java (revision 1035) +++ src/uk/me/parabola/mkgmap/combiners/TdbBuilder.java (working copy) @@ -28,11 +28,12 @@ import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.imgfmt.app.map.Map; import uk.me.parabola.log.Logger; -import uk.me.parabola.mkgmap.CommandArgs; import uk.me.parabola.mkgmap.build.MapBuilder; import uk.me.parabola.mkgmap.general.MapShape; +import uk.me.parabola.mkgmap.CommandArgs; import uk.me.parabola.tdbfmt.DetailMapBlock; import uk.me.parabola.tdbfmt.TdbFile; +import uk.me.parabola.util.EnhancedProperties; /** * Build the TDB file and the overview map. @@ -57,7 +58,6 @@ * * @param args The command line arguments as they are at the end of the list. * In otherwords if the same argument appears more than once, then it will - * have the value that was set last. */ public void init(CommandArgs args) { overviewMapname = args.get("overview-mapname", "63240000"); Index: src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java =================================================================== --- src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java (revision 1035) +++ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java (working copy) @@ -34,6 +34,7 @@ import uk.me.parabola.imgfmt.sys.FileImgChannel; import uk.me.parabola.imgfmt.sys.ImgFS; import uk.me.parabola.log.Logger; +import uk.me.parabola.util.EnhancedProperties; import uk.me.parabola.mkgmap.CommandArgs; /** Index: src/uk/me/parabola/mkgmap/main/Main.java =================================================================== --- src/uk/me/parabola/mkgmap/main/Main.java (revision 1035) +++ src/uk/me/parabola/mkgmap/main/Main.java (working copy) @@ -25,14 +25,20 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import uk.me.parabola.imgfmt.ExitException; import uk.me.parabola.log.Logger; import uk.me.parabola.mkgmap.ArgumentProcessor; import uk.me.parabola.mkgmap.CommandArgs; +import uk.me.parabola.mkgmap.CommandArgsReader; import uk.me.parabola.mkgmap.Version; import uk.me.parabola.mkgmap.combiners.Combiner; import uk.me.parabola.mkgmap.combiners.FileInfo; @@ -67,6 +73,11 @@ private String styleFile = "classpath:styles"; private boolean verbose; + private final List> futures = new LinkedList>(); + private ExecutorService threadPool; + // default number of threads (limited by number of cores available below) + private int maxJobs = 4; + /** * The main program to make or combine maps. We now use a two pass process, * first going through the arguments and make any maps and collect names @@ -87,7 +98,7 @@ try { // Read the command line arguments and process each filename found. - CommandArgs commandArgs = new CommandArgs(mm); + CommandArgsReader commandArgs = new CommandArgsReader(mm); commandArgs.readArgs(args); } catch (ExitException e) { System.err.println(e.getMessage()); @@ -134,6 +145,13 @@ processMap.put("lbl", saver); processMap.put("net", saver); processMap.put("nod", saver); + + // by default, have no more than 1 thread per core + // but this can be overridden with --max-jobs option + int numCores = Runtime.getRuntime().availableProcessors(); + if(maxJobs > numCores) + maxJobs = numCores; + } /** @@ -142,14 +160,25 @@ * @param args The command arguments. * @param filename The filename to process. */ - public void processFilename(CommandArgs args, String filename) { - String ext = extractExtension(filename); + public void processFilename(final CommandArgs args, final String filename) { + final String ext = extractExtension(filename); log.debug("file", filename, ", extension is", ext); - MapProcessor mp = mapMaker(ext); - String output = mp.makeMap(args, filename); - log.debug("adding output name", output); - filenames.add(output); + if (threadPool == null) { + log.info("Creating thread pool with", maxJobs, "threads"); + System.out.println("Creating thread pool with " + maxJobs + " threads"); + threadPool = Executors.newFixedThreadPool(maxJobs); + } + final MapProcessor mp = mapMaker(ext); + + log.info("Submitting job " + filename); + futures.add(threadPool.submit(new Callable() { + public String call() { + String output = mp.makeMap(args, filename); + log.debug("adding output name", output); + return output; + } + })); } private MapProcessor mapMaker(String ext) { @@ -183,6 +212,12 @@ verbose = true; } else if (opt.equals("list-styles")) { listStyles(); + } else if (opt.equals("max-jobs")) { + maxJobs = Integer.parseInt(val); + if(maxJobs < 1) { + log.warn("max-jobs has to be at least 1"); + maxJobs = 1; + } } else if (opt.equals("version")) { System.err.println(Version.VERSION); System.exit(0); @@ -248,9 +283,23 @@ } public void endOptions(CommandArgs args) { + + if (threadPool != null) + threadPool.shutdown(); + for (Future f : futures) { + try { + filenames.add(f.get()); + } catch(Exception e) { + log.error("" + e); + e.printStackTrace(System.err); + } + } + if (combiners.isEmpty()) return; + log.info("Combining maps"); + // Get them all set up. for (Combiner c : combiners) c.init(args); Index: src/uk/me/parabola/mkgmap/main/MapMaker.java =================================================================== --- src/uk/me/parabola/mkgmap/main/MapMaker.java (revision 1035) +++ src/uk/me/parabola/mkgmap/main/MapMaker.java (working copy) @@ -31,6 +31,7 @@ import uk.me.parabola.imgfmt.app.Coord; import uk.me.parabola.imgfmt.app.map.Map; import uk.me.parabola.log.Logger; +import uk.me.parabola.mkgmap.CommandArgsReader; import uk.me.parabola.mkgmap.CommandArgs; import uk.me.parabola.mkgmap.build.MapBuilder; import uk.me.parabola.mkgmap.general.LoadableMapDataSource; @@ -79,6 +80,7 @@ params.setBlockSize(args.getBlockSize()); params.setMapDescription(args.getDescription()); + log.info("Started making", args.getMapname(), "(" + args.getDescription() + ")"); try { Map map = Map.createMap(args.getMapname(), params); setOptions(map, args); @@ -139,7 +141,7 @@ } private void makeAreaPOIs(CommandArgs args, LoadableMapDataSource src) { - String s = args.getProperties().getProperty("add-pois-to-areas"); + String s = args.get("add-pois-to-areas", null); if (s != null) { MapPointFastFindMap poiMap = new MapPointFastFindMap(); @@ -182,7 +184,7 @@ void makeRoadNamePOIS(CommandArgs args, LoadableMapDataSource src) { - String rnp = args.getProperties().getProperty("road-name-pois", null); + String rnp = args.get("road-name-pois", null); // are road name POIS wanted? if(rnp != null) { int rnpt = 0x640a; // Garmin type 'Locale' Index: src/uk/me/parabola/mkgmap/main/MapProcessor.java =================================================================== --- src/uk/me/parabola/mkgmap/main/MapProcessor.java (revision 1035) +++ src/uk/me/parabola/mkgmap/main/MapProcessor.java (working copy) @@ -16,6 +16,7 @@ */ package uk.me.parabola.mkgmap.main; +import uk.me.parabola.mkgmap.CommandArgsReader; import uk.me.parabola.mkgmap.CommandArgs; /** Index: src/uk/me/parabola/mkgmap/CommandArgsReader.java =================================================================== --- src/uk/me/parabola/mkgmap/CommandArgsReader.java (revision 1035) +++ src/uk/me/parabola/mkgmap/CommandArgsReader.java (working copy) @@ -40,25 +40,26 @@ * * @author Steve Ratcliffe */ -public class CommandArgs { - private static final Logger log = Logger.getLogger(CommandArgs.class); +public class CommandArgsReader { + private static final Logger log = Logger.getLogger(CommandArgsReader.class); + private final ArgumentProcessor proc; + + private boolean mapnameWasSet; + private final ArgList arglist = new ArgList(); + private final EnhancedProperties args = new EnhancedProperties(); + { // Set some default values. It is as if these were on the command // line before any user supplied options. - arglist.add(new CommandOption("mapname", "63240001")); - arglist.add(new CommandOption("description", "OSM street map")); - arglist.add(new CommandOption("overview-mapname", "63240000")); + add(new CommandOption("mapname", "63240001")); + add(new CommandOption("description", "OSM street map")); + add(new CommandOption("overview-mapname", "63240000")); } - private final ArgumentProcessor proc; - private final EnhancedProperties currentOptions = new EnhancedProperties(); - - private boolean mapnameWasSet; - - public CommandArgs(ArgumentProcessor proc) { + public CommandArgsReader(ArgumentProcessor proc) { this.proc = proc; } @@ -106,7 +107,7 @@ } else { log.debug("adding filename:", arg); - arglist.add(new Filename(arg)); + add(new Filename(arg)); } } @@ -119,82 +120,11 @@ a.processArg(); } - proc.endOptions(this); + proc.endOptions(new CommandArgs(this.args)); } - public EnhancedProperties getProperties() { - return arglist.getProperties(); - } - public int get(String name, int def) { - return currentOptions.getProperty(name, def); - } - - public String get(String name, String def) { - return currentOptions.getProperty(name, def); - } - - // //// - // There are a number of methods to get specific arguments that follow. - // There are many more options in use however. New code should mostly - // just use the get methods above. - // //// - - public String getDescription() { - return arglist.getProperty("description"); - } - - public int getBlockSize() { - return get("block-size", 512); - } - - public String getMapname() { - return arglist.getProperty("mapname"); - } - - public String getCharset() { - String charset = arglist.getProperty("latin1"); - if (charset != null) - return "latin1"; - - // xcharset is the old value, use charset instead. - charset = arglist.getProperty("charset", arglist.getProperty("xcharset")); - if (charset != null) - return charset; - - int cp = getCodePage(); - if (cp != 0) - return "cp" + cp; - - return "ascii"; - } - - public int getCodePage() { - int cp; - - // xcode-page is the old name - String s = arglist.getProperty("code-page", arglist.getProperty("xcode-page", "0")); - try { - cp = Integer.parseInt(s); - } catch (NumberFormatException e) { - cp = 0; - } - - return cp; - } - - public boolean isForceUpper() { - return arglist.getProperty("lower-case") == null; - } - /** - * Test for the existence of an argument. - */ - public boolean exists(String name) { - return currentOptions.containsKey(name); - } - - /** * Add an option based on the option and value separately. * @param option The option name. * @param value Its value. @@ -231,14 +161,26 @@ if (option.equals("input-file")) { log.debug("adding filename", value); - arglist.add(new Filename(value)); + add(new Filename(value)); } else if (option.equals("read-config")) { readConfigFile(value); } else { - arglist.add(opt); + add(opt); } } + private void add(CommandOption option) { + arglist.add(option); + } + + private void add(Filename filename) { + arglist.add(filename); + } + + public Iterator iterator() { + return arglist.iterator(); + } + /** * Read a config file that contains more options. When the number of * options becomes large it is more convenient to place them in a file. @@ -260,63 +202,18 @@ } /** - * The arguments are held in this list. - */ - private class ArgList implements Iterable { - private final List alist = new ArrayList(); - - private int filenameCount; - - public void add(CommandOption option) { - alist.add(option); - } - - public void add(Filename name) { - filenameCount++; - alist.add(name); - } - - public Iterator iterator() { - return alist.iterator(); - } - - public int getFilenameCount() { - return filenameCount; - } - - public String getProperty(String name) { - return currentOptions.getProperty(name); - } - - public String getProperty(String name, String def) { - String val = currentOptions.getProperty(name); - if (val == null) - val = def; - return val; - } - - public EnhancedProperties getProperties() { - return currentOptions; - } - - public void setProperty(String name, String value) { - currentOptions.setProperty(name, value); - } - } - - /** * Interface that represents an argument type. It provides a method for * the argument to be processed in order. Options can be intersperced with * filenames. The options take effect where they appear. */ - private interface ArgType { + interface ArgType { public abstract void processArg(); } /** * A filename. */ - private class Filename implements ArgType { + class Filename implements ArgType { private final String name; private boolean useFilenameAsMapname = true; @@ -333,15 +230,15 @@ if (useFilenameAsMapname) { mapname = extractMapName(name); if (mapname != null) - arglist.setProperty("mapname", mapname); + args.setProperty("mapname", mapname); } // Now process the file - proc.processFilename(CommandArgs.this, name); + proc.processFilename(new CommandArgs(args), name); // Increase the name number. If the next arg sets it then that // will override this new name. - mapname = arglist.getProperty("mapname"); + mapname = args.getProperty("mapname"); try { Formatter fmt = new Formatter(); try { @@ -350,7 +247,7 @@ } catch (NumberFormatException e) { fmt.format("%8.8s", mapname); } - arglist.setProperty("mapname", fmt.toString()); + args.setProperty("mapname", fmt.toString()); } catch (NumberFormatException e) { // If the name is not a number then we just leave it alone... } @@ -373,7 +270,7 @@ /** * An option argument. A key value pair. */ - private class CommandOption implements ArgType { + class CommandOption implements ArgType { private final Option option; private CommandOption(Option option) { @@ -385,7 +282,7 @@ } public void processArg() { - currentOptions.setProperty(option.getOption(), option.getValue()); + args.setProperty(option.getOption(), option.getValue()); proc.processOption(option.getOption(), option.getValue()); } @@ -397,5 +294,37 @@ return option.getValue(); } } + /** + * The arguments are held in this list. + */ + class ArgList implements Iterable { + private final List alist; + private int filenameCount; + + ArgList() { + alist = new ArrayList(); + } + + public ArgList(ArgList args) { + alist = new ArrayList(args.alist); + } + + protected void add(CommandArgsReader.CommandOption option) { + alist.add(option); + } + + public void add(CommandArgsReader.Filename name) { + filenameCount++; + alist.add(name); + } + + public Iterator iterator() { + return alist.iterator(); + } + + public int getFilenameCount() { + return filenameCount; + } + } } Index: src/uk/me/parabola/mkgmap/ArgumentProcessor.java =================================================================== --- src/uk/me/parabola/mkgmap/ArgumentProcessor.java (revision 1035) +++ src/uk/me/parabola/mkgmap/ArgumentProcessor.java (working copy) @@ -16,6 +16,8 @@ */ package uk.me.parabola.mkgmap; +import uk.me.parabola.util.EnhancedProperties; + /** * Used to step through each filename that is given to the program. * Index: src/uk/me/parabola/mkgmap/CommandArgs.java =================================================================== --- src/uk/me/parabola/mkgmap/CommandArgs.java (revision 1035) +++ src/uk/me/parabola/mkgmap/CommandArgs.java (working copy) @@ -1,129 +1,20 @@ -/* - * Copyright (C) 2006 Steve Ratcliffe - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * Author: Steve Ratcliffe - * Create date: 01-Jan-2007 - */ package uk.me.parabola.mkgmap; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Formatter; -import java.util.Iterator; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import uk.me.parabola.imgfmt.ExitException; -import uk.me.parabola.log.Logger; import uk.me.parabola.util.EnhancedProperties; -/** - * Command line arguments for Main. Arguments consist of options and filenames. - * You read arguments from left to right and when a filename is encounted - * the file is processed with the options that were in force at the time. - * - * Since it is likely that the number of options will become quite large, you - * can place options in a file. Place the options each on a separate line - * without the initial '--'. - * - * @author Steve Ratcliffe - */ public class CommandArgs { - private static final Logger log = Logger.getLogger(CommandArgs.class); + private final EnhancedProperties currentOptions; - private final ArgList arglist = new ArgList(); - - { - // Set some default values. It is as if these were on the command - // line before any user supplied options. - arglist.add(new CommandOption("mapname", "63240001")); - arglist.add(new CommandOption("description", "OSM street map")); - arglist.add(new CommandOption("overview-mapname", "63240000")); + public CommandArgs() { + currentOptions = new EnhancedProperties(); } - private final ArgumentProcessor proc; - private final EnhancedProperties currentOptions = new EnhancedProperties(); - - private boolean mapnameWasSet; - - public CommandArgs(ArgumentProcessor proc) { - this.proc = proc; + public CommandArgs(EnhancedProperties args) { + currentOptions = new EnhancedProperties(args); } - /** - * Read and interpret the command line arguments. Most have a double hyphen - * preceeding them and these work just the same if they are in a config - * file. - *

- * There are a few options that consist of a single hyphen followed by a - * single letter that are short cuts for a long option. - *

- * The -c option is special. It is followed by the name of a file in which - * there are further command line options. Any option on the command line - * that comes after the -c option will override the value that is set in - * this file. - * - * @param args The command line arguments. - */ - public void readArgs(String[] args) { - - proc.startOptions(); - - int i = 0; - while (i < args.length) { - String arg = args[i++]; - if (arg.startsWith("--")) { - // This is a long style 'property' format option. - addOption(arg.substring(2)); - - } else if (arg.equals("-c")) { - // Config file - readConfigFile(args[i++]); - - } else if (arg.equals("-n")) { - // Map name (should be an 8 digit number). - addOption("mapname", args[i++]); - - } else if (arg.equals("-v")) { - // make commands more verbose - addOption("verbose"); - - } else if (arg.startsWith("-")) { - // this is an unrecognised option. - System.err.println("unrecognised option " + arg); - - } else { - log.debug("adding filename:", arg); - arglist.add(new Filename(arg)); - } - } - - // If there is more than one filename argument we inform of this fact - // via a fake option. - proc.processOption("number-of-files", String.valueOf(arglist.getFilenameCount())); - - // Now process the arguments in order. - for (ArgType a : arglist) { - a.processArg(); - } - - proc.endOptions(this); - } - public EnhancedProperties getProperties() { - return arglist.getProperties(); + return currentOptions; } public int get(String name, int def) { @@ -134,31 +25,31 @@ return currentOptions.getProperty(name, def); } + public String getDescription() { + return currentOptions.getProperty("description"); + } + // //// // There are a number of methods to get specific arguments that follow. // There are many more options in use however. New code should mostly // just use the get methods above. // //// - public String getDescription() { - return arglist.getProperty("description"); - } - public int getBlockSize() { return get("block-size", 512); } public String getMapname() { - return arglist.getProperty("mapname"); + return currentOptions.getProperty("mapname"); } public String getCharset() { - String charset = arglist.getProperty("latin1"); + String charset = currentOptions.getProperty("latin1"); if (charset != null) return "latin1"; // xcharset is the old value, use charset instead. - charset = arglist.getProperty("charset", arglist.getProperty("xcharset")); + charset = currentOptions.getProperty("charset", currentOptions.getProperty("xcharset")); if (charset != null) return charset; @@ -173,7 +64,7 @@ int cp; // xcode-page is the old name - String s = arglist.getProperty("code-page", arglist.getProperty("xcode-page", "0")); + String s = currentOptions.getProperty("code-page", currentOptions.getProperty("xcode-page", "0")); try { cp = Integer.parseInt(s); } catch (NumberFormatException e) { @@ -184,7 +75,7 @@ } public boolean isForceUpper() { - return arglist.getProperty("lower-case") == null; + return currentOptions.getProperty("lower-case") == null; } /** @@ -194,208 +85,7 @@ return currentOptions.containsKey(name); } - /** - * Add an option based on the option and value separately. - * @param option The option name. - * @param value Its value. - */ - private void addOption(String option, String value) { - CommandOption opt = new CommandOption(option, value); - addOption(opt); + public void setProperty(String option, String value) { + currentOptions.setProperty(option, value); } - - /** - * Add an option from a raw string. - * @param optval The option=value string. - */ - private void addOption(String optval) { - CommandOption opt = new CommandOption(new Option(optval)); - addOption(opt); - } - - /** - * Actually add the option. Some of these are special in that they are - * filename arguments or instructions to read options from another file. - * - * @param opt The decoded option. - */ - private void addOption(CommandOption opt) { - String option = opt.getOption(); - String value = opt.getValue(); - - log.debug("adding option", option, value); - - // Note if an explicit mapname is set - if (option.equals("mapname")) - mapnameWasSet = true; - - if (option.equals("input-file")) { - log.debug("adding filename", value); - arglist.add(new Filename(value)); - } else if (option.equals("read-config")) { - readConfigFile(value); - } else { - arglist.add(opt); - } - } - - /** - * Read a config file that contains more options. When the number of - * options becomes large it is more convenient to place them in a file. - * - * @param filename The filename to obtain options from. - */ - private void readConfigFile(String filename) { - Options opts = new Options(new OptionProcessor() { - public void processOption(Option opt) { - log.debug("incoming opt", opt.getOption(), opt.getValue()); - addOption(new CommandOption(opt)); - } - }); - try { - opts.readOptionFile(filename); - } catch (IOException e) { - throw new ExitException("Failed to read option file", e); - } - } - - /** - * The arguments are held in this list. - */ - private class ArgList implements Iterable { - private final List alist = new ArrayList(); - - private int filenameCount; - - public void add(CommandOption option) { - alist.add(option); - } - - public void add(Filename name) { - filenameCount++; - alist.add(name); - } - - public Iterator iterator() { - return alist.iterator(); - } - - public int getFilenameCount() { - return filenameCount; - } - - public String getProperty(String name) { - return currentOptions.getProperty(name); - } - - public String getProperty(String name, String def) { - String val = currentOptions.getProperty(name); - if (val == null) - val = def; - return val; - } - - public EnhancedProperties getProperties() { - return currentOptions; - } - - public void setProperty(String name, String value) { - currentOptions.setProperty(name, value); - } - } - - /** - * Interface that represents an argument type. It provides a method for - * the argument to be processed in order. Options can be intersperced with - * filenames. The options take effect where they appear. - */ - private interface ArgType { - public abstract void processArg(); - } - - /** - * A filename. - */ - private class Filename implements ArgType { - private final String name; - private boolean useFilenameAsMapname = true; - - private Filename(String name) { - this.name = name; - if (mapnameWasSet) - useFilenameAsMapname = false; - } - - public void processArg() { - // If there was no explicit mapname specified and the input filename - // looks like it contains an 8digit number then we use that. - String mapname; - if (useFilenameAsMapname) { - mapname = extractMapName(name); - if (mapname != null) - arglist.setProperty("mapname", mapname); - } - - // Now process the file - proc.processFilename(CommandArgs.this, name); - - // Increase the name number. If the next arg sets it then that - // will override this new name. - mapname = arglist.getProperty("mapname"); - try { - Formatter fmt = new Formatter(); - try { - int n = Integer.parseInt(mapname); - fmt.format("%08d", ++n); - } catch (NumberFormatException e) { - fmt.format("%8.8s", mapname); - } - arglist.setProperty("mapname", fmt.toString()); - } catch (NumberFormatException e) { - // If the name is not a number then we just leave it alone... - } - } - - private String extractMapName(String path) { - - File file = new File(path); - String fname = file.getName(); - Pattern pat = Pattern.compile("([0-9]{8})"); - Matcher matcher = pat.matcher(fname); - boolean found = matcher.find(); - if (found) - return matcher.group(1); - - return null; - } - } - - /** - * An option argument. A key value pair. - */ - private class CommandOption implements ArgType { - private final Option option; - - private CommandOption(Option option) { - this.option = option; - } - - private CommandOption(String key, String val) { - this.option = new Option(key, val); - } - - public void processArg() { - currentOptions.setProperty(option.getOption(), option.getValue()); - proc.processOption(option.getOption(), option.getValue()); - } - - public String getOption() { - return option.getOption(); - } - - public String getValue() { - return option.getValue(); - } - } - -} +} \ No newline at end of file Index: src/uk/me/parabola/util/EnhancedProperties.java =================================================================== --- src/uk/me/parabola/util/EnhancedProperties.java (revision 1035) +++ src/uk/me/parabola/util/EnhancedProperties.java (working copy) @@ -17,6 +17,7 @@ package uk.me.parabola.util; import java.util.Properties; +import java.util.Enumeration; /** * Wrapper that behaves as an enhanced properties class that has getProperty @@ -25,7 +26,20 @@ * @author Steve Ratcliffe */ public class EnhancedProperties extends Properties { + + public EnhancedProperties() { + } + public EnhancedProperties(Properties defaults) { + // We copy values, rather than making them default values so that + // we can enumerate all the options. + Enumeration en = defaults.propertyNames(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + setProperty(key, defaults.getProperty(key)); + } + } + /** * Get a property as an integer value. If the property does not exist * or the value is not a valid integer, then the default value is returned Index: resources/help/en/options =================================================================== --- resources/help/en/options (revision 1035) +++ resources/help/en/options (working copy) @@ -101,6 +101,11 @@ --overview-mapname Misc options: +--max-jobs=''number'' + Limit the number of maps processed concurrently to the + specified number. By default, the limit is set to the number + of CPU cores up to a maximum of 4. + --block-size=''number'' Changes the block size that is used in the generated map. There is no general reason why you would want to do this.