From 91dbcebb20e975d25cd6b61f2e42a9e1ab73bdbc Mon Sep 17 00:00:00 2001 From: nishi Date: Sun, 5 May 2024 06:16:20 +0000 Subject: [PATCH] xml parsing git-svn-id: file:///raid/svn-main/nishi-clover/trunk@5 cc13bd98-b292-b64a-ad22-c0789b689ca7 --- Makefile | 2 +- clover.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f59851e..811e3aa 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = cc CFLAGS = -g -std=c99 LDFLAGS = -LIBS = +LIBS = -lexpat CLOVER_OBJS = clover.o diff --git a/clover.c b/clover.c index e8307b1..89b6ccc 100644 --- a/clover.c +++ b/clover.c @@ -28,13 +28,17 @@ /* -------------------------------------------------------------------------- */ /* --- END LICENSE --- */ +#include #include #include #include #include #include +#include #include +#include + #define CLOVER_VERSION "0.00" char* concat_str(const char* str1, const char* str2) { @@ -45,6 +49,13 @@ 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)); @@ -112,6 +123,149 @@ int parse_config(const char* path) { 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, "\n"); + fprintf(f, "\n"); + fprintf(f, " \n"); + fprintf(f, " \n"); + if(page_title != NULL) { + fprintf(f, " %s - %s\n", title, page_title); + } else { + fprintf(f, " %s\n", title); + } + fprintf(f, " \n"); + fprintf(f, " \n"); + if(page_title != NULL) { + fprintf(f, "

%s - %s

\n", title, page_title); + } else { + fprintf(f, "

%s

\n", title); + } + if(page_data != NULL) { + fprintf(f, "%s\n", page_data); + } + fprintf(f, "
\n"); + fprintf(f, " Last modified: %s
\n", lastmod); + fprintf(f, " Generated by Clover %s\n", CLOVER_VERSION); + fprintf(f, " \n"); + fprintf(f, "\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"); @@ -123,8 +277,10 @@ int main(int argc, char** argv) { 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; } -- 2.43.0