gitout

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

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 }