1 /*
   2  * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.javadoc.internal.doclets.formats.html;
  27 
  28 import java.net.MalformedURLException;
  29 import java.net.URL;
  30 import java.util.ArrayList;
  31 import java.util.LinkedHashMap;
  32 import java.util.List;
  33 import java.util.Map;
  34 import java.util.Set;
  35 import java.util.TreeSet;
  36 
  37 import com.sun.tools.doclint.DocLint;
  38 import jdk.javadoc.doclet.Doclet;
  39 import jdk.javadoc.doclet.Reporter;
  40 import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
  41 import jdk.javadoc.internal.doclets.toolkit.Resources;
  42 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
  43 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  44 
  45 import static javax.tools.Diagnostic.Kind.ERROR;
  46 import static javax.tools.Diagnostic.Kind.WARNING;
  47 
  48 public class HtmlOptions extends BaseOptions {
  49     //<editor-fold desc="Option values">
  50     /**
  51      * Argument for command-line option {@code --add-stylesheet}.
  52      */
  53     public List<String> additionalStylesheets = new ArrayList<>();
  54 
  55     /**
  56      * Argument for command-line option {@code -bottom}.
  57      */
  58     public String bottom = "";
  59 
  60     /**
  61      * Argument for command-line option {@code -charset}.
  62      * The META charset tag used for cross-platform viewing.
  63      */
  64     public String charset = null;
  65 
  66     /**
  67      * Argument for command-line option {@code -use}.
  68      * True if command line option "-use" is used. Default value is false.
  69      */
  70     public boolean classUse = false;
  71 
  72     /**
  73      * Argument for command-line option {@code -noindex}.
  74      * False if command line option "-noindex" is used. Default value is true.
  75      */
  76     public boolean createIndex = true;
  77 
  78     /**
  79      * Argument for command-line option {@code -overview}.
  80      * This is true if option "-overview" is used or option "-overview" is not
  81      * used and number of packages is more than one.
  82      */
  83     public boolean createOverview = false;
  84 
  85     /**
  86      * Argument for command-line option {@code -notree}.
  87      * False if command line option "-notree" is used. Default value is true.
  88      */
  89     public boolean createTree = true;
  90 
  91     /**
  92      * Arguments for command-line option {@code -Xdoclint} and friends.
  93      * Collected set of doclint options.
  94      */
  95     public Map<Doclet.Option, String> doclintOpts = new LinkedHashMap<>();
  96 
  97     /**
  98      * Argument for command-line option {@code -Xdocrootparent}.
  99      */
 100     public String docrootParent = "";
 101 
 102     /**
 103      * Argument for command-line option {@code -doctitle}.
 104      */
 105     public String docTitle = "";
 106 
 107 
 108     /**
 109      * Argument for command-line option {@code -footer}.
 110      */
 111     public String footer = "";
 112 
 113     /**
 114      * Argument for command-line option {@code -header}.
 115      */
 116     public String header = "";
 117 
 118     /**
 119      * Argument for command-line option {@code -helpfile}.
 120      */
 121     public String helpFile = "";
 122 
 123     /**
 124      * Argument for command-line option {@code -nodeprecated}.
 125      * True if command line option "-nodeprecated" is used. Default value is
 126      * false.
 127      */
 128     public boolean noDeprecatedList = false;
 129 
 130     /**
 131      * Argument for command-line option {@code -nohelp}.
 132      * True if command line option "-nohelp" is used. Default value is false.
 133      */
 134     public boolean noHelp = false;
 135 
 136     /**
 137      * Argument for command-line option {@code -nonavbar}.
 138      * True if command line option "-nonavbar" is used. Default value is false.
 139      */
 140     public boolean noNavbar = false;
 141 
 142     /**
 143      * Argument for command-line option {@code -nooverview}.
 144      * True if command line option "-nooverview" is used. Default value is
 145      * false
 146      */
 147     boolean noOverview = false;
 148 
 149     /**
 150      * Argument for command-line option {@code -overview}.
 151      * The overview path specified with "-overview" flag.
 152      */
 153     public String overviewPath = null;
 154 
 155     /**
 156      * Argument for command-line option {@code -packagesheader}.
 157      */
 158     public String packagesHeader = "";
 159 
 160     /**
 161      * Argument for command-line option {@code -splitindex}.
 162      * True if command line option "-splitindex" is used. Default value is
 163      * false.
 164      */
 165     public boolean splitIndex = false;
 166 
 167     /**
 168      * Argument for command-line option {@code -stylesheetfile}.
 169      */
 170     public String stylesheetFile = "";
 171 
 172     /**
 173      * Argument for command-line option {@code -top}.
 174      */
 175     public String top = "";
 176 
 177     /**
 178      * Argument for command-line option {@code -windowtitle}.
 179      */
 180     public String windowTitle = "";
 181     //</editor-fold>
 182 
 183     private HtmlConfiguration config;
 184 
 185     HtmlOptions(HtmlConfiguration config) {
 186         super(config);
 187         this.config = config;
 188     }
 189 
 190     @Override
 191     public Set<? extends Doclet.Option> getSupportedOptions() {
 192         Resources resources = config.getResources();
 193         Reporter reporter = config.getReporter();
 194 
 195         List<Option> options = List.of(
 196                 new Option(resources, "--add-stylesheet", 1) {
 197                     @Override
 198                     public boolean process(String opt, List<String> args) {
 199                         additionalStylesheets.add(args.get(0));
 200                         return true;
 201                     }
 202                 },
 203 
 204                 new Option(resources, "-bottom", 1) {
 205                     @Override
 206                     public boolean process(String opt,  List<String> args) {
 207                         bottom = args.get(0);
 208                         return true;
 209                     }
 210                 },
 211 
 212                 new Option(resources, "-charset", 1) {
 213                     @Override
 214                     public boolean process(String opt,  List<String> args) {
 215                         charset = args.get(0);
 216                         return true;
 217                     }
 218                 },
 219 
 220                 new Option(resources, "-doctitle", 1) {
 221                     @Override
 222                     public boolean process(String opt,  List<String> args) {
 223                         docTitle = args.get(0);
 224                         return true;
 225                     }
 226                 },
 227 
 228                 new Option(resources, "-footer", 1) {
 229                     @Override
 230                     public boolean process(String opt, List<String> args) {
 231                         footer = args.get(0);
 232                         return true;
 233                     }
 234                 },
 235 
 236                 new Option(resources, "-header", 1) {
 237                     @Override
 238                     public boolean process(String opt,  List<String> args) {
 239                         header = args.get(0);
 240                         return true;
 241                     }
 242                 },
 243 
 244                 new Option(resources, "-helpfile", 1) {
 245                     @Override
 246                     public boolean process(String opt,  List<String> args) {
 247                         if (noHelp) {
 248                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 249                                     "-helpfile", "-nohelp"));
 250                             return false;
 251                         }
 252                         if (!helpFile.isEmpty()) {
 253                             reporter.print(ERROR, resources.getText("doclet.Option_reuse",
 254                                     "-helpfile"));
 255                             return false;
 256                         }
 257                         helpFile = args.get(0);
 258                         return true;
 259                     }
 260                 },
 261 
 262                 new Option(resources, "-html5") {
 263                     @Override
 264                     public boolean process(String opt,  List<String> args) {
 265                         return true;
 266                     }
 267                 },
 268 
 269                 new Option(resources, "-nohelp") {
 270                     @Override
 271                     public boolean process(String opt, List<String> args) {
 272                         noHelp = true;
 273                         if (!helpFile.isEmpty()) {
 274                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 275                                     "-nohelp", "-helpfile"));
 276                             return false;
 277                         }
 278                         return true;
 279                     }
 280                 },
 281 
 282                 new Option(resources, "-nodeprecatedlist") {
 283                     @Override
 284                     public boolean process(String opt,  List<String> args) {
 285                         noDeprecatedList = true;
 286                         return true;
 287                     }
 288                 },
 289 
 290                 new Option(resources, "-noindex") {
 291                     @Override
 292                     public boolean process(String opt,  List<String> args) {
 293                         createIndex = false;
 294                         if (splitIndex) {
 295                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 296                                     "-noindex", "-splitindex"));
 297                             return false;
 298                         }
 299                         return true;
 300                     }
 301                 },
 302 
 303                 new Option(resources, "-nonavbar") {
 304                     @Override
 305                     public boolean process(String opt,  List<String> args) {
 306                         noNavbar = true;
 307                         return true;
 308                     }
 309                 },
 310 
 311                 new Hidden(resources, "-nooverview") {
 312                     @Override
 313                     public boolean process(String opt,  List<String> args) {
 314                         noOverview = true;
 315                         if (overviewPath != null) {
 316                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 317                                     "-nooverview", "-overview"));
 318                             return false;
 319                         }
 320                         return true;
 321                     }
 322                 },
 323 
 324                 new Option(resources, "-notree") {
 325                     @Override
 326                     public boolean process(String opt,  List<String> args) {
 327                         createTree = false;
 328                         return true;
 329                     }
 330                 },
 331 
 332                 new Option(resources, "-overview", 1) {
 333                     @Override
 334                     public boolean process(String opt,  List<String> args) {
 335                         overviewPath = args.get(0);
 336                         if (noOverview) {
 337                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 338                                     "-overview", "-nooverview"));
 339                             return false;
 340                         }
 341                         return true;
 342                     }
 343                 },
 344 
 345                 new Hidden(resources, "-packagesheader", 1) {
 346                     @Override
 347                     public boolean process(String opt,  List<String> args) {
 348                         packagesHeader = args.get(0);
 349                         return true;
 350                     }
 351                 },
 352 
 353                 new Option(resources, "-splitindex") {
 354                     @Override
 355                     public boolean process(String opt, List<String> args) {
 356                         splitIndex = true;
 357                         if (!createIndex) {
 358                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 359                                     "-splitindex", "-noindex"));
 360                             return false;
 361                         }
 362                         return true;
 363                     }
 364                 },
 365 
 366                 new Option(resources, "--main-stylesheet -stylesheetfile", 1) {
 367                     @Override
 368                     public boolean process(String opt,  List<String> args) {
 369                         stylesheetFile = args.get(0);
 370                         return true;
 371                     }
 372                 },
 373 
 374                 new Option(resources, "-top", 1) {
 375                     @Override
 376                     public boolean process(String opt,  List<String> args) {
 377                         top = args.get(0);
 378                         return true;
 379                     }
 380                 },
 381 
 382                 new Option(resources, "-use") {
 383                     @Override
 384                     public boolean process(String opt,  List<String> args) {
 385                         classUse = true;
 386                         return true;
 387                     }
 388                 },
 389 
 390                 new Option(resources, "-windowtitle", 1) {
 391                     @Override
 392                     public boolean process(String opt,  List<String> args) {
 393                         windowTitle = args.get(0).replaceAll("<.*?>", "");
 394                         return true;
 395                     }
 396                 },
 397 
 398                 new XOption(resources, "-Xdoclint") {
 399                     @Override
 400                     public boolean process(String opt,  List<String> args) {
 401                         doclintOpts.put(this, DocLint.XMSGS_OPTION);
 402                         return true;
 403                     }
 404                 },
 405 
 406                 new XOption(resources, "-Xdocrootparent", 1) {
 407                     @Override
 408                     public boolean process(String opt, List<String> args) {
 409                         docrootParent = args.get(0);
 410                         try {
 411                             new URL(docrootParent);
 412                         } catch (MalformedURLException e) {
 413                             reporter.print(ERROR, resources.getText("doclet.MalformedURL", docrootParent));
 414                             return false;
 415                         }
 416                         return true;
 417                     }
 418                 },
 419 
 420                 new XOption(resources, "doclet.usage.xdoclint-extended", "-Xdoclint:", 0) {
 421                     @Override
 422                     public boolean process(String opt,  List<String> args) {
 423                         String dopt = opt.replace("-Xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX);
 424                         doclintOpts.put(this, dopt);
 425                         if (dopt.contains("/")) {
 426                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_no_qualifiers"));
 427                             return false;
 428                         }
 429                         if (!DocLint.isValidOption(dopt)) {
 430                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_invalid_arg"));
 431                             return false;
 432                         }
 433                         return true;
 434                     }
 435                 },
 436 
 437                 new XOption(resources, "doclet.usage.xdoclint-package", "-Xdoclint/package:", 0) {
 438                     @Override
 439                     public boolean process(String opt,  List<String> args) {
 440                         String dopt = opt.replace("-Xdoclint/package:", DocLint.XCHECK_PACKAGE);
 441                         doclintOpts.put(this, dopt);
 442                         if (!DocLint.isValidOption(dopt)) {
 443                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_package_invalid_arg"));
 444                             return false;
 445                         }
 446                         return true;
 447                     }
 448                 },
 449 
 450                 new XOption(resources, "--no-frames") {
 451                     @Override
 452                     public boolean process(String opt, List<String> args) {
 453                         reporter.print(WARNING, resources.getText("doclet.NoFrames_specified"));
 454                         return true;
 455                     }
 456                 }
 457         );
 458         Set<Doclet.Option> allOptions = new TreeSet<>();
 459         allOptions.addAll(options);
 460         allOptions.addAll(super.getSupportedOptions());
 461         return allOptions;
 462     }
 463 
 464     @Override
 465     public HtmlOptions getOptions() {
 466         return this;
 467     }
 468 
 469 
 470     protected boolean validateOptions() {
 471         // check shared options
 472         if (!generalValidOptions()) {
 473             return false;
 474         }
 475 
 476         Resources resources = config.getResources();
 477         Reporter reporter = config.getReporter();
 478 
 479         // check if helpfile exists
 480         if (!helpFile.isEmpty()) {
 481             DocFile help = DocFile.createFileForInput(config, helpFile);
 482             if (!help.exists()) {
 483                 reporter.print(ERROR, resources.getText("doclet.File_not_found", helpFile));
 484                 return false;
 485             }
 486         }
 487         // check if stylesheetfile exists
 488         if (!stylesheetFile.isEmpty()) {
 489             DocFile stylesheet = DocFile.createFileForInput(config, stylesheetFile);
 490             if (!stylesheet.exists()) {
 491                 reporter.print(ERROR, resources.getText("doclet.File_not_found", stylesheetFile));
 492                 return false;
 493             }
 494         }
 495         // check if additional stylesheets exists
 496         for (String ssheet : additionalStylesheets) {
 497             DocFile ssfile = DocFile.createFileForInput(config, ssheet);
 498             if (!ssfile.exists()) {
 499                 reporter.print(ERROR, resources.getText("doclet.File_not_found", ssheet));
 500                 return false;
 501             }
 502         }
 503 
 504         // In a more object-oriented world, this would be done by methods on the Option objects.
 505         // Note that -windowtitle silently removes any and all HTML elements, and so does not need
 506         // to be handled here.
 507         Utils utils = config.utils;
 508         utils.checkJavaScriptInOption("-header", header);
 509         utils.checkJavaScriptInOption("-footer", footer);
 510         utils.checkJavaScriptInOption("-top", top);
 511         utils.checkJavaScriptInOption("-bottom", bottom);
 512         utils.checkJavaScriptInOption("-doctitle", docTitle);
 513         utils.checkJavaScriptInOption("-packagesheader", packagesHeader);
 514 
 515         return true;
 516     }
 517 
 518 }