Add virtual converter output interface

This commit is contained in:
deeaitch committed 2026-08-28 00:15:31 -04:00
1 parent 28c9752f18
commit 0f4da8e695
7 files changed
+144 -86

No files matched your search

+24 -82
View File
@@ -18,49 +18,6 @@ static std::string rstrip_cr (std::string s) {
return s;
}
static std::string latex_escape (const std::string &s) {
std::string out;
out.reserve (s.size() + s.size() / 8);
for (unsigned char ch : s) {
switch (ch) {
case '\\':
out += "\\textbackslash{}";
break;
case '{':
out += "\\{";
break;
case '}':
out += "\\}";
break;
case '%':
out += "\\%";
break;
case '$':
out += "\\$";
break;
case '#':
out += "\\#";
break;
case '&':
out += "\\&";
break;
case '_':
out += "\\_";
break;
case '^':
out += "\\textasciicircum{}";
break;
case '~':
out += "\\textasciitilde{}";
break;
default:
out.push_back (static_cast<char> (ch));
break;
}
}
return out;
}
struct Quote {
std::string meta;
std::vector<std::string> text_lines;
@@ -211,6 +168,30 @@ int Converter::error_code() const noexcept {
return error_code_;
}
void Converter::set_error_code (int error_code) noexcept {
error_code_ = error_code;
}
const std::vector<std::string> &Converter::titles() const noexcept {
return impl_->context.order;
}
std::size_t Converter::quote_count (const std::string &title) const {
const auto it = impl_->context.by_title.find (title);
return it == impl_->context.by_title.end() ? 0 : it->second.size();
}
const std::string &Converter::quote_meta (const std::string &title,
std::size_t index) const {
return impl_->context.by_title.at (title).at (index).meta;
}
const std::vector<std::string> &Converter::quote_text_lines (
const std::string &title,
std::size_t index) const {
return impl_->context.by_title.at (title).at (index).text_lines;
}
bool Converter::parse() {
std::ifstream input (input_file_name_);
if (!input.is_open()) {
@@ -256,42 +237,3 @@ bool Converter::parse() {
error_code_ = 0;
return true;
}
bool Converter::save (const std::string &output_file_name) {
if (!parse())
return false;
std::ofstream output (output_file_name, std::ios::trunc);
if (!output.is_open()) {
std::cerr << "Failed to open output file: "
<< output_file_name
<< " (" << std::strerror (errno) << ")\n";
error_code_ = 3;
return false;
}
const ParseContext &ctx = impl_->context;
for (std::size_t i = 0; i < ctx.order.size(); ++i) {
const auto &title = ctx.order[i];
output << "\\section {" << latex_escape (title) << "}\n";
const auto it = ctx.by_title.find (title);
if (it == ctx.by_title.end())
continue;
for (const auto &quote : it->second) {
output << " \\subsection {" << latex_escape (quote.meta) << "}\n";
for (const auto &text_line : quote.text_lines)
output << " " << latex_escape (text_line) << "\n";
output << " \\subsubsection{notes}\n\n";
}
if (i + 1 < ctx.order.size())
output << "\n";
}
error_code_ = 0;
return true;
}
+13 -2
View File
@@ -2,21 +2,32 @@
#define CONVERTER_H
#include <memory>
#include <cstddef>
#include <string>
#include <vector>
class Converter {
public:
explicit Converter (std::string input_file_name);
~Converter();
virtual ~Converter();
Converter (const Converter &) = delete;
Converter &operator= (const Converter &) = delete;
bool save (const std::string &output_file_name);
virtual bool save (const std::string &output_file_name) = 0;
[[nodiscard]] int error_code() const noexcept;
protected:
bool parse();
void set_error_code (int error_code) noexcept;
[[nodiscard]] const std::vector<std::string> &titles() const noexcept;
[[nodiscard]] std::size_t quote_count (const std::string &title) const;
[[nodiscard]] const std::string &quote_meta (const std::string &title,
std::size_t index) const;
[[nodiscard]] const std::vector<std::string> &quote_text_lines (
const std::string &title,
std::size_t index) const;
private:
struct Impl;
+88
View File
@@ -0,0 +1,88 @@
#include "convertlatex.h"
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
static std::string latex_escape (const std::string &s) {
std::string out;
out.reserve (s.size() + s.size() / 8);
for (unsigned char ch : s) {
switch (ch) {
case '\\':
out += "\\textbackslash{}";
break;
case '{':
out += "\\{";
break;
case '}':
out += "\\}";
break;
case '%':
out += "\\%";
break;
case '$':
out += "\\$";
break;
case '#':
out += "\\#";
break;
case '&':
out += "\\&";
break;
case '_':
out += "\\_";
break;
case '^':
out += "\\textasciicircum{}";
break;
case '~':
out += "\\textasciitilde{}";
break;
default:
out.push_back (static_cast<char> (ch));
break;
}
}
return out;
}
bool ConvertLatex::save (const std::string &output_file_name) {
if (!parse())
return false;
std::ofstream output (output_file_name, std::ios::trunc);
if (!output.is_open()) {
std::cerr << "Failed to open output file: "
<< output_file_name
<< " (" << std::strerror (errno) << ")\n";
set_error_code (3);
return false;
}
const auto &book_titles = titles();
for (std::size_t i = 0; i < book_titles.size(); ++i) {
const auto &title = book_titles[i];
output << "\\section {" << latex_escape (title) << "}\n";
for (std::size_t quote_index = 0;
quote_index < quote_count (title);
++quote_index) {
output << " \\subsection {"
<< latex_escape (quote_meta (title, quote_index))
<< "}\n";
for (const auto &text_line : quote_text_lines (title, quote_index))
output << " " << latex_escape (text_line) << "\n";
output << " \\subsubsection{notes}\n\n";
}
if (i + 1 < book_titles.size())
output << "\n";
}
set_error_code (0);
return true;
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef CONVERTLATEX_H
#define CONVERTLATEX_H
#include "converter.h"
class ConvertLatex final : public Converter {
public:
using Converter::Converter;
bool save (const std::string &output_file_name) override;
};
#endif // CONVERTLATEX_H
+2 -2
View File
@@ -2,7 +2,7 @@
#include <iostream>
#include <string>
#include "converter.h"
#include "convertlatex.h"
struct CliArgs {
std::string input;
@@ -53,7 +53,7 @@ int main (int argc, char **argv) {
if (!parse_args (argc, argv, args))
return 1;
Converter converter (args.input);
ConvertLatex converter (args.input);
if (!converter.save (args.output))
return converter.error_code();
+2
View File
@@ -4,9 +4,11 @@ CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
convertlatex.cpp \
converter.cpp \
main.cpp
HEADERS += \
convertlatex.h \
converter.h \
typefactory.h