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 /**
  49  * Storage for all options supported by the
  50  * {@link jdk.javadoc.doclet.StandardDoclet standard doclet},
  51  * including the format-independent options handled
  52  * by {@link BaseOptions}.
  53  *
  54  */
  55 public class HtmlOptions extends BaseOptions {
  56     //<editor-fold desc="Option values">
  57     /**
  58      * Argument for command-line option {@code --add-stylesheet}.
  59      */
  60     public List<String> additionalStylesheets = new ArrayList<>();
  61 
  62     /**
  63      * Argument for command-line option {@code -bottom}.
  64      */
  65     public String bottom = "";
  66 
  67     /**
  68      * Argument for command-line option {@code -charset}.
  69      * The META charset tag used for cross-platform viewing.
  70      */
  71     public String charset = null;
  72 
  73     /**
  74      * Argument for command-line option {@code -use}.
  75      * True if command-line option "-use" is used. Default value is false.
  76      */
  77     public boolean classUse = false;
  78 
  79     /**
  80      * Argument for command-line option {@code -noindex}.
  81      * False if command-line option "-noindex" is used. Default value is true.
  82      */
  83     public boolean createIndex = true;
  84 
  85     /**
  86      * Argument for command-line option {@code -overview}.
  87      * This is true if option "-overview" is used or option "-overview" is not
  88      * used and number of packages is more than one.
  89      */
  90     public boolean createOverview = false;
  91 
  92     /**
  93      * Argument for command-line option {@code -notree}.
  94      * False if command-line option "-notree" is used. Default value is true.
  95      */
  96     public boolean createTree = true;
  97 
  98     /**
  99      * Arguments for command-line option {@code -Xdoclint} and friends.
 100      * Collected set of doclint options.
 101      */
 102     public Map<Doclet.Option, String> doclintOpts = new LinkedHashMap<>();
 103 
 104     /**
 105      * Argument for command-line option {@code -Xdocrootparent}.
 106      */
 107     public String docrootParent = "";
 108 
 109     /**
 110      * Argument for command-line option {@code -doctitle}.
 111      */
 112     public String docTitle = "";
 113 
 114 
 115     /**
 116      * Argument for command-line option {@code -footer}.
 117      */
 118     public String footer = "";
 119 
 120     /**
 121      * Argument for command-line option {@code -header}.
 122      */
 123     public String header = "";
 124 
 125     /**
 126      * Argument for command-line option {@code -helpfile}.
 127      */
 128     public String helpFile = "";
 129 
 130     /**
 131      * Argument for command-line option {@code -nodeprecated}.
 132      * True if command-line option "-nodeprecated" is used. Default value is
 133      * false.
 134      */
 135     public boolean noDeprecatedList = false;
 136 
 137     /**
 138      * Argument for command-line option {@code -nohelp}.
 139      * True if command-line option "-nohelp" is used. Default value is false.
 140      */
 141     public boolean noHelp = false;
 142 
 143     /**
 144      * Argument for command-line option {@code -nonavbar}.
 145      * True if command-line option "-nonavbar" is used. Default value is false.
 146      */
 147     public boolean noNavbar = false;
 148 
 149     /**
 150      * Argument for command-line option {@code -nooverview}.
 151      * True if command-line option "-nooverview" is used. Default value is
 152      * false
 153      */
 154     boolean noOverview = false;
 155 
 156     /**
 157      * Argument for command-line option {@code -overview}.
 158      * The overview path specified with "-overview" flag.
 159      */
 160     public String overviewPath = null;
 161 
 162     /**
 163      * Argument for command-line option {@code -packagesheader}.
 164      */
 165     public String packagesHeader = "";
 166 
 167     /**
 168      * Argument for command-line option {@code -splitindex}.
 169      * True if command-line option "-splitindex" is used. Default value is
 170      * false.
 171      */
 172     public boolean splitIndex = false;
 173 
 174     /**
 175      * Argument for command-line option {@code -stylesheetfile}.
 176      */
 177     public String stylesheetFile = "";
 178 
 179     /**
 180      * Argument for command-line option {@code -top}.
 181      */
 182     public String top = "";
 183 
 184     /**
 185      * Argument for command-line option {@code -windowtitle}.
 186      */
 187     public String windowTitle = "";
 188     //</editor-fold>
 189 
 190     private HtmlConfiguration config;
 191 
 192     HtmlOptions(HtmlConfiguration config) {
 193         super(config);
 194         this.config = config;
 195     }
 196 
 197     @Override
 198     public Set<? extends Option> getSupportedOptions() {
 199         Resources resources = config.getResources();
 200         Reporter reporter = config.getReporter();
 201 
 202         List<Option> options = List.of(
 203                 new Option(resources, "--add-stylesheet", 1) {
 204                     @Override
 205                     public boolean process(String opt, List<String> args) {
 206                         additionalStylesheets.add(args.get(0));
 207                         return true;
 208                     }
 209                 },
 210 
 211                 new Option(resources, "-bottom", 1) {
 212                     @Override
 213                     public boolean process(String opt,  List<String> args) {
 214                         bottom = args.get(0);
 215                         return true;
 216                     }
 217                 },
 218 
 219                 new Option(resources, "-charset", 1) {
 220                     @Override
 221                     public boolean process(String opt,  List<String> args) {
 222                         charset = args.get(0);
 223                         return true;
 224                     }
 225                 },
 226 
 227                 new Option(resources, "-doctitle", 1) {
 228                     @Override
 229                     public boolean process(String opt,  List<String> args) {
 230                         docTitle = args.get(0);
 231                         return true;
 232                     }
 233                 },
 234 
 235                 new Option(resources, "-footer", 1) {
 236                     @Override
 237                     public boolean process(String opt, List<String> args) {
 238                         footer = args.get(0);
 239                         return true;
 240                     }
 241                 },
 242 
 243                 new Option(resources, "-header", 1) {
 244                     @Override
 245                     public boolean process(String opt,  List<String> args) {
 246                         header = args.get(0);
 247                         return true;
 248                     }
 249                 },
 250 
 251                 new Option(resources, "-helpfile", 1) {
 252                     @Override
 253                     public boolean process(String opt,  List<String> args) {
 254                         if (noHelp) {
 255                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 256                                     "-helpfile", "-nohelp"));
 257                             return false;
 258                         }
 259                         if (!helpFile.isEmpty()) {
 260                             reporter.print(ERROR, resources.getText("doclet.Option_reuse",
 261                                     "-helpfile"));
 262                             return false;
 263                         }
 264                         helpFile = args.get(0);
 265                         return true;
 266                     }
 267                 },
 268 
 269                 new Option(resources, "-html5") {
 270                     @Override
 271                     public boolean process(String opt,  List<String> args) {
 272                         return true;
 273                     }
 274                 },
 275 
 276                 new Option(resources, "-nohelp") {
 277                     @Override
 278                     public boolean process(String opt, List<String> args) {
 279                         noHelp = true;
 280                         if (!helpFile.isEmpty()) {
 281                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 282                                     "-nohelp", "-helpfile"));
 283                             return false;
 284                         }
 285                         return true;
 286                     }
 287                 },
 288 
 289                 new Option(resources, "-nodeprecatedlist") {
 290                     @Override
 291                     public boolean process(String opt,  List<String> args) {
 292                         noDeprecatedList = true;
 293                         return true;
 294                     }
 295                 },
 296 
 297                 new Option(resources, "-noindex") {
 298                     @Override
 299                     public boolean process(String opt,  List<String> args) {
 300                         createIndex = false;
 301                         if (splitIndex) {
 302                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 303                                     "-noindex", "-splitindex"));
 304                             return false;
 305                         }
 306                         return true;
 307                     }
 308                 },
 309 
 310                 new Option(resources, "-nonavbar") {
 311                     @Override
 312                     public boolean process(String opt,  List<String> args) {
 313                         noNavbar = true;
 314                         return true;
 315                     }
 316                 },
 317 
 318                 new Hidden(resources, "-nooverview") {
 319                     @Override
 320                     public boolean process(String opt,  List<String> args) {
 321                         noOverview = true;
 322                         if (overviewPath != null) {
 323                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 324                                     "-nooverview", "-overview"));
 325                             return false;
 326                         }
 327                         return true;
 328                     }
 329                 },
 330 
 331                 new Option(resources, "-notree") {
 332                     @Override
 333                     public boolean process(String opt,  List<String> args) {
 334                         createTree = false;
 335                         return true;
 336                     }
 337                 },
 338 
 339                 new Option(resources, "-overview", 1) {
 340                     @Override
 341                     public boolean process(String opt,  List<String> args) {
 342                         overviewPath = args.get(0);
 343                         if (noOverview) {
 344                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 345                                     "-overview", "-nooverview"));
 346                             return false;
 347                         }
 348                         return true;
 349                     }
 350                 },
 351 
 352                 new Hidden(resources, "-packagesheader", 1) {
 353                     @Override
 354                     public boolean process(String opt,  List<String> args) {
 355                         packagesHeader = args.get(0);
 356                         return true;
 357                     }
 358                 },
 359 
 360                 new Option(resources, "-splitindex") {
 361                     @Override
 362                     public boolean process(String opt, List<String> args) {
 363                         splitIndex = true;
 364                         if (!createIndex) {
 365                             reporter.print(ERROR, resources.getText("doclet.Option_conflict",
 366                                     "-splitindex", "-noindex"));
 367                             return false;
 368                         }
 369                         return true;
 370                     }
 371                 },
 372 
 373                 new Option(resources, "--main-stylesheet -stylesheetfile", 1) {
 374                     @Override
 375                     public boolean process(String opt,  List<String> args) {
 376                         stylesheetFile = args.get(0);
 377                         return true;
 378                     }
 379                 },
 380 
 381                 new Option(resources, "-top", 1) {
 382                     @Override
 383                     public boolean process(String opt,  List<String> args) {
 384                         top = args.get(0);
 385                         return true;
 386                     }
 387                 },
 388 
 389                 new Option(resources, "-use") {
 390                     @Override
 391                     public boolean process(String opt,  List<String> args) {
 392                         classUse = true;
 393                         return true;
 394                     }
 395                 },
 396 
 397                 new Option(resources, "-windowtitle", 1) {
 398                     @Override
 399                     public boolean process(String opt,  List<String> args) {
 400                         windowTitle = args.get(0).replaceAll("<.*?>", "");
 401                         return true;
 402                     }
 403                 },
 404 
 405                 new XOption(resources, "-Xdoclint") {
 406                     @Override
 407                     public boolean process(String opt,  List<String> args) {
 408                         doclintOpts.put(this, DocLint.XMSGS_OPTION);
 409                         return true;
 410                     }
 411                 },
 412 
 413                 new XOption(resources, "-Xdocrootparent", 1) {
 414                     @Override
 415                     public boolean process(String opt, List<String> args) {
 416                         docrootParent = args.get(0);
 417                         try {
 418                             new URL(docrootParent);
 419                         } catch (MalformedURLException e) {
 420                             reporter.print(ERROR, resources.getText("doclet.MalformedURL", docrootParent));
 421                             return false;
 422                         }
 423                         return true;
 424                     }
 425                 },
 426 
 427                 new XOption(resources, "doclet.usage.xdoclint-extended", "-Xdoclint:", 0) {
 428                     @Override
 429                     public boolean process(String opt,  List<String> args) {
 430                         String dopt = opt.replace("-Xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX);
 431                         doclintOpts.put(this, dopt);
 432                         if (dopt.contains("/")) {
 433                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_no_qualifiers"));
 434                             return false;
 435                         }
 436                         if (!DocLint.isValidOption(dopt)) {
 437                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_invalid_arg"));
 438                             return false;
 439                         }
 440                         return true;
 441                     }
 442                 },
 443 
 444                 new XOption(resources, "doclet.usage.xdoclint-package", "-Xdoclint/package:", 0) {
 445                     @Override
 446                     public boolean process(String opt,  List<String> args) {
 447                         String dopt = opt.replace("-Xdoclint/package:", DocLint.XCHECK_PACKAGE);
 448                         doclintOpts.put(this, dopt);
 449                         if (!DocLint.isValidOption(dopt)) {
 450                             reporter.print(ERROR, resources.getText("doclet.Option_doclint_package_invalid_arg"));
 451                             return false;
 452                         }
 453                         return true;
 454                     }
 455                 },
 456 
 457                 new XOption(resources, "--no-frames") {
 458                     @Override
 459                     public boolean process(String opt, List<String> args) {
 460                         reporter.print(WARNING, resources.getText("doclet.NoFrames_specified"));
 461                         return true;
 462                     }
 463                 }
 464         );
 465         Set<BaseOptions.Option> allOptions = new TreeSet<>();
 466         allOptions.addAll(options);
 467         allOptions.addAll(super.getSupportedOptions());
 468         return allOptions;
 469     }
 470 
 471     protected boolean validateOptions() {
 472         // check shared options
 473         if (!generalValidOptions()) {
 474             return false;
 475         }
 476 
 477         Resources resources = config.getResources();
 478         Reporter reporter = config.getReporter();
 479 
 480         // check if helpfile exists
 481         if (!helpFile.isEmpty()) {
 482             DocFile help = DocFile.createFileForInput(config, helpFile);
 483             if (!help.exists()) {
 484                 reporter.print(ERROR, resources.getText("doclet.File_not_found", helpFile));
 485                 return false;
 486             }
 487         }
 488         // check if stylesheetFile exists
 489         if (!stylesheetFile.isEmpty()) {
 490             DocFile stylesheet = DocFile.createFileForInput(config, stylesheetFile);
 491             if (!stylesheet.exists()) {
 492                 reporter.print(ERROR, resources.getText("doclet.File_not_found", stylesheetFile));
 493                 return false;
 494             }
 495         }
 496         // check if additional stylesheets exists
 497         for (String ssheet : additionalStylesheets) {
 498             DocFile ssfile = DocFile.createFileForInput(config, ssheet);
 499             if (!ssfile.exists()) {
 500                 reporter.print(ERROR, resources.getText("doclet.File_not_found", ssheet));
 501                 return false;
 502             }
 503         }
 504 
 505         // In a more object-oriented world, this would be done by methods on the Option objects.
 506         // Note that -windowtitle silently removes any and all HTML elements, and so does not need
 507         // to be handled here.
 508         Utils utils = config.utils;
 509         utils.checkJavaScriptInOption("-header", header);
 510         utils.checkJavaScriptInOption("-footer", footer);
 511         utils.checkJavaScriptInOption("-top", top);
 512         utils.checkJavaScriptInOption("-bottom", bottom);
 513         utils.checkJavaScriptInOption("-doctitle", docTitle);
 514         utils.checkJavaScriptInOption("-packagesheader", packagesHeader);
 515 
 516         return true;
 517     }
 518 
 519 }