Compare commits
No commits in common. "d9e6f8b3a37d5e698b9caed2f79914c5a2917822" and "8643a180f137c29a451509a234ccda900e71c207" have entirely different histories.
d9e6f8b3a3
...
8643a180f1
7 changed files with 1 additions and 685 deletions
19
README.md
19
README.md
|
|
@ -1,21 +1,2 @@
|
||||||
# cclock
|
# cclock
|
||||||
#### Simply C program to display the time and temperature without too much fuss, made for home use.
|
|
||||||
|
|
||||||
Current the only dependencies are:
|
|
||||||
```
|
|
||||||
gcc
|
|
||||||
libncurses
|
|
||||||
libcurl
|
|
||||||
```
|
|
||||||
|
|
||||||
Build with ```gcc -Wall -Wextra -pedantic -std=c11 cclock.c -lncurses -lcurl -o cclock```
|
|
||||||
|
|
||||||
To effectively use this program, there is a toml config you must provide
|
|
||||||
$HOME/.conifg/cclock/config
|
|
||||||
```
|
|
||||||
[weather]
|
|
||||||
api_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
||||||
location = "Portland,US"
|
|
||||||
units = "imperial" # metric is another option
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
||||||
BIN
cclock
BIN
cclock
Binary file not shown.
319
cclock.bkp.c
319
cclock.bkp.c
|
|
@ -1,319 +0,0 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
|
||||||
|
|
||||||
#include <ncurses.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
319
cclock.c
319
cclock.c
|
|
@ -1,319 +0,0 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
|
||||||
|
|
||||||
#include <ncurses.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
1
error
1
error
|
|
@ -1 +0,0 @@
|
||||||
cannot evaluate a function that has an argument without a value ('lib') Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'.
|
|
||||||
BIN
toml-parse
BIN
toml-parse
Binary file not shown.
26
toml-parse.c
26
toml-parse.c
|
|
@ -1,26 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue