summary refs log tree commit diff
diff options
context:
space:
mode:
authorwrmr2025-06-24 21:52:55 -0400
committerwrmr2025-06-24 21:52:55 -0400
commitb0b005472fa0ec0d22fc2ed06cd7378a6ef68e9b (patch)
tree062e26aee30906b6da2838eb884def4259c79743
parentaaa94bac44546589e422748477edb8446efe41e2 (diff)
tagline with three levels (ok, warn, err), post index profiling
-rw-r--r--main.c112
1 files changed, 98 insertions, 14 deletions
diff --git a/main.c b/main.c
index 7d0ab9b..84c9e98 100644
--- a/main.c
+++ b/main.c
@@ -14,6 +14,8 @@
 
 #define _POSIX_C_SOURCE 202506L
 
+/* includes */
+
 #include <stdio.h>
 #include <locale.h>
 #include <stdlib.h>
@@ -50,6 +52,9 @@
 #define CPAIR_TIME 2
 #define CPAIR_MENTION 3
 #define CPAIR_BORDER 4
+#define CPAIR_TAGLINE_OK 5
+#define CPAIR_TAGLINE_WARN 6
+#define CPAIR_TAGLINE_ERR 7
 
 /* dynamic arrays */
 
@@ -80,15 +85,45 @@
 
 regex_t re_mention;
 
+#define TAGLINE_MAX 1024
+char tagline[TAGLINE_MAX] = { 0 };
+enum {
+	TAGLINE_OK,
+	TAGLINE_WARN,
+	TAGLINE_ERR
+} tagline_status = TAGLINE_OK;
+
 /* logging */
 /* TODO: change to put in a proper log file or something */
 
+void tagline_set(const char *fmt, ...) {
+	va_list ap;
+	va_start(ap, fmt);
+	vsnprintf(tagline, TAGLINE_MAX - 1, fmt, ap);
+	va_end(ap);
+	tagline_status = TAGLINE_OK;
+}
+
 void log_warn(const char *fmt, ...) {
 	va_list ap;
 	va_start(ap, fmt);
-	vfprintf(stderr, fmt, ap);
-	fprintf(stderr, "\n");
+	beep();
+	flash();
+	vsnprintf(tagline, TAGLINE_MAX - 1, fmt, ap);
 	va_end(ap);
+	tagline_status = TAGLINE_WARN;
+}
+
+void log_err(const char *fmt, ...) {
+	beep();
+	flash();
+	va_list ap;
+	va_start(ap, fmt);
+	vsnprintf(tagline, TAGLINE_MAX - 1, fmt, ap);
+	size_t n = strlen(tagline);
+	snprintf(tagline + n, TAGLINE_MAX - n - 1, ": %s", strerror(errno));
+	va_end(ap);
+	tagline_status = TAGLINE_ERR;
 }
 
 /* string conversion */
@@ -128,6 +163,12 @@ typedef struct {
 	ptrdiff_t len, cap;
 } PostList;
 
