1 /*
   2  * Copyright (c) 1998, 2017, 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.*;
  29 import java.util.*;
  30 
  31 import javax.lang.model.element.Element;
  32 import javax.lang.model.element.PackageElement;
  33 import javax.lang.model.element.TypeElement;
  34 import javax.tools.JavaFileManager;
  35 import javax.tools.JavaFileObject;
  36 import javax.tools.StandardJavaFileManager;
  37 
  38 import com.sun.source.util.DocTreePath;
  39 import com.sun.tools.doclint.DocLint;
  40 
  41 import jdk.javadoc.doclet.Doclet;
  42 import jdk.javadoc.doclet.DocletEnvironment;
  43 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
  44 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
  45 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlVersion;
  46 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
  47 import jdk.javadoc.internal.doclets.toolkit.Content;
  48 import jdk.javadoc.internal.doclets.toolkit.DocletException;
  49 import jdk.javadoc.internal.doclets.toolkit.Messages;
  50 import jdk.javadoc.internal.doclets.toolkit.Resources;
  51 import jdk.javadoc.internal.doclets.toolkit.WriterFactory;
  52 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
  53 import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
  54 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
  55 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  56 
  57 import static javax.tools.Diagnostic.Kind.*;
  58 
  59 /**
  60  * Configure the output based on the command line options.
  61  * <p>
  62  * Also determine the length of the command line option. For example,
  63  * for a option "-header" there will be a string argument associated, then the
  64  * the length of option "-header" is two. But for option "-nohelp" no argument
  65  * is needed so it's length is 1.
  66  * </p>
  67  * <p>
  68  * Also do the error checking on the options used. For example it is illegal to
  69  * use "-helpfile" option when already "-nohelp" option is used.
  70  * </p>
  71  *
  72  *  <p><b>This is NOT part of any supported API.
  73  *  If you write code that depends on this, you do so at your own risk.
  74  *  This code and its internal interfaces are subject to change or
  75  *  deletion without notice.</b>
  76  *
  77  * @author Robert Field.
  78  * @author Atul Dambalkar.
  79  * @author Jamie Ho
  80  * @author Bhavesh Patel (Modified)
  81  */
  82 public class HtmlConfiguration extends BaseConfiguration {
  83 
  84     /**
  85      * The build date.  Note: For now, we will use
  86      * a version number instead of a date.
  87      */
  88     public static final String BUILD_DATE = System.getProperty("java.version");
  89 
  90     /**
  91      * Argument for command line option "-header".
  92      */
  93     public String header = "";
  94 
  95     /**
  96      * Argument for command line option "-packagesheader".
  97      */
  98     public String packagesheader = "";
  99 
 100     /**
 101      * Argument for command line option "-footer".
 102      */
 103     public String footer = "";
 104 
 105     /**
 106      * Argument for command line option "-doctitle".
 107      */
 108     public String doctitle = "";
 109 
 110     /**
 111      * Argument for command line option "-windowtitle".
 112      */
 113     public String windowtitle = "";
 114 
 115     /**
 116      * Argument for command line option "-top".
 117      */
 118     public String top = "";
 119 
 120     /**
 121      * Argument for command line option "-bottom".
 122      */
 123     public String bottom = "";
 124 
 125     /**
 126      * Argument for command line option "-helpfile".
 127      */
 128     public String helpfile = "";
 129 
 130     /**
 131      * Argument for command line option "-stylesheetfile".
 132      */
 133     public String stylesheetfile = "";
 134 
 135     /**
 136      * Argument for command line option "-Xdocrootparent".
 137      */
 138     public String docrootparent = "";
 139 
 140     /**
 141      * True if command line option "-nohelp" is used. Default value is false.
 142      */
 143     public boolean nohelp = false;
 144 
 145     /**
 146      * True if command line option "-splitindex" is used. Default value is
 147      * false.
 148      */
 149     public boolean splitindex = false;
 150 
 151     /**
 152      * False if command line option "-noindex" is used. Default value is true.
 153      */
 154     public boolean createindex = true;
 155 
 156     /**
 157      * True if command line option "-use" is used. Default value is false.
 158      */
 159     public boolean classuse = false;
 160 
 161     /**
 162      * False if command line option "-notree" is used. Default value is true.
 163      */
 164     public boolean createtree = true;
 165 
 166     /**
 167      * The META charset tag used for cross-platform viewing.
 168      */
 169     public String charset = null;
 170 
 171     /**
 172      * True if command line option "-nodeprecated" is used. Default value is
 173      * false.
 174      */
 175     public boolean nodeprecatedlist = false;
 176 
 177     /**
 178      * True if command line option "-nonavbar" is used. Default value is false.
 179      */
 180     public boolean nonavbar = false;
 181 
 182     /**
 183      * True if command line option "-nooverview" is used. Default value is
 184      * false
 185      */
 186     private boolean nooverview = false;
 187 
 188     /**
 189      * The overview path specified with "-overview" flag.
 190      */
 191     public String overviewpath = null;
 192 
 193     /**
 194      * This is true if option "-overview" is used or option "-overview" is not
 195      * used and number of packages is more than one.
 196      */
 197     public boolean createoverview = false;
 198 
 199     /**
 200      * Specifies whether or not frames should be generated.
 201      * Defaults to true; can be set by --frames; can be set to false by --no-frames; last one wins.
 202      */
 203     public boolean frames = true;
 204 
 205     /**
 206      * This is the HTML version of the generated pages. HTML 4.01 is the default output version.
 207      */
 208     public HtmlVersion htmlVersion = HtmlVersion.HTML4;
 209 
 210     /**
 211      * Collected set of doclint options
 212      */
 213     public Map<Doclet.Option, String> doclintOpts = new LinkedHashMap<>();
 214 
 215     public final Resources resources;
 216 
 217     /**
 218      * First file to appear in the right-hand frame in the generated
 219      * documentation.
 220      */
 221     public DocPath topFile = DocPath.empty;
 222 
 223     /**
 224      * The TypeElement for the class file getting generated.
 225      */
 226     public TypeElement currentTypeElement = null;  // Set this TypeElement in the ClassWriter.
 227 
 228     protected List<SearchIndexItem> memberSearchIndex = new ArrayList<>();
 229 
 230     protected List<SearchIndexItem> moduleSearchIndex = new ArrayList<>();
 231 
 232     protected List<SearchIndexItem> packageSearchIndex = new ArrayList<>();
 233 
 234     protected SortedSet<SearchIndexItem> tagSearchIndex = new TreeSet<>(makeSearchTagComparator());
 235 
 236     protected List<SearchIndexItem> typeSearchIndex = new ArrayList<>();
 237 
 238     protected Map<Character,List<SearchIndexItem>> tagSearchIndexMap = new HashMap<>();
 239 
 240     protected Set<Character> tagSearchIndexKeys;
 241 
 242     protected Contents contents;
 243 
 244     protected Messages messages;
 245 
 246     /**
 247      * Constructor. Initializes resource for the
 248      * {@link jdk.javadoc.internal.tool.Messager Messager}.
 249      */
 250     public HtmlConfiguration(Doclet doclet) {
 251         super(doclet);
 252         resources = new Resources(this,
 253                 BaseConfiguration.sharedResourceBundleName,
 254                 "jdk.javadoc.internal.doclets.formats.html.resources.standard");
 255 
 256         messages = new Messages(this);
 257         contents = new Contents(this);
 258     }
 259 
 260     private final String versionRBName = "jdk.javadoc.internal.tool.resources.version";
 261     private ResourceBundle versionRB;
 262 
 263     /**
 264      * Return the build date for the doclet.
 265      * @return the build date
 266      */
 267     @Override
 268     public String getDocletSpecificBuildDate() {
 269         if (versionRB == null) {
 270             try {
 271                 versionRB = ResourceBundle.getBundle(versionRBName, getLocale());
 272             } catch (MissingResourceException e) {
 273                 return BUILD_DATE;
 274             }
 275         }
 276 
 277         try {
 278             return versionRB.getString("release");
 279         } catch (MissingResourceException e) {
 280             return BUILD_DATE;
 281         }
 282     }
 283 
 284     @Override
 285     public Resources getResources() {
 286         return resources;
 287     }
 288 
 289     @Override
 290     public Messages getMessages() {
 291         return messages;
 292     }
 293 
 294     protected boolean validateOptions() {
 295         // check shared options
 296         if (!generalValidOptions()) {
 297             return false;
 298         }
 299         // check if helpfile exists
 300         if (!helpfile.isEmpty()) {
 301             DocFile help = DocFile.createFileForInput(this, helpfile);
 302             if (!help.exists()) {
 303                 reporter.print(ERROR, getText("doclet.File_not_found", helpfile));
 304                 return false;
 305             }
 306         }
 307 
 308         // In a more object-oriented world, this would be done by methods on the Option objects.
 309         // Note that -windowtitle silently removes any and all HTML elements, and so does not need
 310         // to be handled here.
 311         utils.checkJavaScriptInOption("-header", header);
 312         utils.checkJavaScriptInOption("-footer", footer);
 313         utils.checkJavaScriptInOption("-top", top);
 314         utils.checkJavaScriptInOption("-bottom", bottom);
 315         utils.checkJavaScriptInOption("-doctitle", doctitle);
 316         utils.checkJavaScriptInOption("-packagesheader", packagesheader);
 317 
 318         return true;
 319     }
 320 
 321 
 322     @Override
 323     public boolean finishOptionSettings() {
 324         if (!validateOptions()) {
 325             return false;
 326         }
 327         if (!getSpecifiedTypeElements().isEmpty()) {
 328             Map<String, PackageElement> map = new HashMap<>();
 329             PackageElement pkg;
 330             for (TypeElement aClass : getIncludedTypeElements()) {
 331                 pkg = utils.containingPackage(aClass);
 332                 if (!map.containsKey(utils.getPackageName(pkg))) {
 333                     map.put(utils.getPackageName(pkg), pkg);
 334                 }
 335             }
 336         }
 337         setCreateOverview();
 338         setTopFile(docEnv);
 339         workArounds.initDocLint(doclintOpts.values(), tagletManager.getCustomTagNames(),
 340                 Utils.toLowerCase(htmlVersion.name()));
 341         return true;
 342     }
 343 
 344     /**
 345      * Return true if the generated output is HTML5.
 346      */
 347     public boolean isOutputHtml5() {
 348         return htmlVersion == HtmlVersion.HTML5;
 349     }
 350 
 351     /**
 352      * Return true if the tag is allowed for this specific version of HTML.
 353      */
 354     public boolean allowTag(HtmlTag htmlTag) {
 355         return htmlTag.allowTag(this.htmlVersion);
 356     }
 357 
 358     public Comparator<SearchIndexItem> makeSearchTagComparator() {
 359         return (SearchIndexItem sii1, SearchIndexItem sii2) -> {
 360             int result = (sii1.getLabel()).compareTo(sii2.getLabel());
 361             if (result == 0) {
 362                 result = (sii1.getHolder()).compareTo(sii2.getHolder());
 363             }
 364             return result;
 365         };
 366     }
 367 
 368     /**
 369      * Decide the page which will appear first in the right-hand frame. It will
 370      * be "overview-summary.html" if "-overview" option is used or no
 371      * "-overview" but the number of packages is more than one. It will be
 372      * "package-summary.html" of the respective package if there is only one
 373      * package to document. It will be a class page(first in the sorted order),
 374      * if only classes are provided on the command line.
 375      *
 376      * @param docEnv the doclet environment
 377      */
 378     protected void setTopFile(DocletEnvironment docEnv) {
 379         if (!checkForDeprecation(docEnv)) {
 380             return;
 381         }
 382         if (createoverview) {
 383             topFile = DocPaths.overviewSummary(frames);
 384         } else {
 385             if (showModules) {
 386                 topFile = DocPath.empty.resolve(DocPaths.moduleSummary(modules.first()));
 387             } else if (packages.size() == 1 && packages.first().isUnnamed()) {
 388                 List<TypeElement> classes = new ArrayList<>(getIncludedTypeElements());
 389                 if (!classes.isEmpty()) {
 390                     TypeElement te = getValidClass(classes);
 391                     topFile = DocPath.forClass(utils, te);
 392                 }
 393             } else if (!packages.isEmpty()) {
 394                 topFile = DocPath.forPackage(packages.first()).resolve(DocPaths.PACKAGE_SUMMARY);
 395             }
 396         }
 397     }
 398 
 399     protected TypeElement getValidClass(List<TypeElement> classes) {
 400         if (!nodeprecated) {
 401             return classes.get(0);
 402         }
 403         for (TypeElement te : classes) {
 404             if (!utils.isDeprecated(te)) {
 405                 return te;
 406             }
 407         }
 408         return null;
 409     }
 410 
 411     protected boolean checkForDeprecation(DocletEnvironment docEnv) {
 412         for (TypeElement te : getIncludedTypeElements()) {
 413             if (isGeneratedDoc(te)) {
 414                 return true;
 415             }
 416         }
 417         return false;
 418     }
 419 
 420     /**
 421      * Generate "overview.html" page if option "-overview" is used or number of
 422      * packages is more than one. Sets {@link #createoverview} field to true.
 423      */
 424     protected void setCreateOverview() {
 425         if ((overviewpath != null || packages.size() > 1) && !nooverview) {
 426             createoverview = true;
 427         }
 428     }
 429 
 430     /**
 431      * {@inheritDoc}
 432      */
 433     @Override
 434     public WriterFactory getWriterFactory() {
 435         return new WriterFactoryImpl(this);
 436     }
 437 
 438     /**
 439      * {@inheritDoc}
 440      */
 441     @Override
 442     public Locale getLocale() {
 443         if (locale == null)
 444             return Locale.getDefault();
 445         return locale;
 446     }
 447 
 448     /**
 449      * Return the path of the overview file or null if it does not exist.
 450      *
 451      * @return the path of the overview file or null if it does not exist.
 452      */
 453     @Override
 454     public JavaFileObject getOverviewPath() {
 455         if (overviewpath != null && getFileManager() instanceof StandardJavaFileManager) {
 456             StandardJavaFileManager fm = (StandardJavaFileManager) getFileManager();
 457             return fm.getJavaFileObjects(overviewpath).iterator().next();
 458         }
 459         return null;
 460     }
 461 
 462     /**
 463      * {@inheritDoc}
 464      */
 465     @Override
 466     public JavaFileManager getFileManager() {
 467         return docEnv.getJavaFileManager();
 468     }
 469 
 470     @Override
 471     public boolean showMessage(DocTreePath path, String key) {
 472         return (path == null || workArounds.haveDocLint());
 473     }
 474 
 475     @Override
 476     public boolean showMessage(Element e, String key) {
 477         return (e == null || workArounds.haveDocLint());
 478     }
 479 
 480     @Override
 481     public String getText(String key) {
 482         return resources.getText(key);
 483     }
 484 
 485     @Override
 486     public String getText(String key, String... args) {
 487         return resources.getText(key, (Object[]) args);
 488     }
 489 
 490    /**
 491      * {@inheritdoc}
 492      */
 493     @Override
 494     public Content getContent(String key) {
 495         return contents.getContent(key);
 496     }
 497 
 498     /**
 499      * Get the configuration string as a content.
 500      *
 501      * @param key the key to look for in the configuration file
 502      * @param o   string or content argument added to configuration text
 503      * @return a content tree for the text
 504      */
 505     @Override
 506     public Content getContent(String key, Object o) {
 507         return contents.getContent(key, o);
 508     }
 509 
 510     /**
 511      * Get the configuration string as a content.
 512      *
 513      * @param key the key to look for in the configuration file
 514      * @param o1 resource argument
 515      * @param o2 resource argument
 516      * @return a content tree for the text
 517      */
 518     @Override
 519     public Content getContent(String key, Object o1, Object o2) {
 520         return contents.getContent(key, o1, o2);
 521     }
 522 
 523     /**
 524      * Get the configuration string as a content.
 525      *
 526      * @param key the key to look for in the configuration file
 527      * @param o0  string or content argument added to configuration text
 528      * @param o1  string or content argument added to configuration text
 529      * @param o2  string or content argument added to configuration text
 530      * @return a content tree for the text
 531      */
 532     @Override
 533     public Content getContent(String key, Object o0, Object o1, Object o2) {
 534         return contents.getContent(key, o0, o1, o2);
 535     }
 536 
 537     protected void buildSearchTagIndex() {
 538         for (SearchIndexItem sii : tagSearchIndex) {
 539             String tagLabel = sii.getLabel();
 540             Character unicode = (tagLabel.length() == 0)
 541                     ? '*'
 542                     : Character.toUpperCase(tagLabel.charAt(0));
 543             List<SearchIndexItem> list = tagSearchIndexMap.get(unicode);
 544             if (list == null) {
 545                 list = new ArrayList<>();
 546                 tagSearchIndexMap.put(unicode, list);
 547             }
 548             list.add(sii);
 549         }
 550         tagSearchIndexKeys = tagSearchIndexMap.keySet();
 551     }
 552 
 553     @Override
 554     public Set<Doclet.Option> getSupportedOptions() {
 555         Resources resources = getResources();
 556         Doclet.Option[] options = {
 557             new Option(resources, "-bottom", 1) {
 558                 @Override
 559                 public boolean process(String opt,  List<String> args) {
 560                     bottom = args.get(0);
 561                     return true;
 562                 }
 563             },
 564             new Option(resources, "-charset", 1) {
 565                 @Override
 566                 public boolean process(String opt,  List<String> args) {
 567                     charset = args.get(0);
 568                     return true;
 569                 }
 570             },
 571             new Option(resources, "-doctitle", 1) {
 572                 @Override
 573                 public boolean process(String opt,  List<String> args) {
 574                     doctitle = args.get(0);
 575                     return true;
 576                 }
 577             },
 578             new Option(resources, "-footer", 1) {
 579                 @Override
 580                 public boolean process(String opt, List<String> args) {
 581                     footer = args.get(0);
 582                     return true;
 583                 }
 584             },
 585             new Option(resources, "-header", 1) {
 586                 @Override
 587                 public boolean process(String opt,  List<String> args) {
 588                     header = args.get(0);
 589                     return true;
 590                 }
 591             },
 592             new Option(resources, "-helpfile", 1) {
 593                 @Override
 594                 public boolean process(String opt,  List<String> args) {
 595                     if (nohelp == true) {
 596                         reporter.print(ERROR, getText("doclet.Option_conflict",
 597                                 "-helpfile", "-nohelp"));
 598                         return false;
 599                     }
 600                     if (!helpfile.isEmpty()) {
 601                         reporter.print(ERROR, getText("doclet.Option_reuse",
 602                                 "-helpfile"));
 603                         return false;
 604                     }
 605                     helpfile = args.get(0);
 606                     return true;
 607                 }
 608             },
 609             new Option(resources, "-html4") {
 610                 @Override
 611                 public boolean process(String opt,  List<String> args) {
 612                     htmlVersion = HtmlVersion.HTML4;
 613                     return true;
 614                 }
 615             },
 616             new Option(resources, "-html5") {
 617                 @Override
 618                 public boolean process(String opt,  List<String> args) {
 619                     htmlVersion = HtmlVersion.HTML5;
 620                     return true;
 621                 }
 622             },
 623             new Option(resources, "-nohelp") {
 624                 @Override
 625                 public boolean process(String opt, List<String> args) {
 626                     nohelp = true;
 627                     if (!helpfile.isEmpty()) {
 628                         reporter.print(ERROR, getText("doclet.Option_conflict",
 629                                 "-nohelp", "-helpfile"));
 630                         return false;
 631                     }
 632                     return true;
 633                 }
 634             },
 635             new Option(resources, "-nodeprecatedlist") {
 636                 @Override
 637                 public boolean process(String opt,  List<String> args) {
 638                     nodeprecatedlist = true;
 639                     return true;
 640                 }
 641             },
 642             new Option(resources, "-noindex") {
 643                 @Override
 644                 public boolean process(String opt,  List<String> args) {
 645                     createindex = false;
 646                     if (splitindex == true) {
 647                         reporter.print(ERROR, getText("doclet.Option_conflict",
 648                                 "-noindex", "-splitindex"));
 649                         return false;
 650                     }
 651                     return true;
 652                 }
 653             },
 654             new Option(resources, "-nonavbar") {
 655                 @Override
 656                 public boolean process(String opt,  List<String> args) {
 657                     nonavbar = true;
 658                     return true;
 659                 }
 660             },
 661             new Hidden(resources, "-nooverview") {
 662                 @Override
 663                 public boolean process(String opt,  List<String> args) {
 664                     nooverview = true;
 665                     if (overviewpath != null) {
 666                         reporter.print(ERROR, getText("doclet.Option_conflict",
 667                                 "-nooverview", "-overview"));
 668                         return false;
 669                     }
 670                     return true;
 671                 }
 672             },
 673             new Option(resources, "-notree") {
 674                 @Override
 675                 public boolean process(String opt,  List<String> args) {
 676                     createtree = false;
 677                     return true;
 678                 }
 679             },
 680             new Option(resources, "-overview", 1) {
 681                 @Override
 682                 public boolean process(String opt,  List<String> args) {
 683                     overviewpath = args.get(0);
 684                     if (nooverview == true) {
 685                         reporter.print(ERROR, getText("doclet.Option_conflict",
 686                                 "-overview", "-nooverview"));
 687                         return false;
 688                     }
 689                     return true;
 690                 }
 691             },
 692             new Option(resources, "--frames") {
 693                 @Override
 694                 public boolean process(String opt,  List<String> args) {
 695                     frames = true;
 696                     return true;
 697                 }
 698             },
 699             new Option(resources, "--no-frames") {
 700                 @Override
 701                 public boolean process(String opt,  List<String> args) {
 702                     frames = false;
 703                     return true;
 704                 }
 705             },
 706             new Hidden(resources, "-packagesheader", 1) {
 707                 @Override
 708                 public boolean process(String opt,  List<String> args) {
 709                     packagesheader = args.get(0);
 710                     return true;
 711                 }
 712             },
 713             new Option(resources, "-splitindex") {
 714                 @Override
 715                 public boolean process(String opt, List<String> args) {
 716                     splitindex = true;
 717                     if (createindex == false) {
 718                         reporter.print(ERROR, getText("doclet.Option_conflict",
 719                                 "-splitindex", "-noindex"));
 720                         return false;
 721                     }
 722                     return true;
 723                 }
 724             },
 725             new Option(resources, "-stylesheetfile", 1) {
 726                 @Override
 727                 public boolean process(String opt,  List<String> args) {
 728                     stylesheetfile = args.get(0);
 729                     return true;
 730                 }
 731             },
 732             new Option(resources, "-top", 1) {
 733                 @Override
 734                 public boolean process(String opt,  List<String> args) {
 735                     top = args.get(0);
 736                     return true;
 737                 }
 738             },
 739             new Option(resources, "-use") {
 740                 @Override
 741                 public boolean process(String opt,  List<String> args) {
 742                     classuse = true;
 743                     return true;
 744                 }
 745             },
 746             new Option(resources, "-windowtitle", 1) {
 747                 @Override
 748                 public boolean process(String opt,  List<String> args) {
 749                     windowtitle = args.get(0).replaceAll("\\<.*?>", "");
 750                     return true;
 751                 }
 752             },
 753             new XOption(resources, "-Xdoclint") {
 754                 @Override
 755                 public boolean process(String opt,  List<String> args) {
 756                     doclintOpts.put(this, DocLint.XMSGS_OPTION);
 757                     return true;
 758                 }
 759             },
 760             new XOption(resources, "-Xdocrootparent", 1) {
 761                 @Override
 762                 public boolean process(String opt, List<String> args) {
 763                     docrootparent = args.get(0);
 764                     try {
 765                         URL ignored = new URL(docrootparent);
 766                     } catch (MalformedURLException e) {
 767                         reporter.print(ERROR, getText("doclet.MalformedURL", docrootparent));
 768                         return false;
 769                     }
 770                     return true;
 771                 }
 772             },
 773             new XOption(resources, "doclet.usage.xdoclint-extended", "-Xdoclint:", 0) {
 774                 @Override
 775                 public boolean process(String opt,  List<String> args) {
 776                     String dopt = opt.replace("-Xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX);
 777                     doclintOpts.put(this, dopt);
 778                     if (dopt.contains("/")) {
 779                         reporter.print(ERROR, getText("doclet.Option_doclint_no_qualifiers"));
 780                         return false;
 781                     }
 782                     if (!DocLint.isValidOption(dopt)) {
 783                         reporter.print(ERROR, getText("doclet.Option_doclint_invalid_arg"));
 784                         return false;
 785                     }
 786                     return true;
 787                 }
 788             },
 789             new XOption(resources, "doclet.usage.xdoclint-package", "-Xdoclint/package:", 0) {
 790                 @Override
 791                 public boolean process(String opt,  List<String> args) {
 792                     String dopt = opt.replace("-Xdoclint/package:", DocLint.XCHECK_PACKAGE);
 793                     doclintOpts.put(this, dopt);
 794                     if (!DocLint.isValidOption(dopt)) {
 795                         reporter.print(ERROR, getText("doclet.Option_doclint_package_invalid_arg"));
 796                         return false;
 797                     }
 798                     return true;
 799                 }
 800             }
 801         };
 802         Set<Doclet.Option> oset = new TreeSet<>();
 803         oset.addAll(Arrays.asList(options));
 804         oset.addAll(super.getSupportedOptions());
 805         return oset;
 806     }
 807 
 808     @Override
 809     protected boolean finishOptionSettings0() throws DocletException {
 810         if (docencoding == null) {
 811             if (charset == null) {
 812                 docencoding = charset = (encoding == null) ? HtmlConstants.HTML_DEFAULT_CHARSET : encoding;
 813             } else {
 814                 docencoding = charset;
 815             }
 816         } else {
 817             if (charset == null) {
 818                 charset = docencoding;
 819             } else if (!charset.equals(docencoding)) {
 820                 reporter.print(ERROR, getText("doclet.Option_conflict", "-charset", "-docencoding"));
 821                 return false;
 822             }
 823         }
 824         return super.finishOptionSettings0();
 825     }
 826 }