fileblob.c (3065B)
1 #include "writer/html/fileblob.h" 2 3 #include <err.h> 4 #include <libgen.h> 5 #include <limits.h> 6 #include <stdbool.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include "format.h" 12 #include "utils.h" 13 #include "writer/html/page.h" 14 15 struct HtmlFileBlob { 16 const GitRepo* repo; 17 FILE* out; 18 HtmlPage* page; 19 }; 20 21 HtmlFileBlob* html_fileblob_create(const GitRepo* repo, const char* path) { 22 if (!is_safe_repo_path(path)) { 23 errx(1, "unsafe path: %s", path); 24 } 25 HtmlFileBlob* blob = ecalloc(1, sizeof(HtmlFileBlob)); 26 blob->repo = repo; 27 28 // Create directories. 29 char filename[PATH_MAX]; 30 if (snprintf(filename, sizeof(filename), "%s.html", path) < 0) { 31 err(1, "snprintf"); 32 } 33 char out_path[PATH_MAX]; 34 path_concat(out_path, sizeof(out_path), "file", filename); 35 char dir[PATH_MAX]; 36 estrlcpy(dir, out_path, sizeof(dir)); 37 const char* d = dirname(dir); 38 if (!d) { 39 err(1, "dirname"); 40 } 41 mkdirp(d); 42 blob->out = efopen(out_path, "w"); 43 44 // Compute the relative path. 45 char relpath[PATH_MAX]; 46 estrlcpy(relpath, "../", sizeof(relpath)); 47 for (const char* p = d; *p != '\0'; p++) { 48 if (*p == '/') { 49 estrlcat(relpath, "../", sizeof(relpath)); 50 } 51 } 52 estrlcpy(filename, path, sizeof(filename)); 53 const char* title = basename(filename); 54 if (!title) { 55 err(1, "basename"); 56 } 57 blob->page = html_page_create(blob->out, repo, title, relpath); 58 return blob; 59 } 60 61 void html_fileblob_free(HtmlFileBlob* blob) { 62 if (!blob) { 63 return; 64 } 65 fclose(blob->out); 66 blob->out = NULL; 67 html_page_free(blob->page); 68 blob->page = NULL; 69 free(blob); 70 } 71 72 void html_fileblob_begin(HtmlFileBlob* blob) { 73 html_page_begin(blob->page); 74 } 75 76 void html_fileblob_add_file(HtmlFileBlob* blob, const GitFile* file) { 77 FILE* out = blob->out; 78 79 fprintf(out, "<p> "); 80 char path[PATH_MAX]; 81 estrlcpy(path, gitfile_repo_path(file), sizeof(path)); 82 const char* filename = basename(path); 83 if (!filename) { 84 err(1, "basename"); 85 } 86 print_xml_encoded(out, filename); 87 fprintf(out, " (%zdB)", gitfile_size_bytes(file)); 88 fprintf(out, "</p><hr/>"); 89 90 ssize_t size_lines = gitfile_size_lines(file); 91 if (size_lines == -1) { 92 fprintf(out, "<p>Binary file.</p>\n"); 93 return; 94 } 95 if (size_lines == -2) { 96 fprintf(out, "<p>File too large to display.</p>\n"); 97 return; 98 } 99 100 fprintf(out, "<pre id=\"blob\">\n"); 101 102 size_t i = 0; 103 const char* content = gitfile_content(file); 104 const char* end = content + gitfile_size_bytes(file); 105 const char* cur_line = content; 106 while (cur_line < end) { 107 const char* next_line = memchr(cur_line, '\n', end - cur_line); 108 size_t len = (next_line ? next_line : end) - cur_line; 109 110 i++; 111 fprintf(out, "<a href=\"#l%zu\" class=\"line\" id=\"l%zu\">", i, i); 112 fprintf(out, "%7zu</a> ", i); 113 print_xml_encoded_len(out, cur_line, len, false); 114 fprintf(out, "\n"); 115 116 if (next_line) { 117 cur_line = next_line + 1; 118 } else { 119 break; 120 } 121 } 122 fprintf(out, "</pre>\n"); 123 } 124 125 void html_fileblob_end(HtmlFileBlob* blob) { 126 html_page_end(blob->page); 127 }