]> Nishi Git Mirror - clover.git/commitdiff
xml parsing
authornishi <nishi@cc13bd98-b292-b64a-ad22-c0789b689ca7>
Sun, 5 May 2024 06:16:20 +0000 (06:16 +0000)
committernishi <nishi@cc13bd98-b292-b64a-ad22-c0789b689ca7>
Sun, 5 May 2024 06:16:20 +0000 (06:16 +0000)
git-svn-id: file:///raid/svn-main/nishi-clover/trunk@5 cc13bd98-b292-b64a-ad22-c0789b689ca7

Makefile
clover.c

index f59851e73bb7c62aa45dd1a6063d4450eba6e6a1..811e3aa8a3d3c18970182d37dc0736f662a016bb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 CC = cc
 CFLAGS = -g -std=c99
 LDFLAGS =
-LIBS =
+LIBS = -lexpat
 
 CLOVER_OBJS = clover.o
 
index e8307b1f35d16d2c95cb7e0be54131f3f48f25d9..89b6cccd474ec728e8da655a28b3ea6687726006 100644 (file)
--- a/clover.c
+++ b/clover.c
 /* -------------------------------------------------------------------------- */
 /* --- 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) {
@@ -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, "<!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");
@@ -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;
 }