MarkdownCli.java
/*
* Copyright © 2014-2025 The CTAN Team and individual authors
*
* This file is distributed under the 3-clause BSD license.
* See file LICENSE for details.
*/
package org.ctan.markup.markdown;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import lombok.NonNull;
/**
* This class provides the command line interface for the markdown renderer.
*
* @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
*/
public class MarkdownCli {
/**
* The field <code>EXIT_ERROR</code> contains the exit code for errors.
*/
private static final int EXIT_ERROR = -1;
/**
* The field <code>EXIT_OK</code> contains the exit code for success.
*/
private static final int EXIT_OK = 0;
/**
* The field <code>SYNOPSIS</code> contains the -h text.
*/
private static final String SYNOPSIS =
"java -jar [....jar] [-h] [-t title] [-s] [-i] "
+ "[[-f] infile] [-o outfile]";
/**
* This method provides the command line interface.
*
* @param argv the command line arguments
*/
public static int cli(String[] argv) {
return new MarkdownCli().run(argv);
}
/**
* This method provides the command line interface. It invokes System.exit()
* at the end.
*
* @param argv the command line arguments
*/
public static void main(String[] argv) {
System.exit(cli(argv));
}
/**
* The field <code>in</code> contains the input file name or {@code null}
* for stdin.
*/
private String in = null;
/**
* The field <code>out</code> contains the output file name or {@code null}
* for stdout.
*/
private String out = null;
/**
* The field <code>css</code> contains the list of CSS files to include.
*/
private List<String> css = new ArrayList<>();
/**
* The field <code>standalone</code> contains the indicator that a
* stand-alone HTML file should be produced.
*/
private boolean standalone = true;
/**
* The field <code>title</code> contains the HTML title.
*/
private String title = "";
/**
* This method parses the command line arguments.
*
* @param argv the command line arguments
*/
private boolean parseCli(String[] argv) {
for (var i = 0; i < argv.length; i++) {
var arg = argv[i];
if ("-i".equals(arg) || "--input".startsWith(arg)
|| "-f".equals(arg) || "--file".startsWith(arg)) {
if (++i >= argv.length) {
throw new IllegalArgumentException(arg);
}
in = argv[i];
} else if ("-o".equals(arg) || "--output".startsWith(arg)) {
if (++i >= argv.length) {
throw new IllegalArgumentException(arg);
}
out = argv[i];
} else if ("-s".equals(arg) || "--standalone".startsWith(arg)) {
standalone = !standalone;
} else if ("-c".equals(arg) || "--css".startsWith(arg)) {
if (++i >= argv.length) {
throw new IllegalArgumentException(arg);
}
css.add(argv[i]);
} else if ("-t".equals(arg) || "--title".startsWith(arg)) {
if (++i >= argv.length) {
throw new IllegalArgumentException(arg);
}
title = argv[i];
} else if (arg.startsWith("-")) {
System.err.println(SYNOPSIS);
return true;
} else {
in = arg;
}
}
return false;
}
/**
* This method performs all actions required.
*
* @throws IOException in case of an I/O error.
*/
private void run() throws IOException {
if (in != null && out == null) {
out = in.replaceAll("(\\.md)$", "") + ".html";
}
try (Reader r = new BufferedReader(in != null
? new FileReader(in, StandardCharsets.UTF_8)
: new InputStreamReader(System.in, StandardCharsets.UTF_8))) {
try (Writer w = new BufferedWriter(out != null
? new FileWriter(out, StandardCharsets.UTF_8)
: new OutputStreamWriter(System.out, StandardCharsets.UTF_8))) {
run(r, w);
}
}
}
/**
* The method <code>run</code> reads the source and writes the target.
*
* @param r the reader
* @param w the writer
* @throws IOException in case of an error
*/
private void run(Reader r, Writer w) throws IOException {
if (standalone) {
w.write("<html>\n<head>\n<title>");
w.write(title);
w.write("</title>\n");
for (String c : css) {
w.write(
"<link rel='stylesheet' type='text/css' media='all' "
+ "href='");
w.write(c);
w.write("' />\n");
}
w.write("\n</head>\n<body>\n");
}
new MarkdownRenderer(r, "").render(w);
if (standalone) {
w.write("\n</body>\n</html>\n");
}
w.flush();
}
/**
* This method contains the command line processor with handling of
* Exceptions.
*
* @param argv the command line arguments
*
* @return the exit code
*/
public int run(@NonNull String[] argv) {
try {
if (!parseCli(argv)) {
run();
}
return EXIT_OK;
} catch (IOException e) {
System.err.println(
"*** " + e.getMessage());
return EXIT_ERROR;
} catch (IllegalArgumentException e) {
System.err.println(
"*** Missing argument for parameter " + e.getMessage());
return EXIT_ERROR;
}
}
}