Skip to content

Instantly share code, notes, and snippets.

@CoryBloyd
Created July 20, 2018 19:57
Show Gist options
  • Save CoryBloyd/c8dce71c37d40f3cc6b60f5c9b8b138b to your computer and use it in GitHub Desktop.
Save CoryBloyd/c8dce71c37d40f3cc6b60f5c9b8b138b to your computer and use it in GitHub Desktop.
markdown <-> cpp
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#include <string>
#include <vector>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
using std::string, std::string_view, std::vector;
struct Config {
const char *markdownLabel = "markdown";
const char *codeLabel = "cpp";
const char *markdownExt = ".md";
const char *codeExt = ".cpp";
const char *openCodeBlock = "```";
const char *closeCodeBlock = "````\n";
const char *openCommentBlock = "/***";
const char *closeCommentBlock = "****/\n";
};
string readFile(const string &path) {
string result;
if (int fileDescriptor; (fileDescriptor = open(path.data(), _O_RDONLY | _O_TEXT)) != -1) {
if (struct stat fileStat; fstat(fileDescriptor, &fileStat) == 0) {
result.resize(fileStat.st_size);
result.resize(read(fileDescriptor, &result[0], (int)result.size()));
}
close(fileDescriptor);
}
return result;
}
bool writeFile(const string &path, const string &text) {
int fileDescriptor = open(path.data(), O_WRONLY | O_CREAT | O_TRUNC | _O_TEXT, 0640);
if (fileDescriptor == -1)
return false;
int written = write(fileDescriptor, &text[0], (int)text.size());
int closeResult = close(fileDescriptor);
return written == text.size() && closeResult != -1;
}
string join(const vector<string_view> &spans, const char *openBlock, const char *sourceLanguage, const char *closeBlock) {
auto joinInto = [](char *dest, const vector<string_view> &spans, const char *openBlock, const char *sourceLanguage, const char *closeBlock) {
size_t totalSize = 0;
char *cursor = dest;
size_t maxSize = dest == nullptr ? 0 : size_t(-1);
bool comment = true;
for (auto span : spans) {
if (dest != nullptr)
cursor = dest + totalSize;
if (span.size() > 0) {
if (comment)
totalSize += snprintf(cursor, maxSize, "%s %s\n%.*s%s", openBlock, sourceLanguage, (int)span.size(), span.data(), closeBlock);
else
totalSize += snprintf(cursor, maxSize, "%.*s", (int)span.size(), span.data());
}
comment = !comment;
}
return totalSize;
};
size_t totalSize = joinInto(nullptr, spans, openBlock, sourceLanguage, closeBlock);
string result(totalSize, '\0');
joinInto(&result[0], spans, openBlock, sourceLanguage, closeBlock);
return result;
}
string convert(const string &source,
const char *destLanguage, const char *sourceLanguage,
const char *destOpenBlock, const char *destCloseBlock,
const char *srcOpenBlock, const char *srcCloseBlock) {
vector<string_view> spans;
const char *token = srcOpenBlock;
const string::size_type strlenSrcCloseBlock = strlen(srcCloseBlock);
const string::size_type sourceSize = source.size();
for (string::size_type spanStart = 0, spanEnd = 0; spanEnd < sourceSize;) {
spanEnd = source.find(token, spanStart);
if (spanEnd == string::npos)
spanEnd = sourceSize;
if (token == srcCloseBlock)
spanStart = source.find('\n', spanStart) + 1;
string_view span = string_view(&source[spanStart], spanEnd - spanStart);
spans.push_back(span);
if (token == srcCloseBlock)
spanEnd += strlenSrcCloseBlock;
token = token == srcOpenBlock ? srcCloseBlock : srcOpenBlock;
spanStart = spanEnd;
}
string result = join(spans, destOpenBlock, sourceLanguage, destCloseBlock);
return result;
}
string codeFromMarkdown(const string &markdown, const Config &config) {
return convert(markdown,
config.codeLabel, config.markdownLabel,
config.openCommentBlock, config.closeCommentBlock,
config.openCodeBlock, config.closeCodeBlock);
}
string markdownFromCode(const string &code, const Config &config) {
return convert(code,
config.markdownLabel, config.codeLabel,
config.openCodeBlock, config.closeCodeBlock,
config.openCommentBlock, config.closeCommentBlock);
}
bool endsWith(const string s, const char *x) { return s.rfind(x) == (s.size() - strlen(x)); }
int main(int argc, char *argv[]) {
Config config;
int errors = 0;
for (int arg = 1; arg < argc; arg++) {
string srcPath(argv[arg]);
const char *mdExt = config.markdownExt, *codeExt = config.codeExt;
const char *srcExt = endsWith(srcPath, mdExt) ? mdExt : codeExt;
const char *dstExt = srcExt == mdExt ? codeExt : mdExt;
string srcText = readFile(srcPath.data());
string dstText = dstExt == mdExt ? markdownFromCode(srcText, config)
: codeFromMarkdown(srcText, config);
if (dstText.empty()) {
errors++;
fprintf(stderr, "Failed to convert %.*s\n", (int)srcPath.size(), srcPath.data());
}
else {
string dstPath = srcPath.replace(srcPath.rfind(srcExt), strlen(srcExt), dstExt);
if (!writeFile(dstPath.data(), dstText)) {
errors++;
fprintf(stderr, "Failed to write %.*s\n", (int)dstPath.size(), dstPath.data());
}
}
}
return errors;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment