refs.c (5220B)
1 #include "writer/html/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/html/page.h" 13 14 typedef struct { 15 char* title; 16 char* id; 17 FILE* out; 18 } HtmlRefsTable; 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 HtmlRefs { 33 const GitRepo* repo; 34 const FileSystem* fs; 35 FILE* out; 36 HtmlPage* page; 37 RefList branches; 38 RefList tags; 39 }; 40 41 static HtmlRefsTable* html_refstable_create(const char* title, 42 const char* id, 43 FILE* out); 44 static void html_refstable_free(HtmlRefsTable* table); 45 static void html_refstable_begin(HtmlRefsTable* table); 46 static void html_refstable_add_ref(HtmlRefsTable* table, const RefData* ref); 47 static void html_refstable_end(HtmlRefsTable* table); 48 49 static HtmlRefsTable* html_refstable_create(const char* title, 50 const char* id, 51 FILE* out) { 52 assert(title != NULL); 53 assert(id != NULL); 54 assert(out != NULL); 55 HtmlRefsTable* table = ecalloc(1, sizeof(HtmlRefsTable)); 56 table->title = estrdup(title); 57 table->id = estrdup(id); 58 table->out = out; 59 return table; 60 } 61 62 static void html_refstable_free(HtmlRefsTable* table) { 63 if (!table) { 64 return; 65 } 66 free(table->title); 67 free(table->id); 68 free(table); 69 } 70 71 static void html_refstable_begin(HtmlRefsTable* table) { 72 assert(table != NULL); 73 fprintf(table->out, "<h2>%s</h2>", table->title); 74 fprintf(table->out, "<table id=\"%s\">", table->id); 75 fprintf(table->out, 76 "<thead>\n" 77 "<tr>" 78 "<td><b>Name</b></td>" 79 "<td><b>Last commit date</b></td>" 80 "<td><b>Author</b></td>\n" 81 "</tr>\n" 82 "</thead><tbody>\n"); 83 } 84 85 static void html_refstable_add_ref(HtmlRefsTable* table, const RefData* ref) { 86 assert(table != NULL); 87 assert(ref != NULL); 88 fprintf(table->out, "<tr><td>"); 89 print_xml_encoded(table->out, ref->shorthand); 90 fprintf(table->out, "</td><td>"); 91 print_time_short(table->out, ref->author_time); 92 fprintf(table->out, "</td><td>"); 93 print_xml_encoded(table->out, ref->author_name); 94 fprintf(table->out, "</td></tr>\n"); 95 } 96 97 static void html_refstable_end(HtmlRefsTable* table) { 98 assert(table != NULL); 99 fprintf(table->out, "</tbody></table><br/>\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 HtmlRefs* html_refs_create(const GitRepo* repo, const FileSystem* fs) { 133 assert(repo != NULL); 134 assert(fs != NULL); 135 HtmlRefs* refs = ecalloc(1, sizeof(HtmlRefs)); 136 refs->repo = repo; 137 refs->fs = fs; 138 refs->out = fs->fopen("refs.html", "w"); 139 if (!refs->out) { 140 err(1, "fopen: refs.html"); 141 } 142 refs->page = html_page_create(refs->out, repo, fs, "Refs", ""); 143 return refs; 144 } 145 146 void html_refs_free(HtmlRefs* refs) { 147 if (!refs) { 148 return; 149 } 150 refs->fs->fclose(refs->out); 151 html_page_free(refs->page); 152 reflist_clear(&refs->branches); 153 reflist_clear(&refs->tags); 154 free(refs); 155 } 156 157 void html_refs_begin(HtmlRefs* refs) { 158 assert(refs != NULL); 159 html_page_begin(refs->page); 160 } 161 162 void html_refs_add_ref(HtmlRefs* 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 html_refs_end(HtmlRefs* refs) { 176 assert(refs != NULL); 177 if (refs->branches.count > 0) { 178 HtmlRefsTable* table = 179 html_refstable_create("Branches", "branches", refs->out); 180 html_refstable_begin(table); 181 for (size_t i = 0; i < refs->branches.count; i++) { 182 html_refstable_add_ref(table, &refs->branches.items[i]); 183 } 184 html_refstable_end(table); 185 html_refstable_free(table); 186 } 187 if (refs->tags.count > 0) { 188 HtmlRefsTable* table = html_refstable_create("Tags", "tags", refs->out); 189 html_refstable_begin(table); 190 for (size_t i = 0; i < refs->tags.count; i++) { 191 html_refstable_add_ref(table, &refs->tags.items[i]); 192 } 193 html_refstable_end(table); 194 html_refstable_free(table); 195 } 196 html_page_end(refs->page); 197 }