summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);