001/*
002 * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package org.jdrupes.mdoclet.internal.doclets.formats.html;
027
028import java.net.MalformedURLException;
029import java.net.URL;
030import java.util.ArrayList;
031import java.util.List;
032import java.util.Set;
033import java.util.TreeSet;
034
035import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseOptions;
036import org.jdrupes.mdoclet.internal.doclets.toolkit.Messages;
037import org.jdrupes.mdoclet.internal.doclets.toolkit.Resources;
038import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFile;
039import org.jdrupes.mdoclet.internal.doclets.toolkit.util.Utils;
040import org.jdrupes.mdoclet.internal.doclint.DocLint;
041
042/**
043 * Storage for all options supported by the
044 * {@link jdk.javadoc.doclet.StandardDoclet standard doclet},
045 * including the format-independent options handled
046 * by {@link BaseOptions}.
047 *
048 * <p>Some of the methods used to access the values of options
049 * have names that begin with a verb, such as {@link #createOverview}
050 * or {@link #splitIndex}. Unless otherwise stated,
051 * these methods should all be taken as just accessing the value
052 * of the associated option.
053 *
054 */
055public class HtmlOptions extends BaseOptions {
056    // <editor-fold desc="Option values">
057    /**
058     * Argument for command-line option {@code --add-stylesheet}.
059     */
060    private List<String> additionalStylesheets = new ArrayList<>();
061
062    /**
063     * Argument for command-line option {@code --add-script}.
064     */
065    private List<String> additionalScripts = new ArrayList<>();
066
067    /**
068     * Argument for command-line option {@code -bottom}.
069     */
070    private String bottom = "";
071
072    /**
073     * Argument for command-line option {@code -charset}.
074     * The META charset tag used for cross-platform viewing.
075     */
076    private String charset = null;
077
078    /**
079     * Argument for command-line option {@code -use}.
080     * True if command-line option "-use" is used. Default value is false.
081     */
082    private boolean classUse = false;
083
084    /**
085     * Argument for command-line option {@code -noindex}.
086     * False if command-line option "-noindex" is used. Default value is true.
087     */
088    private boolean createIndex = true;
089
090    /**
091     * Argument for command-line option {@code -overview}.
092     * This is true if option "-overview" is used or option "-overview" is not
093     * used and number of packages is more than one.
094     */
095    private boolean createOverview = false;
096
097    /**
098     * Argument for command-line option {@code -notree}.
099     * False if command-line option "-notree" is used. Default value is true.
100     */
101    private boolean createTree = true;
102
103    /**
104     * Arguments for command-line option {@code -Xdoclint} and friends.
105     * Collected set of doclint options.
106     */
107    private List<String> doclintOpts = new ArrayList<>();
108
109    /**
110     * Argument for command-line option {@code -Xdocrootparent}.
111     */
112    private String docrootParent = "";
113
114    /**
115     * Argument for command-line option {@code -doctitle}.
116     */
117    private String docTitle = "";
118
119    /**
120     * Argument for command-line option {@code -header}.
121     */
122    private String header = "";
123
124    /**
125     * Argument for command-line option {@code -helpfile}.
126     */
127    private String helpFile = "";
128
129    /**
130     * Argument for command-line option {@code --legal-notices}.
131     */
132    private String legalNotices = "";
133
134    /**
135     * Argument for command-line option {@code -nodeprecatedlist}.
136     * True if command-line option "-nodeprecatedlist" is used. Default value is
137     * false.
138     */
139    private boolean noDeprecatedList = false;
140
141    /**
142     * Argument for command-line option {@code --no-external-spec-page}.
143     * True if command-line option "--no-external-spec-page" is used. Default value is
144     * false.
145     */
146    private boolean noExternalSpecsPage = false;
147
148    /**
149     * Argument for command-line option {@code -nohelp}.
150     * True if command-line option "-nohelp" is used. Default value is false.
151     */
152    private boolean noHelp = false;
153
154    /**
155     * Argument for command-line option {@code -nonavbar}.
156     * True if command-line option "-nonavbar" is used. Default value is false.
157     */
158    private boolean noNavbar = false;
159
160    /**
161     * Argument for command-line option {@code -nooverview}.
162     * True if command-line option "-nooverview" is used. Default value is
163     * false
164     */
165    private boolean noOverview = false;
166
167    /**
168     * Argument for command-line option {@code -overview}.
169     * The overview path specified with "-overview" flag.
170     */
171    private String overviewPath = null;
172
173    /**
174     * Argument for command-line option {@code -packagesheader}.
175     */
176    private String packagesHeader = "";
177
178    /**
179     * Argument for command-line option {@code -splitindex}.
180     * True if command-line option "-splitindex" is used. Default value is
181     * false.
182     */
183    private boolean splitIndex = false;
184
185    /**
186     * Argument for command-line option {@code -stylesheetfile}.
187     */
188    private String stylesheetFile = "";
189
190    /**
191     * Argument for command-line option {@code -top}.
192     */
193    private String top = "";
194
195    /**
196     * Argument for command-line option {@code -windowtitle}.
197     */
198    private String windowTitle = "";
199    // </editor-fold>
200
201    private HtmlConfiguration config;
202
203    HtmlOptions(HtmlConfiguration config) {
204        super(config);
205        this.config = config;
206    }
207
208    @Override
209    public Set<? extends Option> getSupportedOptions() {
210        Messages messages = config.getMessages();
211        Resources resources = messages.getResources();
212
213        List<Option> options = List.of(
214            new Option(resources, "--add-script", 1) {
215                @Override
216                public boolean process(String opt, List<String> args) {
217                    additionalScripts.add(args.get(0));
218                    return true;
219                }
220            },
221
222            new Option(resources, "--add-stylesheet", 1) {
223                @Override
224                public boolean process(String opt, List<String> args) {
225                    additionalStylesheets.add(args.get(0));
226                    return true;
227                }
228            },
229
230            new Option(resources, "-bottom", 1) {
231                @Override
232                public boolean process(String opt, List<String> args) {
233                    bottom = args.get(0);
234                    return true;
235                }
236            },
237
238            new Option(resources, "-charset", 1) {
239                @Override
240                public boolean process(String opt, List<String> args) {
241                    charset = args.get(0);
242                    return true;
243                }
244            },
245
246            new Option(resources, "-doctitle", 1) {
247                @Override
248                public boolean process(String opt, List<String> args) {
249                    docTitle = args.get(0);
250                    return true;
251                }
252            },
253
254            new Option(resources, "-footer", 1) {
255                @Override
256                public boolean process(String opt, List<String> args) {
257                    messages.warning("doclet.footer_specified");
258                    return true;
259                }
260            },
261
262            new Option(resources, "-header", 1) {
263                @Override
264                public boolean process(String opt, List<String> args) {
265                    header = args.get(0);
266                    return true;
267                }
268            },
269
270            new Option(resources, "-helpfile", 1) {
271                @Override
272                public boolean process(String opt, List<String> args) {
273                    if (noHelp) {
274                        messages.error("doclet.Option_conflict", "-helpfile",
275                            "-nohelp");
276                        return false;
277                    }
278                    if (!helpFile.isEmpty()) {
279                        messages.error("doclet.Option_reuse", "-helpfile");
280                        return false;
281                    }
282                    helpFile = args.get(0);
283                    return true;
284                }
285            },
286
287            new Option(resources, "-html5") {
288                @Override
289                public boolean process(String opt, List<String> args) {
290                    return true;
291                }
292            },
293
294            new XOption(resources, "--legal-notices", 1) {
295                @Override
296                public boolean process(String opt, List<String> args) {
297                    legalNotices = args.get(0);
298                    return true;
299                }
300            },
301
302            new Option(resources, "-nohelp") {
303                @Override
304                public boolean process(String opt, List<String> args) {
305                    noHelp = true;
306                    if (!helpFile.isEmpty()) {
307                        messages.error("doclet.Option_conflict", "-nohelp",
308                            "-helpfile");
309                        return false;
310                    }
311                    return true;
312                }
313            },
314
315            new Option(resources, "-nodeprecatedlist") {
316                @Override
317                public boolean process(String opt, List<String> args) {
318                    noDeprecatedList = true;
319                    return true;
320                }
321            },
322
323            new Option(resources, "-noindex") {
324                @Override
325                public boolean process(String opt, List<String> args) {
326                    createIndex = false;
327                    if (splitIndex) {
328                        messages.error("doclet.Option_conflict", "-noindex",
329                            "-splitindex");
330                        return false;
331                    }
332                    return true;
333                }
334            },
335
336            new Option(resources, "-nonavbar") {
337                @Override
338                public boolean process(String opt, List<String> args) {
339                    noNavbar = true;
340                    return true;
341                }
342            },
343
344            new Hidden(resources, "-nooverview") {
345                @Override
346                public boolean process(String opt, List<String> args) {
347                    noOverview = true;
348                    if (overviewPath != null) {
349                        messages.error("doclet.Option_conflict", "-nooverview",
350                            "-overview");
351                        return false;
352                    }
353                    return true;
354                }
355            },
356
357            new Hidden(resources, "--no-external-specs-page") {
358                @Override
359                public boolean process(String opt, List<String> args) {
360                    noExternalSpecsPage = true;
361                    return true;
362                }
363            },
364
365            new Option(resources, "-notree") {
366                @Override
367                public boolean process(String opt, List<String> args) {
368                    createTree = false;
369                    return true;
370                }
371            },
372
373            new Option(resources, "-overview", 1) {
374                @Override
375                public boolean process(String opt, List<String> args) {
376                    overviewPath = args.get(0);
377                    if (noOverview) {
378                        messages.error("doclet.Option_conflict", "-overview",
379                            "-nooverview");
380                        return false;
381                    }
382                    return true;
383                }
384            },
385
386            new Hidden(resources, "-packagesheader", 1) {
387                @Override
388                public boolean process(String opt, List<String> args) {
389                    packagesHeader = args.get(0);
390                    return true;
391                }
392            },
393
394            new Option(resources, "-splitindex") {
395                @Override
396                public boolean process(String opt, List<String> args) {
397                    splitIndex = true;
398                    if (!createIndex) {
399                        messages.error("doclet.Option_conflict", "-splitindex",
400                            "-noindex");
401                        return false;
402                    }
403                    return true;
404                }
405            },
406
407            new Option(resources, "--main-stylesheet -stylesheetfile", 1) {
408                @Override
409                public boolean process(String opt, List<String> args) {
410                    stylesheetFile = args.get(0);
411                    return true;
412                }
413            },
414
415            new Option(resources, "-top", 1) {
416                @Override
417                public boolean process(String opt, List<String> args) {
418                    top = args.get(0);
419                    return true;
420                }
421            },
422
423            new Option(resources, "-use") {
424                @Override
425                public boolean process(String opt, List<String> args) {
426                    classUse = true;
427                    return true;
428                }
429            },
430
431            new Option(resources, "-windowtitle", 1) {
432                @Override
433                public boolean process(String opt, List<String> args) {
434                    windowTitle = args.get(0).replaceAll("<.*?>", "");
435                    return true;
436                }
437            },
438
439            new XOption(resources, "-Xdoclint") {
440                @Override
441                public boolean process(String opt, List<String> args) {
442                    doclintOpts.add(DocLint.XMSGS_OPTION);
443                    return true;
444                }
445            },
446
447            new XOption(resources, "doclet.usage.xdoclint-extended",
448                "-Xdoclint:", 0) {
449                @Override
450                public boolean process(String opt, List<String> args) {
451                    String dopt = opt.replace("-Xdoclint:",
452                        DocLint.XMSGS_CUSTOM_PREFIX);
453                    if (dopt.contains("/")) {
454                        messages.error("doclet.Option_doclint_no_qualifiers");
455                        return false;
456                    }
457                    if (!(new DocLint()).isValidOption(dopt)) {
458                        messages.error("doclet.Option_doclint_invalid_arg");
459                        return false;
460                    }
461                    doclintOpts.add(dopt);
462                    return true;
463                }
464            },
465
466            new XOption(resources, "doclet.usage.xdoclint-package",
467                "-Xdoclint/package:", 0) {
468                @Override
469                public boolean process(String opt, List<String> args) {
470                    String dopt = opt.replace("-Xdoclint/package:",
471                        DocLint.XCHECK_PACKAGE);
472                    if (!(new DocLint()).isValidOption(dopt)) {
473                        messages
474                            .error("doclet.Option_doclint_package_invalid_arg");
475                        return false;
476                    }
477                    doclintOpts.add(dopt);
478                    return true;
479                }
480            },
481
482            new XOption(resources, "-Xdocrootparent", 1) {
483                @Override
484                public boolean process(String opt, List<String> args) {
485                    docrootParent = args.get(0);
486                    try {
487                        @SuppressWarnings("deprecation")
488                        var _unused = new URL(docrootParent);
489                    } catch (MalformedURLException e) {
490                        messages.error("doclet.MalformedURL", docrootParent);
491                        return false;
492                    }
493                    return true;
494                }
495            },
496
497            new XOption(resources, "--no-frames") {
498                @Override
499                public boolean process(String opt, List<String> args) {
500                    messages.warning("doclet.NoFrames_specified");
501                    return true;
502                }
503            });
504        Set<BaseOptions.Option> allOptions = new TreeSet<>();
505        allOptions.addAll(options);
506        allOptions.addAll(super.getSupportedOptions());
507        return allOptions;
508    }
509
510    protected boolean validateOptions() {
511        // check shared options
512        if (!generalValidOptions()) {
513            return false;
514        }
515
516        Messages messages = config.getMessages();
517
518        // check if helpfile exists
519        if (!helpFile.isEmpty()) {
520            DocFile help = DocFile.createFileForInput(config, helpFile);
521            if (!help.exists()) {
522                messages.error("doclet.File_not_found", helpFile);
523                return false;
524            }
525        }
526        // check if stylesheetFile exists
527        if (!stylesheetFile.isEmpty()) {
528            DocFile stylesheet
529                = DocFile.createFileForInput(config, stylesheetFile);
530            if (!stylesheet.exists()) {
531                messages.error("doclet.File_not_found", stylesheetFile);
532                return false;
533            }
534        }
535        // check if additional stylesheets exists
536        for (String ssheet : additionalStylesheets) {
537            DocFile ssfile = DocFile.createFileForInput(config, ssheet);
538            if (!ssfile.exists()) {
539                messages.error("doclet.File_not_found", ssheet);
540                return false;
541            }
542        }
543        // check if additional scripts exists
544        for (String script : additionalScripts) {
545            DocFile sfile = DocFile.createFileForInput(config, script);
546            if (!sfile.exists()) {
547                messages.error("doclet.File_not_found", script);
548                return false;
549            }
550        }
551        // In a more object-oriented world, this would be done by methods on the
552        // Option objects.
553        // Note that -windowtitle silently removes any and all HTML elements,
554        // and so does not need
555        // to be handled here.
556        Utils utils = config.utils;
557        utils.checkJavaScriptInOption("-header", header);
558        utils.checkJavaScriptInOption("-top", top);
559        utils.checkJavaScriptInOption("-bottom", bottom);
560        utils.checkJavaScriptInOption("-doctitle", docTitle);
561        utils.checkJavaScriptInOption("-packagesheader", packagesHeader);
562
563        return true;
564    }
565
566    /**
567     * Argument for command-line option {@code --add-script}.
568     */
569    List<String> additionalScripts() {
570        return additionalScripts;
571    }
572
573    /**
574     * Argument for command-line option {@code --add-stylesheet}.
575     */
576    List<String> additionalStylesheets() {
577        return additionalStylesheets;
578    }
579
580    /**
581     * Argument for command-line option {@code -bottom}.
582     */
583    String bottom() {
584        return bottom;
585    }
586
587    /**
588     * Argument for command-line option {@code -charset}.
589     * The META charset tag used for cross-platform viewing.
590     */
591    String charset() {
592        return charset;
593    }
594
595    void setCharset(String charset) {
596        this.charset = charset;
597    }
598
599    /**
600     * Argument for command-line option {@code -use}.
601     * True if command-line option "-use" is used. Default value is false.
602     */
603    public boolean classUse() {
604        return classUse;
605    }
606
607    /**
608     * Argument for command-line option {@code -noindex}.
609     * False if command-line option "-noindex" is used. Default value is true.
610     */
611    public boolean createIndex() {
612        return createIndex;
613    }
614
615    /**
616     * Argument for command-line option {@code -overview}.
617     * This is true if option "-overview" is used or option "-overview" is not
618     * used and number of packages is more than one.
619     */
620    public boolean createOverview() {
621        return createOverview;
622    }
623
624    public void setCreateOverview(boolean createOverview) {
625        this.createOverview = createOverview;
626    }
627
628    /**
629     * Argument for command-line option {@code -notree}.
630     * False if command-line option "-notree" is used. Default value is true.
631     */
632    public boolean createTree() {
633        return createTree;
634    }
635
636    /**
637     * Arguments for command-line option {@code -Xdoclint} and friends.
638     * Collected set of doclint options.
639     */
640    List<String> doclintOpts() {
641        return doclintOpts;
642    }
643
644    /**
645     * Argument for command-line option {@code -Xdocrootparent}.
646     */
647    String docrootParent() {
648        return docrootParent;
649    }
650
651    /**
652     * Argument for command-line option {@code -doctitle}.
653     */
654    String docTitle() {
655        return docTitle;
656    }
657
658    /**
659     * Argument for command-line option {@code -header}.
660     */
661    String header() {
662        return header;
663    }
664
665    /**
666     * Argument for command-line option {@code -helpfile}.
667     */
668    public String helpFile() {
669        return helpFile;
670    }
671
672    /**
673     * Argument for command-line option {@code --legal-notices}.
674     */
675    public String legalNotices() {
676        return legalNotices;
677    }
678
679    /**
680     * Argument for command-line option {@code -nodeprecated}.
681     * True if command-line option "-nodeprecated" is used. Default value is
682     * false.
683     */
684    public boolean noDeprecatedList() {
685        return noDeprecatedList;
686    }
687
688    /**
689     * Argument for command-line option {@code --no-external-specs-page}.
690     * True if command-line option "--no-external-specs-page" is used. Default value is
691     * false.
692     */
693    public boolean noExternalSpecsPage() {
694        return noExternalSpecsPage;
695    }
696
697    /**
698     * Argument for command-line option {@code -nohelp}.
699     * True if command-line option "-nohelp" is used. Default value is false.
700     */
701    public boolean noHelp() {
702        return noHelp;
703    }
704
705    /**
706     * Argument for command-line option {@code -nonavbar}.
707     * True if command-line option "-nonavbar" is used. Default value is false.
708     */
709    public boolean noNavbar() {
710        return noNavbar;
711    }
712
713    /**
714     * Argument for command-line option {@code -nooverview}.
715     * True if command-line option "-nooverview" is used. Default value is
716     * false
717     */
718    boolean noOverview() {
719        return noOverview;
720    }
721
722    /**
723     * Argument for command-line option {@code -overview}.
724     * The overview path specified with "-overview" flag.
725     */
726    String overviewPath() {
727        return overviewPath;
728    }
729
730    /**
731     * Argument for command-line option {@code -packagesheader}.
732     */
733    String packagesHeader() {
734        return packagesHeader;
735    }
736
737    /**
738     * Argument for command-line option {@code -splitindex}.
739     * True if command-line option "-splitindex" is used. Default value is
740     * false.
741     */
742    public boolean splitIndex() {
743        return splitIndex;
744    }
745
746    /**
747     * Argument for command-line option {@code -stylesheetfile}.
748     */
749    String stylesheetFile() {
750        return stylesheetFile;
751    }
752
753    /**
754     * Argument for command-line option {@code -top}.
755     */
756    String top() {
757        return top;
758    }
759
760    /**
761     * Argument for command-line option {@code -windowtitle}.
762     */
763    String windowTitle() {
764        return windowTitle;
765    }
766}