gout

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

refs.c (5250B)


      1 #include "writer/gopher/refs.h"
      2 
      3 #include <assert.h>
      4 #include <err.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 
      8 #include "format.h"
      9 #include "git/commit.h"
     10 #include "third_party/openbsd/reallocarray.h"
     11 #include "utils.h"
     12 #include "writer/gopher/page.h"
     13 
     14 typedef struct {
     15   char* title;
     16   char* id;
     17   FILE* out;
     18 } GopherRefsTable;
     19 
     20 typedef struct {
     21   char* shorthand;
     22   time_t author_time;
     23   char* author_name;
     24 } RefData;
     25 
     26 typedef struct {
     27   RefData* items;
     28   size_t count;
     29   size_t capacity;
     30 } RefList;
     31 
     32 struct GopherRefs {
     33   const GitRepo* repo;
     34   const FileSystem* fs;
     35   FILE* out;
     36   GopherPage* page;
     37   RefList branches;
     38   RefList tags;
     39 };
     40 
     41 static GopherRefsTable* gopher_refstable_create(const char* title,
     42                                                 const char* id,
     43                                                 FILE* out);
     44 static void gopher_refstable_free(GopherRefsTable* table);
     45 static void gopher_refstable_begin(GopherRefsTable* table);
     46 static void gopher_refstable_add_ref(GopherRefsTable* table,
     47                                      const RefData* ref);
     48 static void gopher_refstable_end(GopherRefsTable* table);
     49 
     50 static GopherRefsTable* gopher_refstable_create(const char* title,
     51                                                 const char* id,
     52                                                 FILE* out) {
     53   assert(title != NULL);
     54   assert(id != NULL);
     55   assert(out != NULL);
     56   GopherRefsTable* table = ecalloc(1, sizeof(GopherRefsTable));
     57   table->title = estrdup(title);
     58   table->id = estrdup(id);
     59   table->out = out;
     60   return table;
     61 }
     62 
     63 static void gopher_refstable_free(GopherRefsTable* table) {
     64   if (!table) {
     65     return;
     66   }
     67   free(table->title);
     68   free(table->id);
     69   free(table);
     70 }
     71 
     72 static void gopher_refstable_begin(GopherRefsTable* table) {
     73   assert(table != NULL);
     74   FILE* out = table->out;
     75   fprintf(out, "%s\n", table->title);
     76   fprintf(out, "  %-32.32s", "Name");
     77   fprintf(out, "  %-16.16s", "Last commit date");
     78   fprintf(out, "  %s\n", "Author");
     79 }
     80 
     81 static void gopher_refstable_add_ref(GopherRefsTable* table,
     82                                      const RefData* ref) {
     83   assert(table != NULL);
     84   assert(ref != NULL);
     85   FILE* out = table->out;
     86 
     87   fprintf(out, "  ");
     88   print_gopher_link_padded(out, ref->shorthand, 32, ' ');
     89   fprintf(out, "  ");
     90   print_time_short(out, ref->author_time);
     91   fprintf(out, "  ");
     92   print_gopher_link_padded(out, ref->author_name, 25, '\0');
     93   fprintf(out, "\n");
     94 }
     95 
     96 static void gopher_refstable_end(GopherRefsTable* table) {
     97   assert(table != NULL);
     98   FILE* out = table->out;
     99   fprintf(out, "\n");
    100 }
    101 
    102 static void reflist_add(RefList* list, const GitReference* ref) {
    103   if (list->count >= list->capacity) {
    104     list->capacity = list->capacity == 0 ? 16 : list->capacity * 2;
    105     list->items = reallocarray(list->items, list->capacity, sizeof(RefData));
    106     if (!list->items) {
    107       err(1, "reallocarray");
    108     }
    109   }
    110   RefData* item = &list->items[list->count++];
    111   item->shorthand = estrdup(ref->shorthand);
    112   if (ref->commit) {
    113     item->author_time = ref->commit->author_time;
    114     item->author_name = estrdup(ref->commit->author_name);
    115   } else {
    116     item->author_time = 0;
    117     item->author_name = estrdup("");
    118   }
    119 }
    120 
    121 static void reflist_clear(RefList* list) {
    122   for (size_t i = 0; i < list->count; i++) {
    123     free(list->items[i].shorthand);
    124     free(list->items[i].author_name);
    125   }
    126   free(list->items);
    127   list->items = NULL;
    128   list->count = 0;
    129   list->capacity = 0;
    130 }
    131 
    132 GopherRefs* gopher_refs_create(const GitRepo* repo, const FileSystem* fs) {
    133   assert(repo != NULL);
    134   assert(fs != NULL);
    135   GopherRefs* refs = ecalloc(1, sizeof(GopherRefs));
    136   refs->repo = repo;
    137   refs->fs = fs;
    138   refs->out = fs->fopen("refs.gph", "w");
    139   if (!refs->out) {
    140     err(1, "fopen: refs.gph");
    141   }
    142   refs->page = gopher_page_create(refs->out, repo, fs, "Refs", "");
    143   return refs;
    144 }
    145 
    146 void gopher_refs_free(GopherRefs* refs) {
    147   if (!refs) {
    148     return;
    149   }
    150   refs->fs->fclose(refs->out);
    151   gopher_page_free(refs->page);
    152   reflist_clear(&refs->branches);
    153   reflist_clear(&refs->tags);
    154   free(refs);
    155 }
    156 
    157 void gopher_refs_begin(GopherRefs* refs) {
    158   assert(refs != NULL);
    159   gopher_page_begin(refs->page);
    160 }
    161 
    162 void gopher_refs_add_ref(GopherRefs* refs, const GitReference* ref) {
    163   assert(refs != NULL);
    164   assert(ref != NULL);
    165   switch (ref->type) {
    166     case kReftypeBranch:
    167       reflist_add(&refs->branches, ref);
    168       break;
    169     case kReftypeTag:
    170       reflist_add(&refs->tags, ref);
    171       break;
    172   }
    173 }
    174 
    175 void gopher_refs_end(GopherRefs* refs) {
    176   assert(refs != NULL);
    177   if (refs->branches.count > 0) {
    178     GopherRefsTable* table =
    179         gopher_refstable_create("Branches", "branches", refs->out);
    180     gopher_refstable_begin(table);
    181     for (size_t i = 0; i < refs->branches.count; i++) {
    182       gopher_refstable_add_ref(table, &refs->branches.items[i]);
    183     }
    184     gopher_refstable_end(table);
    185     gopher_refstable_free(table);
    186   }
    187   if (refs->tags.count > 0) {
    188     GopherRefsTable* table = gopher_refstable_create("Tags", "tags", refs->out);
    189     gopher_refstable_begin(table);
    190     for (size_t i = 0; i < refs->tags.count; i++) {
    191       gopher_refstable_add_ref(table, &refs->tags.items[i]);
    192     }
    193     gopher_refstable_end(table);
    194     gopher_refstable_free(table);
    195   }
    196   gopher_page_end(refs->page);
    197 }