/* -------------------------------------------------------------------------- */
/* --- END LICENSE --- */
+#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <time.h>
#include <unistd.h>
+#include <expat.h>
+
#define CLOVER_VERSION "0.00"
char* concat_str(const char* str1, const char* str2) {
return r;
}
+char* concat3_str(const char* str1, const char* str2, const char* str3) {
+ char* tmp = concat_str(str1, str2);
+ char* str = concat_str(tmp, str3);
+ free(tmp);
+ return str;
+}
+
char* dup_str(const char* str) {
char* r = malloc(strlen(str) + 1);
memcpy(r, str, strlen(str));
return 0;
}
+int typearr[1024];
+int depth;
+
+enum TYPES { ELEM_NONE, ELEM_METADATA, ELEM_TITLE, ELEM_PAGE };
+
+static void XMLCALL xml_startelem(void* user_data, const XML_Char* el, const XML_Char* attr[]) {
+ if(strcmp(el, "metadata") == 0) typearr[depth] = ELEM_METADATA;
+ if(strcmp(el, "title") == 0) typearr[depth] = ELEM_TITLE;
+ if(strcmp(el, "page") == 0) typearr[depth] = ELEM_PAGE;
+ if(depth == 0 && typearr[depth] != ELEM_METADATA) {
+ fprintf(stderr, "toplevel must be metadata\n");
+ exit(1);
+ }
+ depth++;
+}
+
+static void XMLCALL xml_endelem(void* user_data, const XML_Char* el) { depth--; }
+
+char* page_title;
+char* page_data;
+
+static void XMLCALL xml_elemdata(void* user_data, const XML_Char* data, int data_size) {
+ if(data_size > 0) {
+ char* str = malloc(data_size + 1);
+ memcpy(str, data, data_size);
+ str[data_size] = 0;
+ if(typearr[depth - 1] == ELEM_TITLE) {
+ if(page_title != NULL) {
+ char* tmp = page_title;
+ page_title = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_title = dup_str(str);
+ }
+ } else if(typearr[depth - 1] == ELEM_PAGE) {
+ if(page_data != NULL) {
+ char* tmp = page_data;
+ page_data = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_data = dup_str(str);
+ }
+ }
+ free(str);
+ }
+}
+
+int parse_xml(const char* xml, const char* outdir) {
+ printf("%s...\n", xml);
+ depth = 0;
+ page_title = NULL;
+ page_data = NULL;
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(parser, xml_startelem, xml_endelem);
+ XML_SetCharacterDataHandler(parser, xml_elemdata);
+ FILE* f = fopen(xml, "r");
+ char* buffer = malloc(1024);
+ int done = 0;
+ do {
+ int len = fread(buffer, 1, 1024, f);
+ done = len < 1024;
+ if(XML_Parse(parser, buffer, len, done) == XML_STATUS_ERROR) {
+ fprintf(stderr, "XML parse error\n");
+ XML_ParserFree(parser);
+ fclose(f);
+ free(buffer);
+ return 1;
+ }
+ } while(!done);
+ fclose(f);
+ free(buffer);
+ XML_ParserFree(parser);
+ char* html = concat_str(outdir, "/index.html");
+ f = fopen(html, "w");
+ if(f != NULL) {
+ char* lastmod = malloc(513);
+ struct stat s;
+ stat(xml, &s);
+ struct tm* tm = localtime(&s.st_mtime);
+ strftime(lastmod, 512, "%a %b %e %H:%M:%S %Z %Y", tm);
+ fprintf(f, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n");
+ fprintf(f, "<html>\n");
+ fprintf(f, " <head>\n");
+ fprintf(f, " <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
+ if(page_title != NULL) {
+ fprintf(f, " <title>%s - %s</title>\n", title, page_title);
+ } else {
+ fprintf(f, " <title>%s</title>\n", title);
+ }
+ fprintf(f, " </head>\n");
+ fprintf(f, " <body>\n");
+ if(page_title != NULL) {
+ fprintf(f, " <h1>%s - %s</h1>\n", title, page_title);
+ } else {
+ fprintf(f, " <h1>%s</h1>\n", title);
+ }
+ if(page_data != NULL) {
+ fprintf(f, "%s\n", page_data);
+ }
+ fprintf(f, " <hr>\n");
+ fprintf(f, " <i>Last modified: %s</i><br>\n", lastmod);
+ fprintf(f, " <i>Generated by Clover %s</i>\n", CLOVER_VERSION);
+ fprintf(f, " </body>\n");
+ fprintf(f, "</html>\n");
+ fclose(f);
+ free(lastmod);
+ }
+ free(html);
+ if(page_title != NULL) free(page_title);
+ if(page_data != NULL) free(page_data);
+ return 0;
+}
+
+void generate(const char* input, const char* output) {
+ mkdir(output, 0775);
+ DIR* dir = opendir(input);
+ if(dir != NULL) {
+ struct dirent* d;
+ while((d = readdir(dir)) != NULL) {
+ if(strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) continue;
+ char* p = concat3_str(input, "/", d->d_name);
+ struct stat s;
+ if(stat(p, &s) == 0) {
+ if(S_ISDIR(s.st_mode)) {
+ char* op = concat3_str(output, "/", d->d_name);
+ generate(p, op);
+ free(op);
+ } else if(strcmp(d->d_name, "metadata.xml") == 0) {
+ char* xml = concat3_str(input, "/", d->d_name);
+ if(parse_xml(xml, output) == 1) {
+ free(xml);
+ free(p);
+ break;
+ }
+ free(xml);
+ }
+ }
+ free(p);
+ }
+ closedir(dir);
+ }
+}
+
int main(int argc, char** argv) {
output_dir = dup_str("webroot");
input_dir = dup_str("input");
r = parse_config(argv[1]);
}
printf("Clover %s Copyright (c) 2024 Nishi\n", CLOVER_VERSION);
+ printf("Using Expat %d.%d.%d\n", XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
printf(" Title: %s\n", title);
printf(" Input: %s\n", input_dir);
printf("Output: %s\n", output_dir);
+ generate(input_dir, output_dir);
if(r != 0) return r;
}