Put VTV handling in separate file. - vtv-tools - virtual terminal video tools
(HTM) 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
(HTM) 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;
+ }
+}