Ignore:
Timestamp:
2018-11-07T21:38:22+01:00 (5 years ago)
Author:
michael2402
Message:

See #16866: Drop getopt, use own option parser.

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/ProgramArguments.java

    r12893 r14415  
    33
    44import java.util.ArrayList;
     5import java.util.Arrays;
    56import java.util.Collection;
    67import java.util.Collections;
     
    1415import java.util.stream.Stream;
    1516
    16 import org.openstreetmap.josm.tools.I18n;
    1717import org.openstreetmap.josm.tools.Logging;
    18 
    19 import gnu.getopt.Getopt;
    20 import gnu.getopt.LongOpt;
     18import org.openstreetmap.josm.tools.OptionParser;
     19import org.openstreetmap.josm.tools.OptionParser.OptionCount;
    2120
    2221/**
     
    9190            return requiresArg;
    9291        }
    93 
    94         LongOpt toLongOpt() {
    95             return new LongOpt(getName(), requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, 0);
    96         }
    9792    }
    9893
     
    114109     */
    115110    private void buildCommandLineArgumentMap(String... args) {
    116         Getopt.setI18nHandler(I18n::tr);
    117         LongOpt[] los = Stream.of(Option.values()).map(Option::toLongOpt).toArray(LongOpt[]::new);
    118         Getopt g = new Getopt("JOSM", args, "hv", los);
    119 
    120         int c;
    121         while ((c = g.getopt()) != -1) {
    122             Option opt;
    123             switch (c) {
    124             case 'h':
    125                 opt = Option.HELP;
    126                 break;
    127             case 'v':
    128                 opt = Option.VERSION;
    129                 break;
    130             case 0:
    131                 opt = Option.values()[g.getLongind()];
    132                 break;
    133             default:
    134                 opt = null;
     111        OptionParser parser = new OptionParser("JOSM");
     112        for (Option o : Option.values()) {
     113            if (o.requiresArgument()) {
     114                parser.addArgumentParameter(o.getName(), OptionCount.MULTIPLE, p -> addOption(o, p));
     115            } else {
     116                parser.addFlagParameter(o.getName(), () -> addOption(o, ""));
    135117            }
    136             if (opt != null) {
    137                 addOption(opt, g.getOptarg());
    138             } else
    139                 throw new IllegalArgumentException("Invalid option: "+ (char) c);
    140         }
     118        }
     119
     120        parser.addShortAlias(Option.HELP.getName(), "h");
     121        parser.addShortAlias(Option.VERSION.getName(), "v");
     122
     123        List<String> remaining = parser.parseOptionsOrExit(Arrays.asList(args));
     124
    141125        // positional arguments are a shortcut for the --download ... option
    142         for (int i = g.getOptind(); i < args.length; ++i) {
    143             addOption(Option.DOWNLOAD, args[i]);
     126        for (String arg : remaining) {
     127            addOption(Option.DOWNLOAD, arg);
    144128        }
    145129    }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java

    r14120 r14415  
    1212import java.nio.file.Paths;
    1313import java.util.ArrayList;
     14import java.util.Arrays;
    1415import java.util.List;
    1516import java.util.Locale;
     
    3839import org.openstreetmap.josm.spi.preferences.Config;
    3940import org.openstreetmap.josm.spi.preferences.MemoryPreferences;
    40 import org.openstreetmap.josm.tools.I18n;
    4141import org.openstreetmap.josm.tools.JosmDecimalFormatSymbolsProvider;
    4242import org.openstreetmap.josm.tools.Logging;
     43import org.openstreetmap.josm.tools.OptionParser;
     44import org.openstreetmap.josm.tools.OptionParser.OptionCount;
     45import org.openstreetmap.josm.tools.OptionParser.OptionParseException;
    4346import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
    44 
    45 import gnu.getopt.Getopt;
    46 import gnu.getopt.LongOpt;
    4747
    4848/**
     
    7676    private String argProjection;
    7777    private Integer argMaxImageSize;
     78
     79    private StyleData argCurrentStyle;
    7880
    7981    private enum Option {
     
    129131            return shortOption;
    130132        }
    131 
    132         LongOpt toLongOpt() {
    133             return new LongOpt(getName(), requiresArgument() ? LongOpt.REQUIRED_ARGUMENT : LongOpt.NO_ARGUMENT, null, getShortOption());
    134         }
    135133    }
    136134
     
    188186     */
    189187    void parseArguments(String[] argArray) {
    190         Getopt.setI18nHandler(I18n::tr);
    191188        Logging.setLogLevel(Level.INFO);
    192189
    193         LongOpt[] opts = new LongOpt[Option.values().length];
    194         StringBuilder optString = new StringBuilder();
     190        OptionParser parser = new OptionParser("JOSM rendering");
    195191        for (Option o : Option.values()) {
    196             opts[o.ordinal()] = o.toLongOpt();
     192            if (o.requiresArgument()) {
     193                parser.addArgumentParameter(o.getName(),
     194                        o == Option.SETTING ? OptionCount.MULTIPLE : OptionCount.OPTIONAL,
     195                        arg -> handleOption(o, arg));
     196            } else {
     197                parser.addFlagParameter(o.getName(), () -> handleOption(o));
     198            }
    197199            if (o.getShortOption() != '*') {
    198                 optString.append(o.getShortOption());
    199                 if (o.requiresArgument()) {
    200                     optString.append(':');
     200                parser.addShortAlias(o.getName(), o.getShortOption() + "");
     201            }
     202        }
     203
     204        argCurrentStyle = new StyleData();
     205        argStyles = new ArrayList<>();
     206
     207        parser.parseOptionsOrExit(Arrays.asList(argArray));
     208
     209        if (argCurrentStyle.styleUrl != null) {
     210            argStyles.add(argCurrentStyle);
     211        }
     212    }
     213
     214    private void handleOption(Option o) {
     215        switch (o) {
     216        case HELP:
     217            showHelp();
     218            System.exit(0);
     219            break;
     220        case DEBUG:
     221            argDebug = true;
     222            break;
     223        case TRACE:
     224            argTrace = true;
     225            break;
     226        default:
     227            throw new AssertionError("Unexpected option index: " + o);
     228        }
     229    }
     230
     231    private void handleOption(Option o, String arg) {
     232        switch (o) {
     233        case INPUT:
     234            argInput = arg;
     235            break;
     236        case STYLE:
     237            if (argCurrentStyle.styleUrl != null) {
     238                argStyles.add(argCurrentStyle);
     239                argCurrentStyle = new StyleData();
     240            }
     241            argCurrentStyle.styleUrl = arg;
     242            break;
     243        case OUTPUT:
     244            argOutput = arg;
     245            break;
     246        case ZOOM:
     247            try {
     248                argZoom = Integer.valueOf(arg);
     249            } catch (NumberFormatException nfe) {
     250                throw new OptionParseException(
     251                        tr("Expected integer number for option {0}, but got ''{1}''", "--zoom", arg), nfe);
     252            }
     253            if (argZoom < 0) {
     254                throw new OptionParseException(
     255                        tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--zoom", arg));
     256            }
     257            break;
     258        case BOUNDS:
     259            if (!"auto".equals(arg)) {
     260                try {
     261                    argBounds = new Bounds(arg, ",", Bounds.ParseMethod.LEFT_BOTTOM_RIGHT_TOP, false);
     262                } catch (IllegalArgumentException iae) { // NOPMD
     263                    throw new OptionParseException(
     264                            tr("Unable to parse {0} parameter: {1}", "--bounds", iae.getMessage()), iae);
    201265                }
    202266            }
    203         }
    204 
    205         Getopt getopt = new Getopt("JOSM rendering", argArray, optString.toString(), opts);
    206 
    207         StyleData currentStyle = new StyleData();
    208         argStyles = new ArrayList<>();
    209 
    210         int c;
    211         while ((c = getopt.getopt()) != -1) {
    212             switch (c) {
    213             case 'h':
    214                 showHelp();
    215                 System.exit(0);
    216             case 'i':
    217                 argInput = getopt.getOptarg();
    218                 break;
    219             case 's':
    220                 if (currentStyle.styleUrl != null) {
    221                     argStyles.add(currentStyle);
    222                     currentStyle = new StyleData();
    223                 }
    224                 currentStyle.styleUrl = getopt.getOptarg();
    225                 break;
    226             case 'o':
    227                 argOutput = getopt.getOptarg();
    228                 break;
    229             case 'z':
    230                 try {
    231                     argZoom = Integer.valueOf(getopt.getOptarg());
    232                 } catch (NumberFormatException nfe) {
    233                     throw new IllegalArgumentException(
    234                             tr("Expected integer number for option {0}, but got ''{1}''", "--zoom", getopt.getOptarg()), nfe);
    235                 }
    236                 if (argZoom < 0)
    237                     throw new IllegalArgumentException(
    238                             tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--zoom", getopt.getOptarg()));
    239                 break;
    240             case 'b':
    241                 if (!"auto".equals(getopt.getOptarg())) {
    242                     try {
    243                         argBounds = new Bounds(getopt.getOptarg(), ",", Bounds.ParseMethod.LEFT_BOTTOM_RIGHT_TOP, false);
    244                     } catch (IllegalArgumentException iae) { // NOPMD
    245                         throw new IllegalArgumentException(tr("Unable to parse {0} parameter: {1}", "--bounds", iae.getMessage()), iae);
    246                     }
    247                 }
    248                 break;
    249             case '*':
    250                 switch (Option.values()[getopt.getLongind()]) {
    251                 case DEBUG:
    252                     argDebug = true;
    253                     break;
    254                 case TRACE:
    255                     argTrace = true;
    256                     break;
    257                 case SETTING:
    258                     String keyval = getopt.getOptarg();
    259                     String[] comp = keyval.split(":");
    260                     if (comp.length != 2)
    261                         throw new IllegalArgumentException(
    262                                 tr("Expected key and value, separated by '':'' character for option {0}, but got ''{1}''",
    263                                         "--setting", getopt.getOptarg()));
    264                     currentStyle.settings.put(comp[0].trim(), comp[1].trim());
    265                     break;
    266                 case SCALE:
    267                     try {
    268                         argScale = JosmDecimalFormatSymbolsProvider.parseDouble(getopt.getOptarg());
    269                     } catch (NumberFormatException nfe) {
    270                         throw new IllegalArgumentException(
    271                                 tr("Expected floating point number for option {0}, but got ''{1}''", "--scale", getopt.getOptarg()), nfe);
    272                     }
    273                     break;
    274                 case ANCHOR:
    275                     String[] parts = getopt.getOptarg().split(",");
    276                     if (parts.length != 2)
    277                         throw new IllegalArgumentException(
    278                                 tr("Expected two coordinates, separated by comma, for option {0}, but got ''{1}''",
    279                                 "--anchor", getopt.getOptarg()));
    280                     try {
    281                         double lon = LatLonParser.parseCoordinate(parts[0]);
    282                         double lat = LatLonParser.parseCoordinate(parts[1]);
    283                         argAnchor = new LatLon(lat, lon);
    284                     } catch (IllegalArgumentException iae) { // NOPMD
    285                         throw new IllegalArgumentException(tr("In option {0}: {1}", "--anchor", iae.getMessage()), iae);
    286                     }
    287                     break;
    288                 case WIDTH_M:
    289                     try {
    290                         argWidthM = JosmDecimalFormatSymbolsProvider.parseDouble(getopt.getOptarg());
    291                     } catch (NumberFormatException nfe) {
    292                         throw new IllegalArgumentException(
    293                                 tr("Expected floating point number for option {0}, but got ''{1}''", "--width-m", getopt.getOptarg()), nfe);
    294                     }
    295                     if (argWidthM <= 0) throw new IllegalArgumentException(
    296                             tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", getopt.getOptarg()));
    297                     break;
    298                 case HEIGHT_M:
    299                     try {
    300                         argHeightM = JosmDecimalFormatSymbolsProvider.parseDouble(getopt.getOptarg());
    301                     } catch (NumberFormatException nfe) {
    302                         throw new IllegalArgumentException(
    303                                 tr("Expected floating point number for option {0}, but got ''{1}''", "--height-m", getopt.getOptarg()), nfe);
    304                     }
    305                     if (argHeightM <= 0) throw new IllegalArgumentException(
    306                             tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", getopt.getOptarg()));
    307                     break;
    308                 case WIDTH_PX:
    309                     try {
    310                         argWidthPx = Integer.valueOf(getopt.getOptarg());
    311                     } catch (NumberFormatException nfe) {
    312                         throw new IllegalArgumentException(
    313                                 tr("Expected integer number for option {0}, but got ''{1}''", "--width-px", getopt.getOptarg()), nfe);
    314                     }
    315                     if (argWidthPx <= 0) throw new IllegalArgumentException(
    316                             tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--width-px", getopt.getOptarg()));
    317                     break;
    318                 case HEIGHT_PX:
    319                     try {
    320                         argHeightPx = Integer.valueOf(getopt.getOptarg());
    321                     } catch (NumberFormatException nfe) {
    322                         throw new IllegalArgumentException(
    323                                 tr("Expected integer number for option {0}, but got ''{1}''", "--height-px", getopt.getOptarg()), nfe);
    324                     }
    325                     if (argHeightPx <= 0) throw new IllegalArgumentException(
    326                             tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--height-px", getopt.getOptarg()));
    327                     break;
    328                 case PROJECTION:
    329                     argProjection = getopt.getOptarg();
    330                     break;
    331                 case MAX_IMAGE_SIZE:
    332                     try {
    333                         argMaxImageSize = Integer.valueOf(getopt.getOptarg());
    334                     } catch (NumberFormatException nfe) {
    335                         throw new IllegalArgumentException(
    336                                 tr("Expected integer number for option {0}, but got ''{1}''", "--max-image-size", getopt.getOptarg()), nfe);
    337                     }
    338                     if (argMaxImageSize < 0) throw new IllegalArgumentException(
    339                             tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--max-image-size", getopt.getOptarg()));
    340                     break;
    341                 default:
    342                     throw new AssertionError("Unexpected option index: " + getopt.getLongind());
    343                 }
    344                 break;
    345             case '?':
    346                 throw new IllegalArgumentException();   // getopt error
    347             default:
    348                 throw new AssertionError("Unrecognized option: " + c);
    349             }
    350         }
    351         if (currentStyle.styleUrl != null) {
    352             argStyles.add(currentStyle);
     267            break;
     268
     269        case SETTING:
     270            String keyval = arg;
     271            String[] comp = keyval.split(":", 2);
     272            if (comp.length != 2) {
     273                throw new OptionParseException(
     274                        tr("Expected key and value, separated by '':'' character for option {0}, but got ''{1}''",
     275                                "--setting", arg));
     276            }
     277            argCurrentStyle.settings.put(comp[0].trim(), comp[1].trim());
     278            break;
     279        case SCALE:
     280            try {
     281                argScale = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
     282            } catch (NumberFormatException nfe) {
     283                throw new OptionParseException(
     284                        tr("Expected floating point number for option {0}, but got ''{1}''", "--scale", arg), nfe);
     285            }
     286            break;
     287        case ANCHOR:
     288            String[] parts = arg.split(",");
     289            if (parts.length != 2)
     290                throw new OptionParseException(
     291                        tr("Expected two coordinates, separated by comma, for option {0}, but got ''{1}''", "--anchor",
     292                                arg));
     293            try {
     294                double lon = LatLonParser.parseCoordinate(parts[0]);
     295                double lat = LatLonParser.parseCoordinate(parts[1]);
     296                argAnchor = new LatLon(lat, lon);
     297            } catch (IllegalArgumentException iae) { // NOPMD
     298                throw new OptionParseException(tr("In option {0}: {1}", "--anchor", iae.getMessage()), iae);
     299            }
     300            break;
     301        case WIDTH_M:
     302            try {
     303                argWidthM = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
     304            } catch (NumberFormatException nfe) {
     305                throw new OptionParseException(
     306                        tr("Expected floating point number for option {0}, but got ''{1}''", "--width-m", arg), nfe);
     307            }
     308            if (argWidthM <= 0)
     309                throw new OptionParseException(
     310                        tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", arg));
     311            break;
     312        case HEIGHT_M:
     313            try {
     314                argHeightM = JosmDecimalFormatSymbolsProvider.parseDouble(arg);
     315            } catch (NumberFormatException nfe) {
     316                throw new OptionParseException(
     317                        tr("Expected floating point number for option {0}, but got ''{1}''", "--height-m", arg), nfe);
     318            }
     319            if (argHeightM <= 0)
     320                throw new OptionParseException(
     321                        tr("Expected floating point number > 0 for option {0}, but got ''{1}''", "--width-m", arg));
     322            break;
     323        case WIDTH_PX:
     324            try {
     325                argWidthPx = Integer.valueOf(arg);
     326            } catch (NumberFormatException nfe) {
     327                throw new OptionParseException(
     328                        tr("Expected integer number for option {0}, but got ''{1}''", "--width-px", arg), nfe);
     329            }
     330            if (argWidthPx <= 0)
     331                throw new OptionParseException(
     332                        tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--width-px", arg));
     333            break;
     334        case HEIGHT_PX:
     335            try {
     336                argHeightPx = Integer.valueOf(arg);
     337            } catch (NumberFormatException nfe) {
     338                throw new OptionParseException(
     339                        tr("Expected integer number for option {0}, but got ''{1}''", "--height-px", arg), nfe);
     340            }
     341            if (argHeightPx <= 0) {
     342                throw new OptionParseException(
     343                        tr("Expected integer number > 0 for option {0}, but got ''{1}''", "--height-px", arg));
     344            }
     345            break;
     346        case PROJECTION:
     347            argProjection = arg;
     348            break;
     349        case MAX_IMAGE_SIZE:
     350            try {
     351                argMaxImageSize = Integer.valueOf(arg);
     352            } catch (NumberFormatException nfe) {
     353                throw new OptionParseException(
     354                        tr("Expected integer number for option {0}, but got ''{1}''", "--max-image-size", arg), nfe);
     355            }
     356            if (argMaxImageSize < 0) {
     357                throw new OptionParseException(
     358                        tr("Expected integer number >= 0 for option {0}, but got ''{1}''", "--max-image-size", arg));
     359            }
     360            break;
     361        default:
     362            throw new AssertionError("Unexpected option index: " + o);
    353363        }
    354364    }
     
    383393                "\t                          "+tr("Area to render, default value is ''{0}''", "auto")+"\n"+
    384394                "\t                          "+tr("With keyword ''{0}'', the downloaded area in the .osm input file will be used (if recorded).",
    385                                                      "auto")+"\n"+
     395                                                  "auto")+"\n"+
    386396                "\t--anchor <lon>,<lat>      "+tr("Specify bottom left corner of the rendering area")+"\n"+
    387397                "\t                          "+tr("Used in combination with width and height options to determine the area to render.")+"\n"+
     
    392402                "\t--projection <code>       "+tr("Projection to use, default value ''{0}'' (web-Mercator)", "epsg:3857")+"\n"+
    393403                "\t--max-image-size <number> "+tr("Maximum image width/height in pixel (''{0}'' means no limit), default value: {1}",
    394                                                     0, Integer.toString(DEFAULT_MAX_IMAGE_SIZE))+"\n"+
     404                                                   0, Integer.toString(DEFAULT_MAX_IMAGE_SIZE))+"\n"+
    395405                "\n"+
    396406                tr("To specify the rendered area and scale, the options can be combined in various ways")+":\n"+
     
    452462        Double scale = null; // scale in east-north units per pixel
    453463        if (argZoom != null) {
    454             scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, argZoom) / OsmMercator.DEFAUL_TILE_SIZE / proj.getMetersPerUnit();
     464            scale = OsmMercator.EARTH_RADIUS * Math.PI * 2 / Math.pow(2, argZoom) / OsmMercator.DEFAUL_TILE_SIZE
     465                    / proj.getMetersPerUnit();
    455466        }
    456467        Bounds bounds = argBounds;
     
    464475                DoubleSupplier getEnPerMeter = () -> {
    465476                    double shiftMeter = 10;
    466                     EastNorth projAnchorShifted = projAnchor.add(
    467                             shiftMeter / proj.getMetersPerUnit(), shiftMeter / proj.getMetersPerUnit());
     477                    EastNorth projAnchorShifted = projAnchor.add(shiftMeter / proj.getMetersPerUnit(),
     478                            shiftMeter / proj.getMetersPerUnit());
    468479                    LatLon anchorShifted = proj.eastNorth2latlon(projAnchorShifted);
    469480                    return projAnchor.distance(projAnchorShifted) / argAnchor.greatCircleDistance(anchorShifted);
     
    482493                    } else {
    483494                        throw new IllegalArgumentException(
    484                                 tr("Argument {0} given, but scale cannot be determined from remaining arguments", "--anchor"));
     495                                tr("Argument {0} given, but scale cannot be determined from remaining arguments",
     496                                        "--anchor"));
    485497                    }
    486498                }
     
    517529            } else {
    518530                if (ds.getDataSourceBounds().isEmpty()) {
    519                     throw new IllegalArgumentException(tr("{0} mode, but no bounds found in osm data input file", "--bounds=auto"));
     531                    throw new IllegalArgumentException(
     532                            tr("{0} mode, but no bounds found in osm data input file", "--bounds=auto"));
    520533                }
    521534                bounds = ds.getDataSourceBounds().get(0);
     
    531544        if (scale == null) {
    532545            if (argScale != null) {
    533                 double enPerMeter = pb.getMin().distance(pb.getMax()) / bounds.getMin().greatCircleDistance(bounds.getMax());
     546                double enPerMeter = pb.getMin().distance(pb.getMax())
     547                        / bounds.getMin().greatCircleDistance(bounds.getMax());
    534548                scale = argScale * enPerMeter / PIXEL_PER_METER;
    535549            } else if (argWidthPx != null) {
     
    539553            } else {
    540554                throw new IllegalArgumentException(
    541                         tr("Unable to determine scale, one of the options {0}, {1}, {2} or {3} expected",
    542                                 "--zoom", "--scale", "--width-px", "--height-px"));
     555                        tr("Unable to determine scale, one of the options {0}, {1}, {2} or {3} expected", "--zoom",
     556                                "--scale", "--width-px", "--height-px"));
    543557            }
    544558        }
Note: See TracChangeset for help on using the changeset viewer.