From d9e6f8b3a37d5e698b9caed2f79914c5a2917822 Mon Sep 17 00:00:00 2001 From: anihilis Date: Sun, 15 Mar 2026 23:11:26 -0700 Subject: [PATCH] update --- cclock | Bin 26032 -> 26032 bytes cclock.bkp.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++ cclock.c | 6 +- toml-parse | Bin 0 -> 12632 bytes toml-parse.c | 26 +++++ 5 files changed, 348 insertions(+), 3 deletions(-) create mode 100644 cclock.bkp.c create mode 100755 toml-parse create mode 100644 toml-parse.c diff --git a/cclock b/cclock index 46470c7285a07a28a78b92a6d2bf636963a05532..1cf1aaa1681b0c674af09b3ce8d412ffc5d44127 100755 GIT binary patch delta 158 zcmdmRnh}IFm_?5MR+t{fGik{JNzlU9^1jdz`*b#^!@+;9^I^Y)(i~0Kmz+17!(*hI*-4Q`2bSC!Xx>H zM{nzdKmY%O1ed@4|KCINut(=DkIoAo7hiO`&hhA-3X<(Eoiq8NsPN=aF$+e<&3$4@ F{s3;`O!EK$ delta 152 zcmdmRnh}IFm_=$8+e&M{Oi+_pof2_wvkmiXA#;!3sT=2e~)g~LTd(wT_Ayd3=9ek9-YTu$WIm&6VYAu_Wyqm w&BGp@w>&y8cwBtZ={l#|bwO_hqet)52_QpV=fF)oHrZdyj*)3|pO}(A0A5^0;Q#;t diff --git a/cclock.bkp.c b/cclock.bkp.c new file mode 100644 index 0000000..192f620 --- /dev/null +++ b/cclock.bkp.c @@ -0,0 +1,319 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile sig_atomic_t running = 1; +static volatile sig_atomic_t resized = 0; + +static void handle_sigint(int sig) { (void)sig; running = 0; } +static void handle_winch(int sig) { (void)sig; resized = 1; } + +/* ---------------- Config ---------------- */ +typedef struct { + char api_key[128]; + char location[64]; + char units[16]; +} config_t; + +/* Simple TOML parser for [weather] section */ +static bool load_config_toml(config_t *cfg, const char *path) { + FILE *f = fopen(path, "r"); + if (!f) return false; + + bool in_weather_section = false; + while (!feof(f)) { + char line[256]; + if (!fgets(line, sizeof(line), f)) break; + + /* Remove comments */ + char *hash = strchr(line, '#'); + if (hash) *hash = '\0'; + + /* Strip leading/trailing whitespace */ + char *start = line; + while (*start && (*start == ' ' || *start == '\t')) start++; + char *end = start + strlen(start) - 1; + while (end > start && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) *end-- = '\0'; + + if (strlen(start) == 0) continue; + + if (start[0] == '[' && start[strlen(start)-1] == ']') { + if (strncmp(start+1, "weather", 7) == 0) in_weather_section = true; + else in_weather_section = false; + continue; + } + + if (!in_weather_section) continue; + + char key[32], val[128]; + if (sscanf(start, "%31[^=]= \"%127[^\"]\"", key, val) == 2) { + char *k_end = key + strlen(key) - 1; + while (k_end > key && (*k_end == ' ' || *k_end == '\t')) *k_end-- = '\0'; + + if (strcmp(key, "api_key") == 0) strncpy(cfg->api_key, val, sizeof(cfg->api_key)-1); + else if (strcmp(key, "location") == 0) strncpy(cfg->location, val, sizeof(cfg->location)-1); + else if (strcmp(key, "units") == 0) strncpy(cfg->units, val, sizeof(cfg->units)-1); + } + } + + fclose(f); + return cfg->api_key[0] && cfg->location[0]; +} + +/* ---------------- libcurl callback ---------------- */ +struct mem { + char *data; + size_t size; +}; + +static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *userdata) { + struct mem *m = (struct mem *)userdata; + size_t total = size * nmemb; + + if (m->size + total < 10240) { + memcpy(m->data + m->size, ptr, total); + m->size += total; + m->data[m->size] = '\0'; + } + return total; +} + +/* ---------------- Fetch temperature ---------------- */ +bool fetch_temp_owm(const config_t *cfg, char *out, size_t out_size) { + if (!cfg || !out) return false; + + CURL *curl = curl_easy_init(); + if (!curl) return false; + + char url[512]; + snprintf(url, sizeof(url), + "https://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", + cfg->location, cfg->units[0] ? cfg->units : "metric", cfg->api_key); + + char buffer[10240] = {0}; + struct mem m = { buffer, 0 }; + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &m); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "tty-clock-weather/1.0"); + + CURLcode res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + if (res != CURLE_OK) return false; + + char *p = strstr(buffer, "\"temp\":"); + if (!p) return false; + p += 7; + + double temp = atof(p); + char unit = (cfg->units[0] && strcmp(cfg->units, "imperial") == 0) ? 'F' : 'C'; + snprintf(out, out_size, "%.0f°%c %s", temp, unit, cfg->location); + + return true; +} + +/* ---------------- Main ---------------- */ +int main(int argc, char **argv) { +bool twelve_hour = false; +bool human_date = false; +bool quiet = false; +bool hide_temp = false; +bool force_c = false; +bool force_f = false; + +/* Parse CLI flags FIRST */ + +for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--help") == 0) { + goto show_help; + } + if (argv[i][0] != '-') continue; + + for (int j = 1; argv[i][j]; j++) { + switch (argv[i][j]) { + case 't': twelve_hour = true; break; + case 'H': human_date = true; break; + case 'q': quiet = true; break; + case 'T': hide_temp = true; break; + case 'C': force_c = true; break; + case 'F': force_f = true; break; + + case 'h': + goto show_help; + + show_help: + + printf("Usage: %s [-HqTtCF]\n\n", argv[0]); + printf("Options:\n"); + printf(" -t Use 12-hour time format\n"); + printf(" -H Human-readable date (\"Tuesday 16, Feb\")\n"); + printf(" -q Hide \"Press q to quit\" footer\n"); + printf(" -T Hide temperature display\n"); + printf(" -C Force Celsius\n"); + printf(" -F Force Fahrenheit\n"); + printf(" -h,--help Show this help\n"); + return 0; + + default: + printf("Unknown flag: -%c\n", argv[i][j]); + return 1; + } + } +} + +/* NOW load config */ + +config_t cfg = {0}; +char config_path[512]; +snprintf(config_path, sizeof(config_path), "%s/.config/cclock/config", getenv("HOME")); + +if (!load_config_toml(&cfg, config_path)) { + hide_temp = true; + printf("Failed to load config from %s\n", config_path); +} +/* WORK IN PROGRESS CUSTOM_CONFIG +else if (custom_config = true) { + snprintf(config_path, sizeof(config_path), "%s/.config/cclock/config", getenv("HOME")); +}*/ + + +/* NOW apply overrides */ + +if (force_c) { + strncpy(cfg.units, "metric", sizeof(cfg.units) - 1); + cfg.units[sizeof(cfg.units) - 1] = '\0'; +} +else if (force_f) { + strncpy(cfg.units, "imperial", sizeof(cfg.units) - 1); + cfg.units[sizeof(cfg.units) - 1] = '\0'; +} + +for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-') continue; + + for (int j = 1; argv[i][j]; j++) { + switch (argv[i][j]) { + case 't': + twelve_hour = true; + break; + + case 'T': + hide_temp = true; + break; + + case 'C': + force_c = true; + break; + + case 'F': + force_f = true; + break; + + case 'H': + human_date = true; + break; + + case 'q': + quiet = true; + break; + + /*case 'c': + goto custom_config;*/ + + case 'h': + goto show_help; + + default: + printf("Unknown flag: -%c\n", argv[i][j]); + return 1; + } + } +} + + signal(SIGINT, handle_sigint); + signal(SIGWINCH, handle_winch); + + initscr(); + cbreak(); + noecho(); + curs_set(0); + keypad(stdscr, TRUE); + nodelay(stdscr, TRUE); + + curl_global_init(CURL_GLOBAL_DEFAULT); + + char time_buf[16], date_buf[20], temp_buf[64]; + time_t last_fetch = 0; + const int refresh_interval = 600; /* 10 minutes */ + + if (!fetch_temp_owm(&cfg, temp_buf, sizeof(temp_buf))) + strncpy(temp_buf, "N/A", sizeof(temp_buf)); + + while (running) { + if (resized) { + endwin(); + refresh(); + clear(); + resized = 0; + } + + clear(); + + time_t now = time(NULL); + struct tm *tm_now = localtime(&now); + if (!tm_now) break; + + const char *time_fmt = twelve_hour ? "%I:%M %p" : "%H:%M"; + strftime(time_buf, sizeof(time_buf), time_fmt, tm_now); + + const char *date_fmt = human_date ? "%A %d, %b" : "%m/%d/%Y"; + strftime(date_buf, sizeof(date_buf), date_fmt, tm_now); + + if (difftime(now, last_fetch) >= refresh_interval) { + if (!fetch_temp_owm(&cfg, temp_buf, sizeof(temp_buf))) + strncpy(temp_buf, "N/A", sizeof(temp_buf)); + last_fetch = now; + } + + int rows, cols; + getmaxyx(stdscr, rows, cols); + + int time_x = (cols - strlen(time_buf)) / 2; + int y_mid = rows / 2; + attron(A_BOLD); + mvprintw(y_mid -1, time_x, "%s", time_buf); + attroff(A_BOLD); + + int date_x = (cols - strlen(date_buf)) / 2; + mvprintw(y_mid, date_x, "%s", date_buf); + + if (!hide_temp) { + int temp_x = (cols - strlen(temp_buf)) / 2; + mvprintw(y_mid + 1, temp_x, "%s", temp_buf); + } + + if (!quiet) + mvprintw(rows - 1, 0, "Press 'q' to quit"); + + refresh(); + + int ch = getch(); + if (ch == 'q' || ch == 'Q') break; + + sleep(1); + } + + curl_global_cleanup(); + endwin(); + return 0; +} diff --git a/cclock.c b/cclock.c index e63f70f..192f620 100644 --- a/cclock.c +++ b/cclock.c @@ -291,15 +291,15 @@ for (int i = 1; i < argc; i++) { int time_x = (cols - strlen(time_buf)) / 2; int y_mid = rows / 2; attron(A_BOLD); - mvprintw(y_mid, time_x, "%s", time_buf); + mvprintw(y_mid -1, time_x, "%s", time_buf); attroff(A_BOLD); int date_x = (cols - strlen(date_buf)) / 2; - mvprintw(y_mid + 1, date_x, "%s", date_buf); + mvprintw(y_mid, date_x, "%s", date_buf); if (!hide_temp) { int temp_x = (cols - strlen(temp_buf)) / 2; - mvprintw(y_mid + 2, temp_x, "%s", temp_buf); + mvprintw(y_mid + 1, temp_x, "%s", temp_buf); } if (!quiet) diff --git a/toml-parse b/toml-parse new file mode 100755 index 0000000000000000000000000000000000000000..09b80acec276ba358c4b09dcd0b71802bf33e243 GIT binary patch literal 12632 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 GxC{Uxj&QvI literal 0 HcmV?d00001 diff --git a/toml-parse.c b/toml-parse.c new file mode 100644 index 0000000..3408764 --- /dev/null +++ b/toml-parse.c @@ -0,0 +1,26 @@ +#include +#include + +typedef struct { + char api_key[128]; + char location[64]; + char units[16]; +} config_t; + +static bool load_config_toml(config_t *cfg, const char *path) { + +int main() { + config_t cfg = {0}; + char config_path[512]; + snprintf(config_path, sizeof(config_path), "%s/.config/cclock/config", getenv("HOME")); + + if (!load_config_toml(&cfg, config_path)) { + printf("Failed to load config from %s\n", config_path); + } + + else if (load_config_toml(&cfg, config_path)) { + printf("Loaded config from %s\n", config_path); + } + + return 0; +}