From 1de3a9aae84ec71c4fd83604ea9c45204efb9baf Mon Sep 17 00:00:00 2001 From: Aleksey Veresov Date: Fri, 25 Oct 2019 14:10:45 +0300 Subject: . --- examples/Makefile | 2 +- examples/lines.cpp | 61 +++++++++++++++++ examples/lines.txt | 2 + examples/plain.cpp | 61 +++++++++++++++++ examples/plain.txt | 17 +++++ examples/plain_to_html.cpp | 22 ------ src/html.cpp | 10 +++ src/html.hpp | 23 +++++++ src/lines.cpp | 87 +++++++++++++++++++++++ src/lines.hpp | 41 +++++++++++ src/markdown.cpp | 167 +++++++++++++++++++++++++++++++++++++++++++++ src/markdown.hpp | 49 +++++++++++++ src/plain.cpp | 130 ++++++++++++++++++++--------------- src/plain.hpp | 11 +-- src/producer.cpp | 5 ++ src/producer.hpp | 1 + src/texo.hpp | 1 + 17 files changed, 607 insertions(+), 83 deletions(-) create mode 100644 examples/lines.cpp create mode 100644 examples/lines.txt create mode 100644 examples/plain.cpp create mode 100644 examples/plain.txt delete mode 100644 examples/plain_to_html.cpp create mode 100644 src/lines.cpp create mode 100644 src/lines.hpp create mode 100644 src/markdown.cpp create mode 100644 src/markdown.hpp diff --git a/examples/Makefile b/examples/Makefile index 1959b4b..69f383c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,7 +2,7 @@ DEBUG = yes CC = g++ -EXAMPLES = plain_to_html +EXAMPLES = plain lines CPPFLAGS = -Wall -ansi ifeq '$(DEBUG)' 'yes' diff --git a/examples/lines.cpp b/examples/lines.cpp new file mode 100644 index 0000000..5c24444 --- /dev/null +++ b/examples/lines.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + + +void plain() +{ + fputs(" ---- Lines to Plain ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerPlain producer(exporter); + TexoImporterLines importer(producer); + FILE *file = fopen("lines.txt", "r"); + importer.Put(file); + fclose(file); +} + +void html() +{ + fputs("\n\n ---- Lines to HTML ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerHTML producer(exporter); + TexoImporterLines importer(producer); + FILE *file = fopen("lines.txt", "r"); + importer.Put(file); + fclose(file); +} + +void markdown() +{ + fputs("\n\n ---- Lines to Markdown ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerMarkdown producer(exporter); + TexoImporterLines importer(producer); + FILE *file = fopen("lines.txt", "r"); + importer.Put(file); + fclose(file); +} + +void lines() +{ + fputs("\n\n ---- Lines to Lines ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerLines producer(exporter); + TexoImporterLines importer(producer); + FILE *file = fopen("lines.txt", "r"); + importer.Put(file); + fclose(file); +} + +int main() +{ + plain(); + html(); + markdown(); + lines(); + + return 0; +} diff --git a/examples/lines.txt b/examples/lines.txt new file mode 100644 index 0000000..a227a08 --- /dev/null +++ b/examples/lines.txt @@ -0,0 +1,2 @@ +Simpliest format. Paragraphs on newlines. And nothing else. +So this is second paragraph. diff --git a/examples/plain.cpp b/examples/plain.cpp new file mode 100644 index 0000000..d91fcde --- /dev/null +++ b/examples/plain.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include + + +void plain() +{ + fputs(" ---- Plain to Plain ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerPlain producer(exporter); + TexoImporterPlain importer(producer); + FILE *file = fopen("plain.txt", "r"); + importer.Put(file); + fclose(file); +} + +void html() +{ + fputs("\n\n ---- Plain to HTML ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerHTML producer(exporter); + TexoImporterPlain importer(producer); + FILE *file = fopen("plain.txt", "r"); + importer.Put(file); + fclose(file); +} + +void markdown() +{ + fputs("\n\n ---- Plain to Markdown ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerMarkdown producer(exporter); + TexoImporterPlain importer(producer); + FILE *file = fopen("plain.txt", "r"); + importer.Put(file); + fclose(file); +} + +void lines() +{ + fputs("\n\n ---- Plain to Lines ----\n\n", stdout); + TexoExporterFile exporter(stdout); + TexoProducerLines producer(exporter); + TexoImporterPlain importer(producer); + FILE *file = fopen("plain.txt", "r"); + importer.Put(file); + fclose(file); +} + +int main() +{ + plain(); + html(); + markdown(); + lines(); + + return 0; +} diff --git a/examples/plain.txt b/examples/plain.txt new file mode 100644 index 0000000..c05d73f --- /dev/null +++ b/examples/plain.txt @@ -0,0 +1,17 @@ +I am a little cute line. + +I am another and that's fine. + +But I am as long as a pine, +so lets drink a glass of wine. + + + +You can use any count of empty lines to mark paragraphs. + +> This is quote. +> Long enough. + +-------------------------------------------------------- + +This was horizontal rule diff --git a/examples/plain_to_html.cpp b/examples/plain_to_html.cpp deleted file mode 100644 index d123a84..0000000 --- a/examples/plain_to_html.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include -#include -#include - - -int main() -{ - TexoExporterFile exporter(stdout); - TexoProducerHTML producer(exporter); - TexoImporterPlain importer(producer); - importer.Put( - "I am a little cute line. \n" - "I am another and that's fine. \n" - "But I am as long as a pine,\n" - "so lets drink a glass of wine.\n\n" - "Second paragraph was started here. \n" - "Take your bananas and go home, seer.\n" - ); - return 0; -} diff --git a/src/html.cpp b/src/html.cpp index 5155661..92b4e05 100644 --- a/src/html.cpp +++ b/src/html.cpp @@ -172,3 +172,13 @@ void TexoImporterHTML::Put(char c) { // TODO producer.Put(Texo(c)); } + +void TexoImporterHTML::Put(const ScriptVariable &str) +{ + TexoImporter::Put(str); +} + +void TexoImporterHTML::Put(FILE *file) +{ + TexoImporter::Put(file); +} diff --git a/src/html.hpp b/src/html.hpp index dc291f6..fcf64e6 100644 --- a/src/html.hpp +++ b/src/html.hpp @@ -35,6 +35,29 @@ public: TexoImporterHTML(TexoProducer &producer); void Put(char c); + void Put(const ScriptVariable &str); + void Put(FILE *file); + +private: + enum State { + text, // TODO: decoding (">" -> ">") + open, + tag_name, + tag_skip, + attr_pre, + attr_name, + attr_name_post, + attr_value_pre, + attr_value + } state; + bool closing; + ScriptVariable tag; + ScriptVariable attr; + ScriptVariable attr_src; + ScriptVariable attr_href; + ScriptVariable attr_title; + ScriptVariable attr_alt; + ScriptVariable link_text; }; diff --git a/src/lines.cpp b/src/lines.cpp new file mode 100644 index 0000000..05a75e4 --- /dev/null +++ b/src/lines.cpp @@ -0,0 +1,87 @@ +#include "lines.hpp" + + +TexoProducerLines::TexoProducerLines(TexoExporter &exporter): + TexoProducer(exporter) +{} + +void TexoProducerLines::Put(const Texo &piece) +{ + if (piece.c == '\n') { + exporter.Put(' '); + } else { + exporter.Put(piece.c); + } +} + +void TexoProducerLines::Put(const TexoParagraph &piece) +{ + if (piece.closing) { + exporter.Put('\n'); + } +} + +void TexoProducerLines::Put(const TexoQuote &piece) +{ + if (piece.closing) { + exporter.Put('\n'); + } else { + exporter.Put('>'); + } +} + +void TexoProducerLines::Put(const TexoLineBreak &piece) +{ + exporter.Put('\n'); +} + + +TexoImporterLines::TexoImporterLines(TexoProducer &producer): + TexoImporter(producer), quoted(false), newline(true) +{} + +TexoImporterLines::~TexoImporterLines() +{ + if (!newline) { + if (quoted) { + producer.Put(TexoQuote(true)); + } else { + producer.Put(TexoParagraph(true)); + } + } +} + +void TexoImporterLines::Put(char c) +{ + if (c == '\n') { + if (!newline) { + if (quoted) { + producer.Put(TexoQuote(true)); + quoted = false; + } else { + producer.Put(TexoParagraph(true)); + } + newline = true; + } + } else if (newline && c == '>') { + producer.Put(TexoQuote()); + newline = false; + quoted = true; + } else { + if (newline) { + producer.Put(TexoParagraph()); + newline = false; + } + producer.Put(c); + } +} + +void TexoImporterLines::Put(const ScriptVariable &str) +{ + TexoImporter::Put(str); +} + +void TexoImporterLines::Put(FILE *file) +{ + TexoImporter::Put(file); +} diff --git a/src/lines.hpp b/src/lines.hpp new file mode 100644 index 0000000..4f68cb9 --- /dev/null +++ b/src/lines.hpp @@ -0,0 +1,41 @@ +#ifndef TEXO_INCLUDED_LINES +#define TEXO_INCLUDED_LINES + +#include "exporter.hpp" +#include "producer.hpp" +#include "importer.hpp" + + +class TexoProducerLines: public TexoProducer { +public: + TexoProducerLines(TexoExporter &exporter); + + void Put(const Texo &piece); + + void Put(const TexoParagraph &piece); + void Put(const TexoQuote &piece); + + void Put(const TexoLineBreak &piece); + +private: + bool quoted; + bool newline; +}; + + +class TexoImporterLines: public TexoImporter { +public: + TexoImporterLines(TexoProducer &producer); + ~TexoImporterLines(); + + void Put(char c); + void Put(const ScriptVariable &str); + void Put(FILE *file); + +private: + bool quoted; + bool newline; +}; + + +#endif diff --git a/src/markdown.cpp b/src/markdown.cpp new file mode 100644 index 0000000..c542a1f --- /dev/null +++ b/src/markdown.cpp @@ -0,0 +1,167 @@ +#include "markdown.hpp" + + +TexoProducerMarkdown::TexoProducerMarkdown(TexoExporter &exporter): + TexoProducer(exporter), quoted(false), newline(false), code(false) +{} + +void TexoProducerMarkdown::Put(const Texo &piece) +{ + if (piece.c == '\n') { + if (code) { + exporter.Put('\n'); + } else if (quoted) { + exporter.Put("\n>"); + } else if (header || newline) { + exporter.Put(' '); + } else { + exporter.Put('\n'); + newline = true; + } + } else { + exporter.Put(piece.c); + newline = false; + } +} + +void TexoProducerMarkdown::Put(const TexoHeader &piece) +{ + if (piece.closing) { + exporter.Put('\n'); + header = false; + newline = true; + } else { + if (!newline) { + exporter.Put('\n'); + } + if (piece.level <= 1) { + exporter.Put("###### "); + } else if (piece.level == 2) { + exporter.Put("##### "); + } else if (piece.level == 3) { + exporter.Put("#### "); + } else if (piece.level == 4) { + exporter.Put("### "); + } else if (piece.level == 5) { + exporter.Put("## "); + } else { + exporter.Put("# "); + } + header = true; + } +} + +void TexoProducerMarkdown::Put(const TexoParagraph &piece) +{ + if (piece.closing) { + exporter.Put("\n\n"); + newline = true; + } +} + +void TexoProducerMarkdown::Put(const TexoCode &piece) +{ + exporter.Put("\n```\n"); + code = !code; +} + +void TexoProducerMarkdown::Put(const TexoQuote &piece) +{ + if (piece.closing) { + exporter.Put("\n\n"); + quoted = false; + newline = true; + } else { + if (!newline) { + exporter.Put('\n'); + } + exporter.Put(">"); + quoted = true; + } +} + +void TexoProducerMarkdown::Put(const TexoMono &piece) +{ + exporter.Put("`"); +} + +void TexoProducerMarkdown::Put(const TexoBold &piece) +{ + exporter.Put("**"); +} + +void TexoProducerMarkdown::Put(const TexoItalic &piece) +{ + exporter.Put("*"); +} + +void TexoProducerMarkdown::Put(const TexoUnderline &piece) +{ + exporter.Put("++"); +} + +void TexoProducerMarkdown::Put(const TexoStrike &piece) +{ + exporter.Put("~~"); +} + +void TexoProducerMarkdown::Put(const TexoImage &piece) +{ + if (piece.path != "") { + const bool link = piece.link != ""; + if (link) { + exporter.Put('['); + } + exporter.Put("!["); + exporter.Put(piece.alt); + exporter.Put("]("); + exporter.Put(piece.path); + if (piece.title != "") { + exporter.Put(" \""); + exporter.Put(piece.title); + exporter.Put('"'); + } + exporter.Put(')'); + if (link) { + exporter.Put("]("); + exporter.Put(piece.link); + if (piece.title != "") { + exporter.Put(" \""); + exporter.Put(piece.title); + exporter.Put('"'); + } + exporter.Put(')'); + } + } +} + +void TexoProducerMarkdown::Put(const TexoLink &piece) +{ + if (piece.text != "") { + exporter.Put('['); + exporter.Put(piece.text); + exporter.Put("]("); + exporter.Put(piece.link); + if (piece.title != "") { + exporter.Put(" \""); + exporter.Put(piece.title); + exporter.Put('"'); + } + exporter.Put(')'); + } +} + +void TexoProducerMarkdown::Put(const TexoLineBreak &piece) +{ + exporter.Put("\\\n"); + newline = true; +} + +void TexoProducerMarkdown::Put(const TexoHorizontalRule &piece) +{ + if (!newline) { + exporter.Put('\n'); + } + exporter.Put("---\n"); + newline = false; +} diff --git a/src/markdown.hpp b/src/markdown.hpp new file mode 100644 index 0000000..7a23fed --- /dev/null +++ b/src/markdown.hpp @@ -0,0 +1,49 @@ +#ifndef TEXO_INCLUDED_MARKDOWN +#define TEXO_INCLUDED_MARKDOWN + +#include "exporter.hpp" +#include "producer.hpp" +#include "importer.hpp" + + +class TexoProducerMarkdown: public TexoProducer { +public: + TexoProducerMarkdown(TexoExporter &exporter); + + void Put(const Texo &piece); + + void Put(const TexoHeader &piece); + void Put(const TexoParagraph &piece); + void Put(const TexoCode &piece); + void Put(const TexoQuote &piece); + + void Put(const TexoMono &piece); + void Put(const TexoBold &piece); + void Put(const TexoItalic &piece); + void Put(const TexoUnderline &piece); + void Put(const TexoStrike &piece); + + void Put(const TexoImage &piece); + void Put(const TexoLink &piece); + void Put(const TexoLineBreak &piece); + void Put(const TexoHorizontalRule &piece); + +private: + bool quoted; + bool newline; + bool header; + bool code; +}; + + +class TexoImporterMarkdown: public TexoImporter { +public: + TexoImporterMarkdown(TexoProducer &producer); + + void Put(char c); + void Put(const ScriptVariable &str); + void Put(FILE *file); +}; + + +#endif diff --git a/src/plain.cpp b/src/plain.cpp index bff9398..d6d262d 100644 --- a/src/plain.cpp +++ b/src/plain.cpp @@ -2,22 +2,23 @@ TexoProducerPlain::TexoProducerPlain(TexoExporter &exporter): - TexoProducer(exporter) + TexoProducer(exporter), quoted(false), newline(false) {} void TexoProducerPlain::Put(const Texo &piece) { - if (quoted && piece.c == '\n') { - exporter.Put("\n> "); + if (piece.c == '\n') { + if (quoted) { + exporter.Put("\n>"); + } else if (newline) { + exporter.Put(' '); + } else { + exporter.Put('\n'); + newline = true; + } } else { exporter.Put(piece.c); - } -} - -void TexoProducerPlain::Put(const TexoHeader &piece) -{ - if (!piece.closing) { - exporter.Put("\n\n# "); + newline = false; } } @@ -25,28 +26,38 @@ void TexoProducerPlain::Put(const TexoParagraph &piece) { if (piece.closing) { exporter.Put("\n\n"); + newline = true; } } void TexoProducerPlain::Put(const TexoQuote &piece) { if (piece.closing) { - quoted = false; exporter.Put("\n\n"); + quoted = false; + newline = true; } else { + if (!newline) { + exporter.Put('\n'); + } + exporter.Put(">"); quoted = true; - exporter.Put("\n\n> "); } } void TexoProducerPlain::Put(const TexoLineBreak &piece) { - exporter.Put(" \n"); + exporter.Put("\n\n"); + newline = true; } void TexoProducerPlain::Put(const TexoHorizontalRule &piece) { - exporter.Put("\n--------------------------------------------------\n"); + if (!newline) { + exporter.Put('\n'); + } + exporter.Put("--------------------------------------------------\n"); + newline = false; } @@ -59,15 +70,17 @@ TexoImporterPlain::TexoImporterPlain(TexoProducer &producer): TexoImporterPlain::~TexoImporterPlain() { switch (state) { - case text: case space: case newline: + case rule: + producer.Put('\n'); + for (;dash_count > 0; --dash_count) { + producer.Put('-'); + } + case text: case newline: producer.Put(TexoParagraph(true)); break; case quote: case quote_newline: producer.Put(TexoQuote(true)); break; - case header: - producer.Put(TexoHeader(true)); - break; case paragraph: break; } @@ -76,13 +89,12 @@ TexoImporterPlain::~TexoImporterPlain() void TexoImporterPlain::Put(char c) { switch (state) { - case text: Text(c); break; - case space: Space(c); break; - case newline: Newline(c); break; - case paragraph: Paragraph(c); break; - case quote: Quote(c); break; - case quote_newline: QuoteNewline(c); break; - case header: Header(c); break; + case text: Text(c); break; + case newline: Newline(c); break; + case paragraph: Paragraph(c); break; + case quote: Quote(c); break; + case quote_newline: QuoteNewline(c); break; + case rule: Rule(c); break; } } @@ -91,53 +103,47 @@ void TexoImporterPlain::Put(const ScriptVariable &str) TexoImporter::Put(str); } -void TexoImporterPlain::Text(char c) +void TexoImporterPlain::Put(FILE *file) { - switch (c) { - case ' ': state = space; break; - case '\n': state = newline; break; - default: producer.Put(Texo(c)); break; - } + TexoImporter::Put(file); } -void TexoImporterPlain::Space(char c) +void TexoImporterPlain::Text(char c) { - if (c == '\n') { - producer.Put(TexoLineBreak()); - state = text; - } else if (c == ' ') { - producer.Put(Texo(' ')); - } else { - producer.Put(Texo(' ')); - producer.Put(Texo(c)); - state = text; + switch (c) { + case '\n': state = newline; break; + default: producer.Put(c); break; } } void TexoImporterPlain::Newline(char c) { if (c == '\n') { - producer.Put(TexoParagraph(true)); state = paragraph; + } else if (c == '-') { + dash_count = 1; + state = rule; } else { - producer.Put(Texo('\n')); - producer.Put(Texo(c)); + producer.Put('\n'); state = text; + Text(c); } } void TexoImporterPlain::Paragraph(char c) { if (c == '>') { + producer.Put(TexoParagraph(true)); producer.Put(TexoQuote()); state = quote; - } else if (c == '#') { - producer.Put(TexoHeader(1)); - state = header; - } else { + } else if (c == '-') { + dash_count = 1; + state = rule; + } else if (c != '\n') { + producer.Put(TexoParagraph(true)); producer.Put(TexoParagraph()); - producer.Put(Texo(c)); state = text; + Text(c); } } @@ -145,31 +151,45 @@ void TexoImporterPlain::Quote(char c) { switch (c) { case '\n': state = quote_newline; break; - default: producer.Put(Texo(c)); break; + default: producer.Put(c); break; } } void TexoImporterPlain::QuoteNewline(char c) { if (c == '>') { + producer.Put('\n'); state = quote; } else if (c == '\n') { producer.Put(TexoQuote(true)); + producer.Put(TexoParagraph()); state = paragraph; + } else if (c == '-') { + producer.Put(TexoQuote(true)); + producer.Put(TexoParagraph()); + dash_count = 1; + state = rule; } else { producer.Put(TexoQuote(true)); producer.Put(TexoParagraph()); - producer.Put(Texo(c)); state = text; + Text(c); } } -void TexoImporterPlain::Header(char c) +void TexoImporterPlain::Rule(char c) { if (c == '\n') { - producer.Put(TexoHeader(1, true)); - state = paragraph; + producer.Put(TexoHorizontalRule()); + state = text; + } else if (c == '-') { + ++dash_count; } else { - producer.Put(Texo(c)); + producer.Put('\n'); + for (;dash_count > 0; --dash_count) { + producer.Put('-'); + } + state = text; + Text(c); } } diff --git a/src/plain.hpp b/src/plain.hpp index 6fa086f..f758843 100644 --- a/src/plain.hpp +++ b/src/plain.hpp @@ -12,7 +12,6 @@ public: void Put(const Texo &piece); - void Put(const TexoHeader &piece); void Put(const TexoParagraph &piece); void Put(const TexoQuote &piece); @@ -21,6 +20,7 @@ public: private: bool quoted; + bool newline; }; @@ -31,25 +31,26 @@ public: void Put(char c); void Put(const ScriptVariable &str); + void Put(FILE *file); private: enum State { text, - space, newline, paragraph, quote, quote_newline, - header + rule } state; void Text(char c); - void Space(char c); void Newline(char c); void Paragraph(char c); void Quote(char c); void QuoteNewline(char c); - void Header(char c); + void Rule(char c); + + int dash_count; }; diff --git a/src/producer.cpp b/src/producer.cpp index c3ef801..8651912 100644 --- a/src/producer.cpp +++ b/src/producer.cpp @@ -4,6 +4,11 @@ TexoProducer::TexoProducer(TexoExporter &exporter): exporter(exporter) {} +void TexoProducer::Put(char c) +{ + Put(Texo(c)); +} + void TexoProducer::Put(const Texo &piece) { exporter.Put(piece.c); diff --git a/src/producer.hpp b/src/producer.hpp index a2f9ecc..c6fcd5f 100644 --- a/src/producer.hpp +++ b/src/producer.hpp @@ -9,6 +9,7 @@ class TexoProducer { public: TexoProducer(TexoExporter &exporter); + virtual void Put(char c); virtual void Put(const Texo &piece); virtual void Put(const TexoHeader &piece); diff --git a/src/texo.hpp b/src/texo.hpp index e2a7d86..82c384e 100644 --- a/src/texo.hpp +++ b/src/texo.hpp @@ -1,5 +1,6 @@ #ifndef TEXO_INCLUDED_TEXO #define TEXO_INCLUDED_TEXO +// TODO: lists & maybe tables #include -- cgit v1.2.3