summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwrmr2025-10-08 16:01:17 -0400
committerwrmr2025-10-08 16:01:17 -0400
commit8402bc583c0d3a9ff42c0a9883c6350c42ccfc18 (patch)
tree70f85e47edc44517a6a793a3b0858884d1e8d2bf
parent39aa3cfe0e44bcd91eb0dfa6899c15f248b724f0 (diff)
various preparations for adding .cbinkrc
-rw-r--r--main.c101
-rw-r--r--opt.h86
2 files changed, 148 insertions, 39 deletions
diff --git a/main.c b/main.c
index 4272144..911fc73 100644
--- a/main.c
+++ b/main.c
@@ -33,10 +33,12 @@
#define STR_IMPL
#define STRIO_IMPL
#define ARENA_IMPL
+#define OPT_IMPL
#include "str.h"
#include "strio.h"
#include "arena.h"
+#include "opt.h"
#define POST_LIMIT 200 /* see bink.py */
#define PAGE_LEN getmaxy(stdscr)
@@ -60,24 +62,31 @@
/* colors */
-#define CPAIR_INIT_X(cp, fg, bg) init_pair(cp, fg, bg);
-#define CPAIR_ENUM_X(cp, fg, bg) cp,
+#define CPAIR_ENUM_X(cp, fg, bg, name) cp,
+#define CPAIR_OPT_X(cp, fg_, bg_, name) opt.color[cp] = (ColorOpt) { .fg = fg_, .bg = bg_ };
+#define CPAIR_INIT_X(cp, fg_, bg_, name) init_pair(cp, opt.color[cp].fg, opt.color[cp].bg);
+#define COLOR_NORM -1
+#define COLOR_FG COLOR_NORM
+#define COLOR_BG COLOR_NORM
#define CPAIR_LIST(X)\
- X(CPAIR_TEXT , COLOR_WHITE , COLOR_BLACK)\
- X(CPAIR_MENTION , COLOR_BLACK , COLOR_WHITE)\
- X(CPAIR_USER , COLOR_YELLOW , COLOR_BLACK)\
- X(CPAIR_PRONOUNS , COLOR_CYAN , COLOR_BLACK)\
- X(CPAIR_TIME , COLOR_BLUE , COLOR_BLACK)\
- X(CPAIR_PFP , COLOR_BLUE , COLOR_BLACK)\
- X(CPAIR_PFP_SELF , COLOR_YELLOW , COLOR_BLACK)\
- X(CPAIR_BANNER , COLOR_WHITE , COLOR_BLACK)\
- X(CPAIR_BORDER , COLOR_BLUE , COLOR_BLACK)\
- X(CPAIR_TAGLINE_OK , COLOR_GREEN , COLOR_BLACK)\
- X(CPAIR_TAGLINE_WARN , COLOR_YELLOW , COLOR_BLACK)\
- X(CPAIR_TAGLINE_ERR , COLOR_RED , COLOR_BLACK)
+ X(CPAIR_TEXT , COLOR_FG , COLOR_BG, "text")\
+ X(CPAIR_MENTION , COLOR_BG , COLOR_FG, "mention")\
+ X(CPAIR_USER , COLOR_YELLOW , COLOR_BG, "user")\
+ X(CPAIR_PRONOUNS , COLOR_CYAN , COLOR_BG, "pronouns")\
+ X(CPAIR_TIME , COLOR_BLUE , COLOR_BG, "time")\
+ X(CPAIR_PFP , COLOR_BLUE , COLOR_BG, "pfp")\
+ X(CPAIR_PFP_SELF , COLOR_YELLOW , COLOR_BG, "pfp.self")\
+ X(CPAIR_BANNER , COLOR_FG , COLOR_BG, "banner")\
+ X(CPAIR_BORDER , COLOR_BLUE , COLOR_BG, "border")\
+ X(CPAIR_MSG_OK , COLOR_GREEN , COLOR_BG, "msg.ok")\
+ X(CPAIR_MSG_WARN , COLOR_YELLOW , COLOR_BG, "msg.warn")\
+ X(CPAIR_MSG_ERR , COLOR_RED , COLOR_BG, "msg.err")
typedef enum {
+ /* not all curses implementation allow modifying cpair 0 */
+ CPAIR_UNUSED,
CPAIR_LIST(CPAIR_ENUM_X)
+ CPAIR_MAX
} ColorPair;
/* dynamic arrays */
@@ -132,12 +141,18 @@ int utf8_cp_to_byte(Str s, int dest) {
/* options */
typedef struct {
+ int fg, bg;
+} ColorOpt;
+
+typedef struct {
struct {
int pfp, pronouns;
} see;
struct {
int left, right, top, bottom;
} margin;
+ int default_colors;
+ ColorOpt color[CPAIR_MAX];
} Options;
/* globals */
@@ -151,27 +166,28 @@ Options opt = {
.margin = {
.left = 0,
.right = 0
- }
+ },
+ .default_colors = 1
};
-/* tagline & logging */
+/* msg & logging */
-#define TAGLINE_MAX 1024
-char tagline[TAGLINE_MAX] = { 0 };
+#define MSG_MAX 1024
+char msg[MSG_MAX] = { 0 };
typedef enum {
- TAGLINE_OK,
- TAGLINE_WARN,
- TAGLINE_ERR
+ MSG_OK,
+ MSG_WARN,
+ MSG_ERR
} TaglineStatus;
-TaglineStatus tagline_status = TAGLINE_OK;
+TaglineStatus msg_status = MSG_OK;
-void tagline_set(const char *fmt, ...) {
+void msg_set(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
- vsnprintf(tagline, TAGLINE_MAX - 1, fmt, ap);
+ vsnprintf(msg, MSG_MAX - 1, fmt, ap);
va_end(ap);
- tagline_status = TAGLINE_OK;
+ msg_status = MSG_OK;
}
void log_warn(const char *fmt, ...) {
@@ -179,9 +195,9 @@ void log_warn(const char *fmt, ...) {
va_start(ap, fmt);
beep();
flash();
- vsnprintf(tagline, TAGLINE_MAX - 1, fmt, ap);
+ vsnprintf(msg, MSG_MAX - 1, fmt, ap);
va_end(ap);
- tagline_status = TAGLINE_WARN;
+ msg_status = MSG_WARN;
}
void log_err(const char *fmt, ...) {
@@ -189,11 +205,11 @@ void log_err(const char *fmt, ...) {
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));
+ vsnprintf(msg, MSG_MAX - 1, fmt, ap);
+ size_t n = strlen(msg);
+ snprintf(msg + n, MSG_MAX - n - 1, ": %s", strerror(errno));
va_end(ap);
- tagline_status = TAGLINE_ERR;
+ msg_status = MSG_ERR;
}
/* string conversion */
@@ -820,13 +836,14 @@ void init_curses(void) {
setlocale(LC_ALL, "");
initscr();
start_color();
- init_color(COLOR_BLACK, 0, 0, 0);
+ init_color(COLOR_BG, 0, 0, 0);
cbreak();
noecho();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
curs_set(0);
+ if (opt.default_colors) use_default_colors();
CPAIR_LIST(CPAIR_INIT_X)
}
@@ -835,6 +852,11 @@ void fini_curses(void) {
endwin();
}
+void load_config(void) {
+ CPAIR_LIST(CPAIR_OPT_X)
+ /* TODO: load cbinkrc */
+}
+
/* main */
int main(void) {
@@ -856,6 +878,7 @@ int main(void) {
"([ \t\n]+|^)[@~]?%s([:;,.!? \t\n]|$)", getlogin()),
REG_EXTENDED | REG_ICASE | REG_NOSUB);
+ load_config();
init_curses();
posts_refresh(&posts, &post_arena);
@@ -868,13 +891,13 @@ int main(void) {
arena_reset(&temp_arena);
gfx_draw(&gfx, cur, &temp_arena);
- 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;
+ switch (msg_status) {
+ case MSG_OK: color_set(CPAIR_MSG_OK, 0); break;
+ case MSG_WARN: color_set(CPAIR_MSG_WARN, 0); break;
+ case MSG_ERR: color_set(CPAIR_MSG_ERR, 0); break;
}
- mvaddstr(getmaxy(stdscr) - 1, getmaxx(stdscr) - strlen(tagline), tagline);
- tagline[0] = '\0';
+ mvaddstr(getmaxy(stdscr) - 1, getmaxx(stdscr) - strlen(msg), msg);
+ msg[0] = '\0';
int ch = getch();
if (ch == 'q') break;
@@ -932,7 +955,7 @@ int main(void) {
refresh:
arena_reset(&post_arena);
posts_refresh(&posts, &post_arena);
- tagline_set("%zu users, %zu posts, %zums", post_stats.user_count, post_stats.post_count,
+ msg_set("%zu users, %zu posts, %zums", post_stats.user_count, post_stats.post_count,
post_stats.gather_ns / 1000000);
goto resize;
case '\t':
diff --git a/opt.h b/opt.h
new file mode 100644
index 0000000..0971112
--- /dev/null
+++ b/opt.h
@@ -0,0 +1,86 @@
+#ifndef OPT_H
+#define OPT_H
+
+#define OPT_ARG 1
+#define OPT_AT_END 0
+#define OPT_ERR_NO_PARAM -1
+#define OPT_ERR_BAD_OPT -2
+
+#define OPTF_MID_SHORT 1
+#define OPTF_IGNORE 2
+#define OPTF_NO_PRINT_ERR 4
+
+/* fmt is a set of short option chars, preceded by : if they accept an
+ * argument, followed by [foo] for a corresponding long option name. */
+
+int opt_next(int *optf, int *argc, const char ***argv, const char *fmt);
+
+#ifdef OPT_IMPL
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+int opt_next(int *optf, int *argc, const char ***argv, const char *fmt) {
+ if (~*optf & OPTF_MID_SHORT) {
+ *argv += 1, *argc -= 1;
+ if (*argc < 1) return OPT_AT_END;
+ }
+ if (*optf & OPTF_IGNORE) return OPT_ARG;
+
+ int is_long = 0;
+ if (~*optf & OPTF_MID_SHORT) {
+ if ((**argv)[0] != '-') return OPT_ARG;
+ is_long = (**argv)[1] == '-';
+ if (is_long && !(**argv)[2]) {
+ *optf |= OPTF_IGNORE;
+ return opt_next(optf, argc, argv, fmt);
+ }
+ }
+
+ const char *opt = **argv + is_long + !(*optf & OPTF_MID_SHORT);
+ const char *opt_end = is_long ? strchr(opt, '=') : opt + 1;
+ if (!opt_end) opt_end = opt + strlen(opt);
+ unsigned opt_len = opt_end - opt;
+
+ int opt_arg = 0, match = 0;
+ char opt_char = '\0';
+ while (*fmt && !match) {
+ opt_arg = (*fmt == ':');
+ if (opt_arg) fmt++;
+ opt_char = *fmt++;
+ assert(opt_char);
+ match = !is_long && *opt == opt_char;
+ if (*fmt == '[') {
+ const char *rt = strchr(++fmt, ']');
+ assert(rt);
+ match |= is_long && rt-fmt == opt_len && !memcmp(opt, fmt, opt_len);
+ fmt = rt + 1;
+ }
+ }
+
+ *optf &= ~OPTF_MID_SHORT;
+ if (match && opt_arg) {
+ if (*opt_end) {
+ **argv = opt_end + is_long;
+ } else {
+ *argv += 1, *argc -= 1;
+ if (*argc > 0) return opt_char;
+ if (~*optf & OPTF_NO_PRINT_ERR) {
+ fprintf(stderr, "option '%.*s' expected parameter, but none given\n", opt_len, opt);
+ }
+ return OPT_ERR_NO_PARAM;
+ }
+ } else if (!is_long && *opt_end) {
+ *optf |= OPTF_MID_SHORT;
+ **argv = opt_end;
+ }
+
+ if (!match && ~*optf & OPTF_NO_PRINT_ERR) {
+ fprintf(stderr, "unrecognized option '%.*s'\n", opt_len, opt);
+ }
+ return match ? opt_char : OPT_ERR_BAD_OPT;
+}
+
+#endif
+#endif