gout

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

fileblob.c (3393B)


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