+typedef struct {
+	size_t user_count, post_count, gather_ns;
+	struct timespec time_start, time_end;
+	int err;
+} PostStats;
+
 /* sorting */
 
 int ts_cmp(const struct timespec *a, const struct timespec *b) {
@@ -144,6 +185,26 @@ int post_cmp(const void *a, const void *b) {
 
 /* post indexing */
 
+PostStats post_stats = { 0 };
+
+void post_stats_init(PostStats *ps) {
+	memset(ps, 0, sizeof(PostStats));
+	if (clock_gettime(CLOCK_REALTIME, &ps->time_start)) {
+		log_warn("clock error!");
+		ps->err = 1;
+	}
+}
+
+void post_stats_fini(PostStats *ps) {
+	if (clock_gettime(CLOCK_REALTIME, &ps->time_end)) {
+		log_warn("clock error!");
+		ps->err = 1;
+	}
+	int64_t diff_sec = ps->time_end.tv_sec - ps->time_start.tv_sec;
+	int64_t diff_nsec = ps->time_end.tv_nsec - ps->time_start.tv_nsec;
+	ps->gather_ns = (diff_sec * 1000000000) + diff_nsec;
+}
+
 /* @path must be both
  * (a) absolute; and
  * (b) allocated either statically or within arena @a
@@ -151,6 +212,7 @@ int post_cmp(const void *a, const void *b) {
 void posts_gather_from(PostList *posts, Str username, const char *path, Arena *a) {
 	DIR *d = opendir(path);
 	if (!d) return;
+	post_stats.user_count++;
 	for (struct dirent *de; (de = readdir(d)); ) {
 		if (*de->d_name == '.') continue;
 		Post p = { 0 };
@@ -176,17 +238,18 @@ void posts_gather(PostList *posts, Arena *a) {
 }
 
 void posts_load(PostList *posts, Arena *a) {
+	post_stats.post_count = posts->len;
 	qsort(posts->data, posts->len, sizeof(Post), post_cmp);
 	if (posts->len > POST_LIMIT) posts->len = POST_LIMIT;
 	for (int i = 0; i < posts->len; i++) {
 		Post *p = &posts->data[i];
 		FILE *f = fopen(p->path, "r/o");
 		if (!f) {
-			log_warn("couldn't open %s", p->path);
+			log_err("couldn't open %s", p->path);
 			continue;
 		}
 		if (read_all(f, &p->text, a)) {
-			log_warn("couldn't read %s", p->path);
+			log_err("couldn't read %s", p->path);
 			fclose(f);
 			continue;
 		}
@@ -196,8 +259,10 @@ void posts_load(PostList *posts, Arena *a) {
 
 void posts_refresh(PostList *posts, Arena *a) {
 	posts->len = 0;
+	post_stats_init(&post_stats);
 	posts_gather(posts, a);
 	posts_load(posts, a);
+	post_stats_fini(&post_stats);
 }
 
 /* word wrapping */
@@ -379,7 +444,10 @@ void new_post(Arena *temp) {
 
 	/* create and edit post in a temp file */
 
-	if (clock_gettime(CLOCK_REALTIME, &ts)) err(1, "clock_gettime failure");
+	if (clock_gettime(CLOCK_REALTIME, &ts)) {
+		log_err("clock failure");
+		return;
+	}
 
 	const char *tmpf = cstr_fmt(temp, "/tmp/cbink_%s_%U%09u.txt", getlogin(),
 			(uint64_t)ts.tv_sec, (uint32_t)ts.tv_nsec);
@@ -390,27 +458,30 @@ void new_post(Arena *temp) {
 	if (!f) return;
 	if (read_all(f, &body, temp)) {
 		fclose(f);
-		log_warn("couldn't read %s", tmpf);
+		log_err("couldn't read %s", tmpf);
 		return;
 	}
 	fclose(f);
-	if (remove(tmpf)) log_warn("failed to remove %s", tmpf);
+	if (remove(tmpf)) log_err("failed to remove %s", tmpf);
 	body = str_trim(body);
 	if (body.n < 1) return;
 
 	/* write it to .bink (with updated timestamp) */
 
-	if (clock_gettime(CLOCK_REALTIME, &ts)) err(1, "clock_gettime failure");
+	if (clock_gettime(CLOCK_REALTIME, &ts)) {
+		log_err("clock failure");
+		return;
+	}
 
 	const char *outf = cstr_fmt(temp, "/home/%s/.bink/%U%09u", getlogin(),
 			(uint64_t)ts.tv_sec, (uint32_t)ts.tv_nsec);
 	f = fopen(outf, "w/o");
 	if (!f) {
-		log_warn("failed to open %s", outf);
+		log_err("failed to open %s", outf);
 		return;
 	}
 	if (fwrite(body.s, 1, body.n, f) != (size_t)body.n) {
-		err(1, "write error in %s", outf);
+		log_err("write error in %s", outf);
 		fclose(f);
 		return;
 	}
@@ -430,6 +501,9 @@ void init_curses(void) {
 	keypad(stdscr, TRUE);
 	curs_set(0);
 
+	init_pair(CPAIR_TAGLINE_OK, COLOR_GREEN, COLOR_BLACK);
+	init_pair(CPAIR_TAGLINE_WARN, COLOR_YELLOW, COLOR_BLACK);
+	init_pair(CPAIR_TAGLINE_ERR, COLOR_RED, COLOR_BLACK);
 	init_pair(CPAIR_BORDER, COLOR_BLUE, COLOR_BLACK);
 	init_pair(CPAIR_USER, COLOR_YELLOW, COLOR_BLACK);
 	init_pair(CPAIR_TIME, COLOR_BLUE, COLOR_BLACK);
@@ -475,6 +549,13 @@ int main(void) {
 
 		arena_reset(&temp_arena);
 		gfx_draw(&gfx, cur);
+		switch (tagline_status) {
+		case TAGLINE_OK: color_set(CPAIR_TAGLINE_OK, 0); break;
+		case TAGLINE_WARN: color_set(CPAIR_TAGLINE_WARN, 0); break;
+		case TAGLINE_ERR: color_set(CPAIR_TAGLINE_ERR, 0); break;
+		}
+		mvaddstr(getmaxy(stdscr) - 1, getmaxx(stdscr) - strlen(tagline), tagline);
+		tagline[0] = '\0';
 
 		int ch = getch();
 		if (ch == 'q') break;
@@ -516,19 +597,22 @@ int main(void) {
 				fini_curses();
 				edit_post(&posts.data[cur], &temp_arena);
 				init_curses();
+				goto refresh;
 			} else {
-				beep();
-				flash();
+				log_warn("not your post to edit!");
+				break;
 			}
-			goto refresh;
 		case 'c':
 			fini_curses();
 			new_post(&temp_arena);
 			init_curses();
 			/* fallthrough */
 		case 'r':
-refresh:		arena_reset(&post_arena);
+refresh:
+			arena_reset(&post_arena);
 			posts_refresh(&posts, &post_arena);
+			tagline_set("%lu users, %lu posts, %lums", post_stats.user_count, post_stats.post_count,
+					post_stats.gather_ns / 1000000);
 			/* fallthrough */
 		case KEY_RESIZE:
 			arena_reset(&gfx_arena);