Add original source files
This commit is contained in:
parent
6e1bdc8870
commit
98b74941db
|
@ -0,0 +1,49 @@
|
||||||
|
# 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>.
|
||||||
|
|
||||||
|
PROGRAM_NAME=swg
|
||||||
|
|
||||||
|
CXXC=g++
|
||||||
|
CXXFLAGS=-Wall -Wextra -g -O0 -std=c++17
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
$(PROGRAM_NAME): build/ build/obj/ build/obj/main.o build/obj/ConfigUtils.o build/obj/WebsiteBuilder.o build/obj/SwgRuntime.o
|
||||||
|
$(CXXC) -o $(PROGRAM_NAME) build/obj/main.o build/obj/ConfigUtils.o build/obj/WebsiteBuilder.o build/obj/SwgRuntime.o
|
||||||
|
|
||||||
|
build/obj/main.o: src/main.cxx src/ConfigUtils.hxx src/SwgContext.hxx src/WebsiteBuilder.hxx src/Common.hxx
|
||||||
|
$(CXXC) $(CXXFLAGS) -o build/obj/main.o -c src/main.cxx
|
||||||
|
|
||||||
|
build/obj/ConfigUtils.o: src/ConfigUtils.cxx src/SwgContext.hxx src/Common.hxx
|
||||||
|
$(CXXC) $(CXXFLAGS) -o build/obj/ConfigUtils.o -c src/ConfigUtils.cxx
|
||||||
|
|
||||||
|
build/obj/WebsiteBuilder.o: src/WebsiteBuilder.hxx src/WebsiteBuilder.cxx src/SwgRuntime.hxx src/Common.hxx
|
||||||
|
$(CXXC) $(CXXFLAGS) -o build/obj/WebsiteBuilder.o -c src/WebsiteBuilder.cxx
|
||||||
|
|
||||||
|
build/obj/SwgRuntime.o: src/SwgRuntime.hxx src/SwgRuntime.cxx
|
||||||
|
$(CXXC) $(CXXFLAGS) -o build/obj/SwgRuntime.o -c src/SwgRuntime.cxx
|
||||||
|
|
||||||
|
build/:
|
||||||
|
mkdir -p build/
|
||||||
|
|
||||||
|
build/obj/:
|
||||||
|
mkdir -p build/obj/
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rfv build/ $(PROGRAM_NAME)
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define PROGRAM_NAME "SWG"
|
||||||
|
#define PROGRAM_VERSION 1
|
||||||
|
#define PROGRAM_VERSION_NAME "0.1-dev"
|
||||||
|
#define PROGRAM_COPYRIGHT "luca0N!"
|
||||||
|
#define PROGRAM_COPYRIGHT_YEARS "2022"
|
||||||
|
|
||||||
|
#define RETURN_SUCCESSFUL 0
|
||||||
|
|
||||||
|
#define RETURN_FAILED_INVALID_SYNTAX 1
|
||||||
|
#define RETURN_FAILED_CONFIG_INVALID_SYNTAX 2
|
||||||
|
#define RETURN_FAILED_INVALID_DIRECTORY 3
|
||||||
|
#define RETURN_FAILED_WEBSITE_BUILD_EXISTS 4
|
||||||
|
|
||||||
|
#define RETURN_FAILED_UNKNOWN_ERROR 10
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* 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 "ConfigUtils.hxx"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "Common.hxx"
|
||||||
|
|
||||||
|
void parse_config(SwgContext *ctx, std::string const &path) {
|
||||||
|
std::string ctxCfgPath = path;
|
||||||
|
ctxCfgPath += "/swg.cfg";
|
||||||
|
|
||||||
|
FILE *ctxCfgFile = fopen(ctxCfgPath.c_str(), "r");
|
||||||
|
|
||||||
|
if (ctxCfgFile == NULL) {
|
||||||
|
std::cerr << "error: cannot open swg.cfg file, are you sure "
|
||||||
|
<< path << " is a valid SWG directory?" << std::endl;
|
||||||
|
perror(ctxCfgPath.c_str());
|
||||||
|
exit(RETURN_FAILED_INVALID_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buflen = 16;
|
||||||
|
char cbuf[buflen];
|
||||||
|
|
||||||
|
// Yes, this looks ugly, but it works for now. Will probably optimize
|
||||||
|
// this in the future :)
|
||||||
|
//
|
||||||
|
// TODO: Optimize config file interpretation
|
||||||
|
|
||||||
|
std::list<std::string> lines = { "" };
|
||||||
|
while (fgets(cbuf, buflen, ctxCfgFile) != NULL) {
|
||||||
|
int eol = -1;
|
||||||
|
for (int c = 0; c < buflen; c++) {
|
||||||
|
if (cbuf[c] == '\0') {
|
||||||
|
break;
|
||||||
|
} else if (cbuf[c] == '\n') {
|
||||||
|
eol = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (eol > -1) {
|
||||||
|
cbuf[eol] = '\0';
|
||||||
|
*(--lines.end()) += cbuf;
|
||||||
|
lines.insert(lines.end(), "");
|
||||||
|
} else
|
||||||
|
*(--lines.end()) += cbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(ctxCfgFile);
|
||||||
|
|
||||||
|
std::cout << "Done loading configuration file in memory" << std::endl;
|
||||||
|
|
||||||
|
// Parse configuration file
|
||||||
|
|
||||||
|
enum ConfigNamespace { General, Blogs };
|
||||||
|
ConfigNamespace ns;
|
||||||
|
|
||||||
|
int blogCount = 0;
|
||||||
|
Blog *currentBlog = NULL; // (Blog*) malloc(sizeof(Blog));
|
||||||
|
|
||||||
|
// currentBlog->name = "asd";
|
||||||
|
|
||||||
|
for (std::string line : lines) {
|
||||||
|
// Skip comment lines
|
||||||
|
if (line.c_str()[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line.c_str()[0] == '[') {
|
||||||
|
if (line == "[General]") {
|
||||||
|
ns = General;
|
||||||
|
continue;
|
||||||
|
} else if (line == "[Blogs]") {
|
||||||
|
ns = Blogs;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
std::cerr << "error: unknown namespace in config file: " << line << std::endl;
|
||||||
|
exit(RETURN_FAILED_CONFIG_INVALID_SYNTAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip empty lines
|
||||||
|
if (line == "") continue;
|
||||||
|
|
||||||
|
int end = line.find("=");
|
||||||
|
std::string k = line.substr(0, end),
|
||||||
|
v = line.substr(end + 2,
|
||||||
|
(line.length() - 1) - (end + 2));
|
||||||
|
|
||||||
|
switch (ns) {
|
||||||
|
case General:
|
||||||
|
if (k == "WebsiteName")
|
||||||
|
ctx->websiteName = v;
|
||||||
|
else if (k == "WebsitePublisher")
|
||||||
|
ctx->websitePublisher = v;
|
||||||
|
else if (k == "WebsiteCopyrightHolder")
|
||||||
|
ctx->websiteCopyrightHolder = v;
|
||||||
|
else if (k == "WebsiteCopyrightYears")
|
||||||
|
ctx->websiteCopyrightYears = v;
|
||||||
|
else if (k == "websiteContentLicense")
|
||||||
|
ctx->websiteContentLicense = v;
|
||||||
|
else
|
||||||
|
std::cerr << "warning: unknown key in namespace \"General\": " << k << std::endl;
|
||||||
|
continue;
|
||||||
|
case Blogs:
|
||||||
|
// FIXME: This code only accepts up to 9 blogs.
|
||||||
|
if (line.substr(0, 4) == "Blog") {
|
||||||
|
// Check No.
|
||||||
|
int blogNo = atoi(line.substr(4, 1).c_str());
|
||||||
|
if (blogNo != blogCount &&
|
||||||
|
blogNo != blogCount +1){
|
||||||
|
std::cerr << "error: blog declaration must be incremental (received "
|
||||||
|
<< blogNo << " instead of " << blogCount << " or " << blogCount + 1
|
||||||
|
<< ")" << std::endl;
|
||||||
|
exit(RETURN_FAILED_CONFIG_INVALID_SYNTAX);
|
||||||
|
} else if (blogNo == blogCount + 1) {
|
||||||
|
blogCount++;
|
||||||
|
if (currentBlog != NULL) ctx->blogs.push_back(currentBlog);
|
||||||
|
currentBlog = (Blog*) malloc(sizeof(Blog));
|
||||||
|
// Clear allocated memory
|
||||||
|
memset(currentBlog, 0, sizeof(Blog));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(currentBlog != NULL);
|
||||||
|
//std::cout << "Attempting to set K/V" << std::endl;
|
||||||
|
|
||||||
|
if (k.substr(5) == "Path") {
|
||||||
|
//std::cout << "Setting path (" << v << ") for " << blogCount << std::endl;
|
||||||
|
strncpy(currentBlog->path, v.c_str(), sizeof(currentBlog->path));
|
||||||
|
} else if (k.substr(5) == "Name") {
|
||||||
|
//std::cout << "Setting name (" << v << ") for " << blogCount << std::endl;
|
||||||
|
strncpy(currentBlog->name, v.c_str(), sizeof(currentBlog->name));
|
||||||
|
} else if (k.substr(5) == "Dir") {
|
||||||
|
strncpy(currentBlog->dir, v.c_str(), sizeof(currentBlog->dir));
|
||||||
|
} else {
|
||||||
|
std::cerr << "warning: unknown key in namespace \"Blogs\": " << k << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentBlog != NULL) ctx->blogs.push_back(currentBlog);
|
||||||
|
/*std::cout << "Loaded " << blogCount << " blogs into memory" << std::endl;
|
||||||
|
for (Blog *b : ctx->blogs) {
|
||||||
|
std::cout << "\t" << b->name << ": " << b->path << std::endl;
|
||||||
|
}*/
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "SwgContext.hxx"
|
||||||
|
|
||||||
|
void parse_config(SwgContext *ctx, std::string const &path);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
struct Blog {
|
||||||
|
char name[64],
|
||||||
|
path[64],
|
||||||
|
dir[64];
|
||||||
|
int test;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SwgContext {
|
||||||
|
std::string websiteName,
|
||||||
|
websitePublisher,
|
||||||
|
websiteCopyrightHolder,
|
||||||
|
websiteCopyrightYears,
|
||||||
|
websiteContentLicense;
|
||||||
|
|
||||||
|
// TODO: Use smart pointers
|
||||||
|
std::list<Blog*> blogs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*class SwgContext {
|
||||||
|
public:
|
||||||
|
SwgContext();
|
||||||
|
SwgContext(std::string websiteName, std::string websitePublisher, std::string copyrightHolder, std::string copyrightYears, std::string contentLicense);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string websiteName, websitePublisher;
|
||||||
|
std::string copyrightHolder, copyrightYears, contentLicense;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlogEntry {
|
||||||
|
public:
|
||||||
|
BlogEntry(std::string name, std::string path);
|
||||||
|
std::string getBlogName();
|
||||||
|
std::string getBlogPath();
|
||||||
|
private:
|
||||||
|
std::string path, name;
|
||||||
|
};*/
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 "SwgRuntime.hxx"
|
||||||
|
|
||||||
|
bool swg_rt_global_bool(const char *name, bool ifne) {
|
||||||
|
// TODO: Check for runtime option and return it (if it's set, return ifne otherwise).
|
||||||
|
return ifne;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Utilities for options set during runtime by the end-user (i.e. through command line options).
|
||||||
|
|
||||||
|
bool swg_rt_global_bool(const char *name, bool ifne);
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* 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 <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "SwgRuntime.hxx"
|
||||||
|
#include "SwgContext.hxx"
|
||||||
|
#include "ConfigUtils.hxx"
|
||||||
|
// #include "Blog.h"
|
||||||
|
#include "Common.hxx"
|
||||||
|
|
||||||
|
std::string blog_relative_path(std::string const &pathPrefix, std::string const &path) {
|
||||||
|
return path.substr(pathPrefix.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFilename(std::string const &path) {
|
||||||
|
// Backwards search for directory separator.
|
||||||
|
for (int x = path.length(); x > 0; --x) {
|
||||||
|
if (path[x] == '/')
|
||||||
|
return path.substr(x + 1);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValidArticle(std::string const &pathPrefix, std::string const &path) {
|
||||||
|
return std::regex_search(blog_relative_path(pathPrefix, path), std::regex("^/\\d{4}/\\d{2}/.*\\.md"));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path get_output_path(std::string const &path) {
|
||||||
|
std::filesystem::path output = path;
|
||||||
|
return output /= "output";
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_dir_structure(std::string const &path) {
|
||||||
|
// Create directory tree, which will be used for the website.
|
||||||
|
std::filesystem::path rootDir = get_output_path(path);
|
||||||
|
|
||||||
|
// Create output directory if it doesn't exist.
|
||||||
|
try {
|
||||||
|
if(!std::filesystem::exists(rootDir)) std::filesystem::create_directory(rootDir);
|
||||||
|
} catch (std::filesystem::filesystem_error const &e) {
|
||||||
|
std::cerr << "error: fs error while generating output website directory structure on \""
|
||||||
|
<< path << "\": " << e.what() << std::endl;
|
||||||
|
exit(RETURN_FAILED_UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a website has already been built.
|
||||||
|
//
|
||||||
|
// This is a safe measure to prevent overwriting an existing website
|
||||||
|
// output, but it can be skipped if explicitly asked by the end-user.
|
||||||
|
if (!swg_rt_global_bool("overwrite_existing", false)) {
|
||||||
|
std::filesystem::path websiteLock = rootDir /= ".swg_built";
|
||||||
|
if (std::filesystem::exists(websiteLock)) {
|
||||||
|
std::cout << "error: existing website build detected, exiting...\n";
|
||||||
|
exit(RETURN_FAILED_WEBSITE_BUILD_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_template(std::string const &path) {
|
||||||
|
// Template lookup
|
||||||
|
std::string stPath = path;
|
||||||
|
stPath += "/__swg_template.html";
|
||||||
|
FILE *swgTemplate = fopen(stPath.c_str(), "r");
|
||||||
|
if (swgTemplate == NULL) {
|
||||||
|
std::cerr << "error: couldn't open the SWG HTML template file; does it exist?\n";
|
||||||
|
perror(stPath.c_str());
|
||||||
|
exit(RETURN_FAILED_INVALID_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for content placeholder
|
||||||
|
int buflen = 8;
|
||||||
|
char buf[buflen];
|
||||||
|
std::string htmlTemplate;
|
||||||
|
while (fgets(buf, buflen, swgTemplate) != NULL) {
|
||||||
|
htmlTemplate += buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(swgTemplate);
|
||||||
|
std::cout << "Loaded HTML template into memory.\n";
|
||||||
|
return htmlTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_blog_structure(std::string const &path, std::string const &prefix, std::list<std::string> const &articles, Blog *blog) {
|
||||||
|
std::filesystem::path obp = get_output_path(path) /= blog->dir; // Output Blog Path
|
||||||
|
try {
|
||||||
|
// Create blog directory
|
||||||
|
if (!std::filesystem::exists(obp)) std::filesystem::create_directory(obp);
|
||||||
|
} catch (std::filesystem::filesystem_error const &e) {
|
||||||
|
std::cerr << "error: failed to create directory for blog \"" << blog->name << "\": " << e.what() << std::endl;
|
||||||
|
exit(RETURN_FAILED_UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::string const &a : articles) {
|
||||||
|
std::string articlePath = blog_relative_path(prefix, a);
|
||||||
|
std::regex yearMonth("(\\d+)");
|
||||||
|
auto match = std::sregex_iterator(articlePath.begin(), articlePath.end(), yearMonth);
|
||||||
|
|
||||||
|
std::string year = match->str(),
|
||||||
|
month = (++match)->str();
|
||||||
|
|
||||||
|
/*std::cout << "Year for \"" << articlePath << "\": " << year << "\n";
|
||||||
|
std::cout << "Month for \"" << articlePath << "\": " << month << "\n";*/
|
||||||
|
|
||||||
|
// TODO: This code could be optimized by removing directory
|
||||||
|
// checks for every single article. Instead, add
|
||||||
|
// directory-checks for years and months to a queue (skipping
|
||||||
|
// existing ones) and then checking and creating the
|
||||||
|
// directories later as needed.
|
||||||
|
try {
|
||||||
|
// Create directory for the year of this article if it doesn't exist.
|
||||||
|
std::filesystem::path oad = obp /= year; // Output Article Directory
|
||||||
|
if (!std::filesystem::exists(oad)) std::filesystem::create_directory(oad);
|
||||||
|
|
||||||
|
// Do the same for the article month.
|
||||||
|
oad /= month;
|
||||||
|
if (!std::filesystem::exists(oad)) std::filesystem::create_directory(oad);
|
||||||
|
|
||||||
|
// Now create the article file.
|
||||||
|
oad /= getFilename(a);
|
||||||
|
FILE *articleOutput = fopen(oad.string().c_str(), "w");
|
||||||
|
FILE *articleFile = fopen(a.c_str(), "r");
|
||||||
|
|
||||||
|
std::string articleContents;
|
||||||
|
|
||||||
|
int buflen = 512;
|
||||||
|
char buf[buflen];
|
||||||
|
|
||||||
|
while (fgets(buf, buflen, articleFile) != NULL) {
|
||||||
|
articleContents += buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(articleFile);
|
||||||
|
|
||||||
|
std::string htmlTemplate = get_template(path);
|
||||||
|
// NOTE: std::regex requires the C++11 standard.
|
||||||
|
std::regex contentPlaceholder("<!--\\[_SWG: \\$CONTENT\\]-->");
|
||||||
|
articleContents = std::regex_replace(htmlTemplate, contentPlaceholder, articleContents);
|
||||||
|
|
||||||
|
fputs(articleContents.c_str(), articleOutput);
|
||||||
|
|
||||||
|
fclose(articleOutput);
|
||||||
|
} catch (std::filesystem::filesystem_error const &e) {
|
||||||
|
std::cerr << "error: failed to create directory for an article from blog \""
|
||||||
|
<< blog->name << "\": " << e.what() << std::endl;
|
||||||
|
exit(RETURN_FAILED_UNKNOWN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_website(SwgContext &ctx, std::string const &path) {
|
||||||
|
build_dir_structure(path);
|
||||||
|
|
||||||
|
// Blog lookup
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
for (Blog *b : ctx.blogs) {
|
||||||
|
std::list<std::string> parsedArticles = { },
|
||||||
|
failedArticles = { };
|
||||||
|
|
||||||
|
// std::filesystem requires the C++17 standard.
|
||||||
|
std::string relativePath = path;
|
||||||
|
relativePath += "/";
|
||||||
|
relativePath += b->path;
|
||||||
|
const std::filesystem::path blogPath(relativePath);
|
||||||
|
try {
|
||||||
|
for (auto const &dir_entry : std::filesystem::recursive_directory_iterator(blogPath)) {
|
||||||
|
// Directory item iteration
|
||||||
|
std::cout << "\t" << dir_entry << std::endl;
|
||||||
|
|
||||||
|
// Check if the item is a Markdown file.
|
||||||
|
std::string filename = getFilename(dir_entry.path());
|
||||||
|
if (dir_entry.is_regular_file() &&
|
||||||
|
filename.find(".md") == filename.length() - 3) {
|
||||||
|
std::cout << "\t\tIs file: " << getFilename(dir_entry.path()) << "\n";
|
||||||
|
// Markdown files should be insite a YYYY/MM directory.
|
||||||
|
if (!isValidArticle(relativePath, dir_entry.path()))
|
||||||
|
failedArticles.insert(failedArticles.end(), dir_entry.path());
|
||||||
|
else parsedArticles.insert(parsedArticles.end(), dir_entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (std::filesystem::filesystem_error const &e) {
|
||||||
|
std::cerr << "error: fs error while attempting to read path for "
|
||||||
|
<< b->name << ": " << e.what() << std::endl;
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*std::cout << "Parsed " << parsedArticles << " articles;\n" <<
|
||||||
|
"Failed to parse " << failedArticles << " articles\n";*/
|
||||||
|
|
||||||
|
for (std::string const &a : parsedArticles)
|
||||||
|
std::cout << "Parsed: " << a << "\n";
|
||||||
|
for (std::string const &a : failedArticles)
|
||||||
|
std::cout << "Unable to parse: " << a << "\n";
|
||||||
|
|
||||||
|
build_blog_structure(path, relativePath, parsedArticles, b);
|
||||||
|
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
std::cerr << "Refusing to proceed due to previous errors\n";
|
||||||
|
exit(RETURN_FAILED_CONFIG_INVALID_SYNTAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Website blog
|
||||||
|
|
||||||
|
// Append blog to website
|
||||||
|
//ctx.appendBlog(blog1);
|
||||||
|
|
||||||
|
// Generate website
|
||||||
|
//ctx.generateWebsite();
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SwgContext.hxx"
|
||||||
|
|
||||||
|
void build_website(SwgContext &ctx, std::string const &path);
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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 <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "SwgContext.hxx"
|
||||||
|
#include "ConfigUtils.hxx"
|
||||||
|
// #include "Blog.h"
|
||||||
|
#include "Common.hxx"
|
||||||
|
#include "WebsiteBuilder.hxx"
|
||||||
|
|
||||||
|
void printUsage(const char *programName) {
|
||||||
|
std::cerr << programName << ": usage: " << programName << " [path]"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIntro() {
|
||||||
|
printf("%s v%s (%d)\nCopyright (C) %s %s\n\n",
|
||||||
|
PROGRAM_NAME, PROGRAM_VERSION_NAME, PROGRAM_VERSION,
|
||||||
|
PROGRAM_COPYRIGHT_YEARS, PROGRAM_COPYRIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printIntro();
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
|
||||||
|
// Parse cmdline options
|
||||||
|
switch (argc) {
|
||||||
|
case 1:
|
||||||
|
path = ".";
|
||||||
|
std::cout << "Assuming working directory is \".\""
|
||||||
|
<< std::endl;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
path = argv[1];
|
||||||
|
std::cout << "Using specified directory: "
|
||||||
|
<< path << std::endl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printUsage(argv[0]);
|
||||||
|
exit(RETURN_FAILED_INVALID_SYNTAX);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwgContext ctx;
|
||||||
|
parse_config(&ctx, path);
|
||||||
|
|
||||||
|
build_website(ctx, path);
|
||||||
|
|
||||||
|
// Website blog
|
||||||
|
|
||||||
|
// Append blog to website
|
||||||
|
//ctx.appendBlog(blog1);
|
||||||
|
|
||||||
|
// Generate website
|
||||||
|
//ctx.generateWebsite();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue