#include <expat.h>
-#define CLOVER_VERSION "0.00"
+#define CLOVER_VERSION "1.0"
char* concat_str(const char* str1, const char* str2) {
char* r = malloc(strlen(str1) + strlen(str2) + 1);
char* input_dir;
char* output_dir;
char* title;
+char* icon;
+char* http_path;
+char* static_dir;
int parse_config(const char* path) {
FILE* f = fopen(path, "r");
free(input_dir);
input_dir = dup_str(str + i);
}
+ } else if(strcmp(str, "static") == 0) {
+ if(found) {
+ free(static_dir);
+ static_dir = dup_str(str + i);
+ }
} else if(strcmp(str, "title") == 0) {
if(found) {
free(title);
title = dup_str(str + i);
}
+ } else if(strcmp(str, "icon") == 0) {
+ if(found) {
+ free(icon);
+ icon = dup_str(str + i);
+ }
+ } else if(strcmp(str, "http-path") == 0) {
+ if(found) {
+ free(http_path);
+ http_path = dup_str(str + i);
+ }
}
free(str);
str = malloc(1);
}
int typearr[1024];
+int typearr2[1024];
int depth;
+int depth2;
+
+enum TYPES { ELEM_NONE, ELEM_METADATA, ELEM_TITLE, ELEM_PAGE, ELEM_ICON, ELEM_SHORTDESC };
+
+char* page_title;
+char* page_data;
+char* page_icon;
+char* page_shortdesc;
+bool page_index;
-enum TYPES { ELEM_NONE, ELEM_METADATA, ELEM_TITLE, ELEM_PAGE };
+char* page_title2;
+char* page_data2;
+char* page_icon2;
+char* page_shortdesc2;
+bool page_index2;
+bool page_do_not_index2;
static void XMLCALL xml_startelem(void* user_data, const XML_Char* el, const XML_Char* attr[]) {
+ typearr[depth] = ELEM_NONE;
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(strcmp(el, "icon") == 0) typearr[depth] = ELEM_ICON;
+ if(strcmp(el, "short-description") == 0) typearr[depth] = ELEM_SHORTDESC;
+ if(strcmp(el, "index") == 0) page_index = true;
if(depth == 0 && typearr[depth] != ELEM_METADATA) {
fprintf(stderr, "toplevel must be metadata\n");
exit(1);
depth++;
}
+static void XMLCALL xml_startelem2(void* user_data, const XML_Char* el, const XML_Char* attr[]) {
+ typearr2[depth2] = ELEM_NONE;
+ if(strcmp(el, "metadata") == 0) typearr2[depth2] = ELEM_METADATA;
+ if(strcmp(el, "title") == 0) typearr2[depth2] = ELEM_TITLE;
+ if(strcmp(el, "page") == 0) typearr2[depth2] = ELEM_PAGE;
+ if(strcmp(el, "icon") == 0) typearr2[depth2] = ELEM_ICON;
+ if(strcmp(el, "index") == 0) page_index2 = true;
+ if(strcmp(el, "do-not-index") == 0) page_do_not_index2 = true;
+ if(strcmp(el, "short-description") == 0) typearr2[depth2] = ELEM_SHORTDESC;
+ if(depth2 == 0 && typearr2[depth2] != ELEM_METADATA) {
+ fprintf(stderr, "toplevel must be metadata\n");
+ exit(1);
+ }
+ depth2++;
+}
+
static void XMLCALL xml_endelem(void* user_data, const XML_Char* el) { depth--; }
-char* page_title;
-char* page_data;
+static void XMLCALL xml_endelem2(void* user_data, const XML_Char* el) { depth2--; }
static void XMLCALL xml_elemdata(void* user_data, const XML_Char* data, int data_size) {
if(data_size > 0) {
} else {
page_data = dup_str(str);
}
+ } else if(typearr[depth - 1] == ELEM_ICON) {
+ if(page_icon != NULL) {
+ char* tmp = page_icon;
+ page_icon = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_icon = dup_str(str);
+ }
+ } else if(typearr[depth - 1] == ELEM_SHORTDESC) {
+ if(page_shortdesc != NULL) {
+ char* tmp = page_shortdesc;
+ page_shortdesc = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_shortdesc = dup_str(str);
+ }
}
free(str);
}
}
+static void XMLCALL xml_elemdata2(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(typearr2[depth2 - 1] == ELEM_TITLE) {
+ if(page_title2 != NULL) {
+ char* tmp = page_title2;
+ page_title2 = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_title2 = dup_str(str);
+ }
+ } else if(typearr2[depth2 - 1] == ELEM_PAGE) {
+ if(page_data2 != NULL) {
+ char* tmp = page_data2;
+ page_data2 = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_data2 = dup_str(str);
+ }
+ } else if(typearr2[depth2 - 1] == ELEM_ICON) {
+ if(page_icon2 != NULL) {
+ char* tmp = page_icon2;
+ page_icon2 = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_icon2 = dup_str(str);
+ }
+ } else if(typearr2[depth2 - 1] == ELEM_SHORTDESC) {
+ if(page_shortdesc2 != NULL) {
+ char* tmp = page_shortdesc2;
+ page_shortdesc2 = concat_str(tmp, str);
+ free(tmp);
+ } else {
+ page_shortdesc2 = dup_str(str);
+ }
+ }
+ free(str);
+ }
+}
+
+void scan_and_print(FILE* f, const char* path, const char* http){
+ DIR* dir = opendir(path);
+ 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(path, "/", d->d_name);
+ struct stat s;
+ if(stat(p, &s) == 0){
+ if(S_ISDIR(s.st_mode)){
+ char* new_http = concat3_str(http, d->d_name, "/");
+ scan_and_print(f, p, new_http);
+ free(new_http);
+ }else if(strcmp(d->d_name, "metadata.xml") == 0){
+ page_title2 = NULL;
+ page_data2 = NULL;
+ page_icon2 = NULL;
+ page_shortdesc2 = NULL;
+ page_do_not_index2 = false;
+ FILE* fp = fopen(p, "r");
+ XML_Parser sparser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(sparser, xml_startelem2, xml_endelem2);
+ XML_SetCharacterDataHandler(sparser, xml_elemdata2);
+ if(fp != NULL){
+ char* buf = malloc(1024);
+ int done;
+ do{
+ int len = fread(buf, 1, 1024, fp);
+ done = len < 1024;
+ if(XML_Parse(sparser, buf, len, done) == XML_STATUS_ERROR){
+ break;
+ }
+ }while(!done);
+ free(buf);
+ fclose(fp);
+ }
+ XML_ParserFree(sparser);
+ if(!page_do_not_index2){
+ fprintf(f, "<dt><a href=\"%s%s\">", http_path, http);
+ if(page_icon2 != NULL) fprintf(f, "<img src=\"/static/%s\">", page_icon2);
+ if(page_icon2 != NULL) fprintf(f, "</a> ");
+ if(page_title2 != NULL) fprintf(f, "<b>%s </b>", page_title2);
+ if(page_icon2 == NULL) fprintf(f, "</a>");
+ fprintf(f, "</dt>\n");
+ if(page_shortdesc2 != NULL){
+ fprintf(f, "<dd>%s</dd>\n", page_shortdesc2);
+ }
+ }
+ if(page_title2 != NULL) free(page_title2);
+ if(page_data2 != NULL) free(page_data2);
+ if(page_icon2 != NULL) free(page_icon2);
+ if(page_shortdesc2 != NULL) free(page_shortdesc2);
+ }
+ }
+ free(p);
+ }
+ closedir(dir);
+ }
+}
+
int parse_xml(const char* xml, const char* outdir) {
printf("%s...\n", xml);
depth = 0;
page_title = NULL;
page_data = NULL;
+ page_icon = NULL;
+ page_index = false;
+ page_shortdesc = NULL;
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, xml_startelem, xml_endelem);
XML_SetCharacterDataHandler(parser, xml_elemdata);
} else {
fprintf(f, " <title>%s</title>\n", title);
}
+ fprintf(f, " <link rel=\"icon\" href=\"/static/%s\">\n", icon);
fprintf(f, " </head>\n");
fprintf(f, " <body>\n");
+ fprintf(f, " <a href=\"%s\"><img src=\"/static/%s\"></a>\n", http_path, icon);
+ if(page_icon != NULL){
+ char* from_path = concat3_str(static_dir, "/", page_icon);
+ char* to_path = concat3_str(output_dir, "/static/", page_icon);
+ FILE* from = fopen(from_path, "rb");
+ FILE* to = fopen(to_path, "wb");
+ if(from != NULL){
+ char* buf = malloc(1024);
+ int done = 0;
+ do{
+ int len = fread(buf, 1, 1024, from);
+ fwrite(buf, 1, len, to);
+ done = len < 1024;
+ }while(!done);
+ free(buf);
+ fclose(from);
+ }
+ fclose(to);
+ free(from_path);
+ free(to_path);
+ fprintf(f, " <img src=\"/static/%s\">\n", page_icon);
+ }
if(page_title != NULL) {
fprintf(f, " <h1>%s - %s</h1>\n", title, page_title);
} else {
if(page_data != NULL) {
fprintf(f, "%s\n", page_data);
}
+ if(page_index){
+ fprintf(f, " <hr>\n");
+ fprintf(f, " <dl>\n");
+ scan_and_print(f, input_dir, "");
+ fprintf(f, " </dl>\n");
+ }
fprintf(f, " <hr>\n");
fprintf(f, " <i>Last modified: %s</i><br>\n", lastmod);
- fprintf(f, " <i>Generated by Clover %s $Id$</i>\n", CLOVER_VERSION);
+ fprintf(f, " <i>Generated by Clover %s</i>\n", CLOVER_VERSION);
fprintf(f, " </body>\n");
fprintf(f, "</html>\n");
fclose(f);
free(html);
if(page_title != NULL) free(page_title);
if(page_data != NULL) free(page_data);
+ if(page_icon != NULL) free(page_icon);
+ if(page_shortdesc != NULL) free(page_shortdesc);
return 0;
}
output_dir = dup_str("webroot");
input_dir = dup_str("input");
title = dup_str("Unnamed");
+ icon = dup_str("icon.png");
+ static_dir = dup_str("static");
+ http_path = dup_str("/");
int r;
if(argv[1] == NULL) {
r = parse_config("clover.conf");
}
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);
+ printf(" Icon: %s\n", icon);
+ printf(" Title: %s\n", title);
+ printf(" Input: %s\n", input_dir);
+ printf(" Output: %s\n", output_dir);
+ printf(" HTTP Path: %s\n", http_path);
+ printf("Static Path: %s\n", static_dir);
+ char* staticp = concat_str(output_dir, "/static");
+ mkdir(staticp, 0775);
+ char* toicon = concat3_str(staticp, "/", icon);
+ FILE* ficon = fopen(toicon, "wb");
+ char* iconpath = concat3_str(static_dir, "/", icon);
+ FILE* from = fopen(iconpath, "rb");
+ if(from != NULL){
+ char* buf = malloc(1024);
+ int done = 0;
+ do{
+ int len = fread(buf, 1, 1024, from);
+ fwrite(buf, 1, len, ficon);
+ done = len < 1024;
+ }while(!done);
+ free(buf);
+ fclose(from);
+ }
+ fclose(ficon);
+ free(toicon);
+ free(staticp);
+ free(iconpath);
generate(input_dir, output_dir);
if(r != 0) return r;
}