gout

A static git page generator
git clone https://git.bracken.jp/gout.git
Log | Files | Refs | README | LICENSE

atom.c (4029B)


      1 #include "atom.h"
      2 
      3 #include <assert.h>
      4 #include <err.h>
      5 #include <stdbool.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 
     10 #include "format.h"
     11 #include "utils.h"
     12 
     13 struct Atom {
     14   const GitRepo* repo;
     15   const char* baseurl;
     16   FILE* out;
     17   size_t remaining_commits;
     18 };
     19 
     20 Atom* atom_create(const GitRepo* repo, FILE* out) {
     21   assert(repo != NULL);
     22   assert(out != NULL);
     23   Atom* atom = ecalloc(1, sizeof(Atom));
     24   atom->repo = repo;
     25   atom->baseurl = "";
     26   atom->out = out;
     27   atom->remaining_commits = 100;
     28   return atom;
     29 }
     30 
     31 void atom_free(Atom* atom) {
     32   if (!atom) {
     33     return;
     34   }
     35   atom->out = NULL;
     36   free(atom);
     37 }
     38 
     39 void atom_set_baseurl(Atom* atom, const char* baseurl) {
     40   assert(atom != NULL);
     41   assert(baseurl != NULL);
     42   atom->baseurl = baseurl;
     43 }
     44 
     45 void atom_begin(Atom* atom) {
     46   assert(atom != NULL);
     47   fprintf(atom->out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
     48   fprintf(atom->out, "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n");
     49   fprintf(atom->out, "<title>");
     50   if (atom->repo->short_name) {
     51     print_xml_encoded(atom->out, atom->repo->short_name);
     52   }
     53   fprintf(atom->out, ", branch HEAD</title>\n");
     54   fprintf(atom->out, "<subtitle>");
     55   if (atom->repo->description) {
     56     print_xml_encoded(atom->out, atom->repo->description);
     57   }
     58   fprintf(atom->out, "</subtitle>\n");
     59 }
     60 
     61 void atom_add_commit(Atom* atom,
     62                      const GitCommit* commit,
     63                      const char* path,
     64                      const char* content_type,
     65                      const char* tag) {
     66   assert(atom != NULL);
     67   assert(commit != NULL);
     68   assert(path != NULL);
     69   assert(path[0] != '\0');
     70   assert(content_type != NULL);
     71 
     72   FILE* out = atom->out;
     73   if (atom->remaining_commits == 0) {
     74     return;
     75   }
     76   if (commit->oid[0] == '\0') {
     77     warnx("atom: processed commit with missing/empty object ID");
     78     return;
     79   }
     80   atom->remaining_commits--;
     81 
     82   fprintf(out, "<entry>\n");
     83   fprintf(out, "<id>%s</id>\n", commit->oid);
     84 
     85   fprintf(out, "<published>");
     86   print_time_z(out, commit->author_time);
     87   fprintf(out, "</published>\n");
     88 
     89   fprintf(out, "<updated>");
     90   print_time_z(out, commit->commit_time);
     91   fprintf(out, "</updated>\n");
     92 
     93   if (commit->summary) {
     94     fprintf(out, "<title>");
     95     if (tag && tag[0] != '\0') {
     96       fprintf(out, "[");
     97       print_xml_encoded(out, tag);
     98       fprintf(out, "]");
     99     }
    100     print_xml_encoded(out, commit->summary);
    101     fprintf(out, "</title>\n");
    102   }
    103   fprintf(out, "<link rel=\"alternate\" ");
    104   if (strlen(content_type) > 0) {
    105     fprintf(out, "type=\"%s\" ", content_type);
    106   }
    107   size_t baseurl_len = strlen(atom->baseurl);
    108   const char* p = path;
    109   if (baseurl_len > 0 && atom->baseurl[baseurl_len - 1] == '/' && p[0] == '/') {
    110     p++;
    111   }
    112   bool needs_slash =
    113       (baseurl_len > 0 && atom->baseurl[baseurl_len - 1] != '/' && p[0] != '/');
    114   fprintf(out, "href=\"%s%s%s\" />\n", atom->baseurl, needs_slash ? "/" : "",
    115           p);
    116 
    117   fprintf(out, "<author>\n<name>");
    118   if (commit->author_name) {
    119     print_xml_encoded(out, commit->author_name);
    120   }
    121   fprintf(out, "</name>\n<email>");
    122   if (commit->author_email) {
    123     print_xml_encoded(out, commit->author_email);
    124   }
    125   fprintf(out, "</email>\n</author>\n");
    126 
    127   fprintf(out, "<content>");
    128   fprintf(out, "commit %s\n", commit->oid);
    129   const char* parentoid = commit->parentoid;
    130   if (parentoid && parentoid[0] != '\0') {
    131     fprintf(out, "parent %s\n", parentoid);
    132   }
    133   fprintf(out, "Author: ");
    134   if (commit->author_name) {
    135     print_xml_encoded(out, commit->author_name);
    136   }
    137   fprintf(out, " &lt;");
    138   if (commit->author_email) {
    139     print_xml_encoded(out, commit->author_email);
    140   }
    141   fprintf(out, "&gt;\n");
    142   fprintf(out, "Date:   ");
    143   print_time(out, commit->author_time, commit->author_timezone_offset);
    144   fprintf(out, "\n");
    145   const char* message = commit->message;
    146   if (message) {
    147     fprintf(out, "\n");
    148     print_xml_encoded(out, message);
    149   }
    150   fprintf(out, "\n</content>\n</entry>\n");
    151 }
    152 
    153 void atom_end(Atom* atom) {
    154   assert(atom != NULL);
    155   fprintf(atom->out, "</feed>\n");
    156 }