30static std::string
readFile(
const std::string &path) {
31 std::fstream f(path, std::ios::in);
33 std::cerr <<
"mxvm-html: could not open file: " << path <<
"\n";
36 std::ostringstream ss;
41static bool endsWith(
const std::string &s,
const std::string &suffix) {
42 return s.size() >= suffix.size() &&
43 s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
47static std::string
dirOf(
const std::string &path) {
48 auto pos = path.find_last_of(
"/\\");
49 return pos == std::string::npos ?
"./" : path.substr(0,
pos + 1);
53 std::ifstream f(path);
59 std::string cssPath =
dirOf(outPath) +
"mxvm-highlight.css";
61 std::ofstream f(cssPath);
64 std::cout <<
"mxvm-html: wrote " << cssPath <<
"\n";
74static void writeHtml(
const std::string &src,
const std::string &inPath,
75 const std::string &outPath,
const std::string &cssHref =
"") {
76 std::fstream ofile(outPath, std::ios::out);
77 if (!ofile.is_open()) {
78 std::cerr <<
"mxvm-html: could not open output file: " << outPath <<
"\n";
83 std::string href = cssHref.empty() ?
"mxvm-highlight.css" : cssHref;
86 gen.
output(ofile, inPath, href);
93 std::cout <<
"mxvm-html: wrote " << outPath <<
"\n";
99 const std::string decls[] = {
"program",
"unit",
"object"};
100 std::size_t
pos = 0, n = src.size();
104 if (std::isspace(
static_cast<unsigned char>(c))) { ++
pos;
continue; }
106 if (c ==
'/' &&
pos + 1 < n && src[
pos + 1] ==
'/') {
107 while (
pos < n && src[
pos] !=
'\n') ++
pos;
112 while (
pos < n && src[
pos] !=
'\n') ++
pos;
117 while (
pos < n && src[
pos] !=
'}') ++
pos;
122 if (c ==
'(' &&
pos + 1 < n && src[
pos + 1] ==
'*') {
124 while (
pos + 1 < n && !(src[
pos] ==
'*' && src[
pos + 1] ==
')')) ++
pos;
125 if (
pos + 1 < n)
pos += 2;
129 if (c ==
'/' &&
pos + 1 < n && src[
pos + 1] ==
'*') {
131 while (
pos + 1 < n && !(src[
pos] ==
'*' && src[
pos + 1] ==
'/')) ++
pos;
132 if (
pos + 1 < n)
pos += 2;
135 if (std::isalpha(
static_cast<unsigned char>(c)) || c ==
'_') {
136 std::size_t start =
pos;
137 while (
pos < n && (std::isalnum(
static_cast<unsigned char>(src[
pos])) || src[
pos] ==
'_'))
139 std::string tok = src.substr(start,
pos - start);
141 std::string ltok = tok;
142 for (
auto &ch : ltok) ch =
static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
143 for (
const auto &kw : decls) {
145 while (
pos < n && std::isspace(
static_cast<unsigned char>(src[
pos]))) ++
pos;
146 if (
pos < n && (std::isalpha(
static_cast<unsigned char>(src[
pos])) || src[
pos] ==
'_')) {
147 std::size_t ns =
pos;
148 while (
pos < n && (std::isalnum(
static_cast<unsigned char>(src[
pos])) || src[
pos] ==
'_'))
150 return src.substr(ns,
pos - ns);
164 .addOptionSingleValue(
'o',
"output .html file (single-file mode only)")
165 .addOptionSingleValue(
's',
"link to this CSS file instead of writing mxvm-highlight.css")
166 .addOptionSingle(
'c',
"batch: convert each listed file, auto-name output from program/unit/object")
167 .addOptionSingle(
'h',
"show this help");
169 std::string inputFile, outputFile, cssHref;
170 bool batchMode =
false;
171 std::vector<std::string> positional;
176 while ((opt = args.
proc(arg)) != -1) {
178 case 'i': inputFile = arg.
arg_value;
break;
179 case 'o': outputFile = arg.
arg_value;
break;
180 case 's': cssHref = arg.
arg_value;
break;
181 case 'c': batchMode =
true;
break;
183 std::cout <<
"mxvm-html: MXVM / Pascal source to HTML converter\n\n";
184 args.
help(std::cout);
193 std::cerr <<
"mxvm-html: " << e.
text() <<
"\n";
198 if (positional.empty()) {
199 std::cerr <<
"mxvm-html: -c requires at least one input file\n";
202 for (
const auto &path : positional) {
206 std::cerr <<
"mxvm-html: no program/unit/object declaration found in: " << path <<
"\n";
209 writeHtml(src, path, name +
".html", cssHref);
214 if (!inputFile.empty()) {
215 std::string src =
readFile(inputFile);
216 if (outputFile.empty()) {
219 std::cerr <<
"mxvm-html: no program/unit/object declaration found in: " << inputFile
220 <<
" — use -o to specify output filename\n";
223 outputFile = name +
".html";
225 writeHtml(src, inputFile, outputFile, cssHref);
229 std::cerr <<
"mxvm-html: no input specified. Use -i <file> [-o <output>] [-s <css>] or -c <file1> [file2...]\n";
230 std::cerr <<
"Run with -h for help.\n";
Generic command-line argument parser with concept-constrained string types.
Exception type thrown for argument parsing errors.
String text() const
Get the error message.
Generic command-line argument parser supporting single/double-dash options.
Argz< String > & addOptionSingleValue(const int &c, const String &description)
Register a single-dash option that takes a value.
void help(T &cout)
Print a formatted help message listing all registered options.
int proc(Argument< String > &a)
Process the next argument from the command line.
Generates syntax-highlighted HTML output from MXVM source code.
void output(std::ostream &out, std::string filename)
Write the generated HTML to an output stream.
Generates syntax-highlighted HTML output from Pascal (.pas) source code.
void output(std::ostream &out, const std::string &filename, const std::string &cssHref="mxvm-highlight.css")
Write generated HTML to an output stream.
static std::string defaultCss()
Return the default stylesheet text.
int64_t pos(const char *substr, const char *s)
static bool fileExists(const std::string &path)
static bool endsWith(const std::string &s, const std::string &suffix)
int main(int argc, char **argv)
static void writeHtml(const std::string &src, const std::string &inPath, const std::string &outPath, const std::string &cssHref="")
static std::string readFile(const std::string &path)
static std::string dirOf(const std::string &path)
static void ensureCss(const std::string &outPath)
static std::string extractDeclName(const std::string &src)
HTML documentation generator from MXVM source code.
int argc(void)
Return the number of stored command-line arguments.
const char * argv(int idx)
Return the command-line argument at the given index.
A parsed or registered command-line argument definition.
String arg_value
parsed value (for value-taking options)