URI: 
       Put VTV handling in separate file. - vtv-tools - virtual terminal video tools
  HTML git clone git://bitreich.org/vtv-tools  git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/vtv-tools
   DIR Log
   DIR Files
   DIR Refs
   DIR Tags
   DIR README
   DIR LICENSE
       ---
   DIR commit 97eae58b832d521bc35a23b2bec42e8ac957b233
   DIR parent ac749bd30b1f473993b382e75d02f67cf028e501
  HTML Author: Troels Henriksen <athas@sigkill.dk>
       Date:   Sun, 17 Sep 2023 14:29:49 +0200
       
       Put VTV handling in separate file.
       
       Diffstat:
         M Makefile                            |       4 +++-
         M src/vtv-viewer.c                    |      53 ++++++++-----------------------
         A src/vtv.h                           |      76 +++++++++++++++++++++++++++++++
       
       3 files changed, 93 insertions(+), 40 deletions(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       @@ -6,7 +6,7 @@ CC?=cc
        
        all: bin/vtv-from-ff bin/vtv-viewer
        
       -bin/%: src/%.c
       +bin/%: src/%.c src/vtv.h
                $(CC) -o $@ $< $(CFLAGS)
        
        install: all
       @@ -19,3 +19,5 @@ install: all
                install -D -m 644 man/* ${MANPREFIX}/man1/
        
        .PHONY: all install
       +
       +clean: rm bin/vtv-from-ff bin/vtv-viewer
   DIR diff --git a/src/vtv-viewer.c b/src/vtv-viewer.c
       @@ -12,6 +12,8 @@
        #include <unistd.h>
        #include <errno.h>
        
       +#include "vtv.h"
       +
        struct termios orig_termios;
        
        void cooked_mode() {
       @@ -47,32 +49,10 @@ void bg_rgb(uint8_t r, uint8_t g, uint8_t b) {
          printf("\033[48;2;%d;%d;%dm", r, g, b);
        }
        
       -int read_lines(FILE* f, char*** lines_out, size_t *num_lines_out) {
       -  size_t n, num_lines = 0, capacity = 10;
       -  char** lines = calloc(capacity, sizeof(char*));
       -  ssize_t len;
       -
       -  while ((len = getline(&lines[num_lines], &n, f)) > 0) {
       -    lines[num_lines][len-1] = 0; // Strip newline.
       -    if (++num_lines == capacity) {
       -      capacity *= 2;
       -      lines = reallocarray(lines, capacity, sizeof(char*));
       -      for (unsigned int i = num_lines; i < capacity; i++) {
       -        lines[i] = NULL;
       -      }
       -    }
       -  }
       -
       -  *lines_out = lines;
       -  *num_lines_out = num_lines;
       -  return 0;
       -}
       -
        struct {
          int frame;
          int lines_per_frame;
       -  char** lines;
       -  int num_lines;
       +  struct vtv* vtv;
        } state;
        
        void show_status() {
       @@ -81,23 +61,16 @@ void show_status() {
        }
        
        void show_frame() {
       -  for (int i = 0; i < state.lines_per_frame; i++) {
       -    int j = state.frame*state.lines_per_frame + i;
       -    if (j < state.num_lines) {
       -      puts(state.lines[j]);
       -    } else {
       -      puts("   MISSING LINE");
       -    }
       -  }
       +  vtv_show_frame(state.vtv, stdout, state.frame, state.lines_per_frame,
       +                 "\033[0m   MISSING LINE");
        }
        
       -int view(char** lines, size_t num_lines) {
       +int view(struct vtv* vtv) {
          raw_mode();
        
          state.frame = 0;
          state.lines_per_frame = 25;
       -  state.lines = lines;
       -  state.num_lines = num_lines;
       +  state.vtv = vtv;
        
          while (1) {
            home();
       @@ -140,12 +113,14 @@ int main(int argc, char** argv) {
                    argv[0], argv[1], strerror(errno));
          }
        
       -  char** lines;
       -  size_t num_lines;
       -  if (read_lines(f, &lines, &num_lines) != 0) {
       +  struct vtv *vtv = vtv_read(f);
       +
       +  if (vtv == NULL) {
            fprintf(stderr, "%s: failed to read from %s: %s\n",
                    argv[0], argv[1], strerror(errno));
       -    exit(1);
          }
       -  return view(lines, num_lines);
       +
       +  int ret = view(vtv);
       +  vtv_free(vtv);
       +  return ret;
        }
   DIR diff --git a/src/vtv.h b/src/vtv.h
       @@ -0,0 +1,76 @@
       +// Single-header library for reading VTV files.
       +//
       +// VTV is an almost trivial format, but there are still a few things
       +// that are convenient to write once and for all (e.g. error
       +// handling).
       +//
       +// Copyright 2023 Troels Henriksen <athas@sigkill.dk>
       +//
       +// See LICENSE file for licensing information.
       +
       +#pragma once
       +
       +struct vtv {
       +  int num_lines;
       +  char** lines;
       +};
       +
       +static void vtv_free(struct vtv* vtv) {
       +  for (int i = 0; i < vtv->num_lines; i++) {
       +    free(vtv->lines[i]);
       +  }
       +  free(vtv->lines);
       +  free(vtv);
       +}
       +
       +// Returns nonzero on error.
       +static int vtv_read_lines(FILE* f, char*** lines_out, int *num_lines_out) {
       +  size_t n, num_lines = 0, capacity = 10;
       +  char** lines = calloc(capacity, sizeof(char*));
       +  ssize_t len;
       +
       +  while ((len = getline(&lines[num_lines], &n, f)) > 0) {
       +    lines[num_lines][len-1] = 0; // Strip newline.
       +    if (++num_lines == capacity) {
       +      capacity *= 2;
       +      lines = reallocarray(lines, capacity, sizeof(char*));
       +      for (unsigned int i = num_lines; i < capacity; i++) {
       +        lines[i] = NULL;
       +      }
       +    }
       +  }
       +
       +  *lines_out = lines;
       +  *num_lines_out = num_lines;
       +  return 0;
       +}
       +
       +// Show the given frame on the provided file.  If there are not enough
       +// lines, show the provided line instead of the missing ones.
       +static void vtv_show_frame(struct vtv* vtv,
       +                           FILE* f,
       +                           int frame,
       +                           int lines_per_frame,
       +                           const char *missing_line) {
       +  for (int i = 0; i < lines_per_frame; i++) {
       +    int j = frame*lines_per_frame + i;
       +    if (j < vtv->num_lines) {
       +      fputs(vtv->lines[j], f);
       +      fputc('\n', f);
       +    } else {
       +      fputs(missing_line, f);
       +      fputc('\n', f);
       +    }
       +  }
       +}
       +
       +// Returns NULL on error.
       +static struct vtv* vtv_read(FILE *f) {
       +  struct vtv* vtv = malloc(sizeof(struct vtv));
       +  if (vtv_read_lines(f, &vtv->lines, &vtv->num_lines) == 0) {
       +    return vtv;
       +  } else {
       +    free(vtv);
       +    return NULL;
       +  }
       +}