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; + } +}