gout

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

atom.c (4161B)


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