fileblob.c (2707B)
1 #include "writer/gopher/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/gopher/page.h" 14 15 struct GopherFileBlob { 16 const GitRepo* repo; 17 FILE* out; 18 GopherPage* page; 19 }; 20 21 GopherFileBlob* gopher_fileblob_create(const GitRepo* repo, const char* path) { 22 GopherFileBlob* blob = ecalloc(1, sizeof(GopherFileBlob)); 23 blob->repo = repo; 24 25 // Create directories. 26 char filename[PATH_MAX]; 27 if (snprintf(filename, sizeof(filename), "%s.gph", path) < 0) { 28 err(1, "snprintf"); 29 } 30 char out_path[PATH_MAX]; 31 path_concat(out_path, sizeof(out_path), "file", filename); 32 char dir[PATH_MAX]; 33 estrlcpy(dir, out_path, sizeof(dir)); 34 const char* d = dirname(dir); 35 if (!d) { 36 err(1, "dirname"); 37 } 38 mkdirp(d); 39 blob->out = efopen(out_path, "w"); 40 41 // Compute the relative path. 42 char relpath[PATH_MAX]; 43 estrlcpy(relpath, "../", sizeof(relpath)); 44 for (const char* p = d; *p != '\0'; p++) { 45 if (*p == '/') { 46 estrlcat(relpath, "../", sizeof(relpath)); 47 } 48 } 49 estrlcpy(filename, path, sizeof(filename)); 50 const char* title = basename(filename); 51 if (!title) { 52 err(1, "basename"); 53 } 54 blob->page = gopher_page_create(blob->out, repo, title, relpath); 55 return blob; 56 } 57 58 void gopher_fileblob_free(GopherFileBlob* blob) { 59 if (!blob) { 60 return; 61 } 62 fclose(blob->out); 63 blob->out = NULL; 64 gopher_page_free(blob->page); 65 blob->page = NULL; 66 free(blob); 67 } 68 69 void gopher_fileblob_begin(GopherFileBlob* blob) { 70 gopher_page_begin(blob->page); 71 } 72 73 void gopher_fileblob_add_file(GopherFileBlob* blob, const GitFile* file) { 74 FILE* out = blob->out; 75 76 char path[PATH_MAX]; 77 estrlcpy(path, gitfile_repo_path(file), sizeof(path)); 78 const char* filename = basename(path); 79 if (!filename) { 80 err(1, "basename"); 81 } 82 print_gopher_text(out, filename, false); 83 fprintf(out, " (%zdB)\n", gitfile_size_bytes(file)); 84 fprintf(out, "---\n"); 85 86 if (gitfile_size_lines(file) < 0) { 87 fprintf(out, "Binary file.\n"); 88 return; 89 } 90 91 size_t i = 0; 92 const char* content = gitfile_content(file); 93 const char* end = content + strlen(content); 94 const char* cur_line = content; 95 while (cur_line) { 96 const char* next_line = strchr(cur_line, '\n'); 97 if (next_line || cur_line < end) { 98 size_t len = (next_line ? next_line : end) - cur_line; 99 i++; 100 fprintf(out, "%6zu ", i); 101 print_gopher_text_len(out, cur_line, len, false); 102 fprintf(out, "\n"); 103 } 104 cur_line = next_line ? next_line + 1 : NULL; 105 } 106 } 107 108 void gopher_fileblob_end(GopherFileBlob* blob) { 109 gopher_page_end(blob->page); 110 }