140 lines
4.1 KiB
C++
140 lines
4.1 KiB
C++
/*
|
|
* Copyright (C) 2022 luca0N!
|
|
*
|
|
* This file is part of Static Website Generator (swg).
|
|
*
|
|
* Static Website Generator (swg) is free software: you can redistribute it
|
|
* and/or modify it under the terms of the version 3 of the GNU Lesser General
|
|
* Public License as published by the Free Software Foundation.
|
|
*
|
|
* Static Website Generator (swg) is distributed in the hope that it will be
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Static Website Generator (swg). If not, see
|
|
* <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Contact luca0N! by e-mail: <luca0n [at] luca0n [dot] com>.
|
|
*/
|
|
|
|
#include "Article.hxx"
|
|
|
|
#include <iostream>
|
|
#include <list>
|
|
#include <string.h>
|
|
|
|
#include "Common.hxx"
|
|
|
|
enum IterationStage {
|
|
CHECKING_TITLE,
|
|
READING_TITLE,
|
|
CHECKING
|
|
};
|
|
|
|
namespace Article {
|
|
/*
|
|
* FIXME: The article metadata declaration uses the same INI format as
|
|
* swg.cfg. Since they use the exact same format, we could unify the .cfg
|
|
* parsing into one function.
|
|
*/
|
|
void get_metadata(std::string const &path, Metadata *m) {
|
|
memset(m, 0, sizeof(Metadata));
|
|
FILE *a = fopen(path.c_str(), "r");
|
|
|
|
int buflen = 16;
|
|
char buf[buflen];
|
|
|
|
const char *det_article = "<!--SwgArticle";
|
|
size_t det_article_pos = 0;
|
|
bool reading_metadata = false,
|
|
done = false,
|
|
skip = false;
|
|
|
|
std::list<std::string> cfg_lines = { "" };
|
|
|
|
while (fgets(buf, buflen, a) != NULL) {
|
|
// Ignore blank lines or lines starting with a comment.
|
|
if (buf[0] == '\n' || buf[0] == '#') continue;
|
|
int eol = -1;
|
|
for (int c = 0; c < buflen; c++) {
|
|
// Check if this loop has already done what it's supposed to do by checking if the title has been set.
|
|
if (done || buf[c] == '\0') break;
|
|
if (!reading_metadata) {
|
|
// FIXME: This code will not work if buflen < strlen(det_article).
|
|
if (buf[c] == det_article[det_article_pos]) {
|
|
det_article_pos++;
|
|
} else {
|
|
// TODO: Instead of exiting with an
|
|
// error code, prompt the end user
|
|
// whether the build should continue
|
|
// (while ignoring this article) or
|
|
// stop.
|
|
std::cerr << "error: invalid article: " << path << "\n";
|
|
exit(RETURN_FAILED_UNKNOWN_ERROR);
|
|
}
|
|
if (det_article_pos == strlen(det_article)) {
|
|
reading_metadata = true;
|
|
skip = true;
|
|
}
|
|
}
|
|
// Check end of HTML comment
|
|
if (buf[c] == '-' &&
|
|
buf[c+1] == '-' &&
|
|
buf[c+2] == '>') {
|
|
reading_metadata = false;
|
|
done = true;
|
|
break;
|
|
}
|
|
if (buf[c] == '\n')
|
|
eol = c;
|
|
}
|
|
if (skip) { skip = false; continue; }
|
|
if (done) break;
|
|
if (reading_metadata) {
|
|
if (eol > -1) {
|
|
buf[eol] = '\0';
|
|
*(--cfg_lines.end()) += buf;
|
|
cfg_lines.insert(cfg_lines.end(), "");
|
|
} else
|
|
*(--cfg_lines.end()) += buf;
|
|
}
|
|
}
|
|
|
|
bool reading_article_metadata = false;
|
|
for (std::string const &line : cfg_lines) {
|
|
// Check namespace
|
|
if (reading_article_metadata) {
|
|
std::string k_title = "Title=",
|
|
k_authors = "Authors=",
|
|
k_published = "Published=";
|
|
if (line.find(k_title) == 0)
|
|
strncpy(m->title, line.substr(k_title.length()).c_str(), sizeof(m->title));
|
|
else if (line.find(k_authors) == 0)
|
|
strncpy(m->authors, line.substr(k_authors.length()).c_str(), sizeof(m->authors));
|
|
else if (line.find(k_published) == 0)
|
|
m->publish_ts = atol(line.substr(k_published.length()).c_str());
|
|
else
|
|
std::cerr << "warning: ignoring unknown key/value due to unknown key: " << line << std::endl;
|
|
} else if (line[0] == '[') {
|
|
if (line == "[ArticleMetadata]") {
|
|
reading_article_metadata = true;
|
|
} else {
|
|
std::cerr << "error: article properties has unknown namespace: " << line << std::endl;
|
|
exit(RETURN_FAILED_CONFIG_INVALID_SYNTAX);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(a);
|
|
}
|
|
bool Comparator::comp(Metadata *a, Metadata *b) {
|
|
return a->publish_ts > b->publish_ts;
|
|
}
|
|
bool Comparator::equiv(Metadata *a, Metadata *b) {
|
|
return a->publish_ts == b->publish_ts;
|
|
}
|
|
};
|
|
|