commit b0613d87eb19532de28e5b6021271221a89873ff Author: Tyler Murphy Date: Sat Apr 22 00:48:41 2023 -0400 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..45e10d2 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +CC = gcc + +INCFLAGS = -Isrc + +CCFLAGS = -std=gnu99 -Wall -Wextra -pedantic -O2 +CCFLAGS += $(INCFLAGS) + +LDFLAGS += $(INCFLAGS) + +BIN = bin +APP = $(BIN)/app +SRC = $(shell find src -name "*.c") +OBJ = $(SRC:%.c=$(BIN)/%.o) + +.PHONY: dirs run clean build install uninstall + +EOF: clean build + +dirs: + mkdir -p ./$(BIN) + mkdir -p ./$(BIN)/src + +run: build + $(APP) + +build: dirs ${OBJ} + ${CC} -o $(APP) $(filter %.o,$^) $(LDFLAGS) + +$(BIN)/%.o: %.c + $(CC) -o $@ -c $< $(CCFLAGS) + +clean: + rm -rf $(APP) + rm -rf $(BIN) + +install: + cp $(APP) /usr/local/bin/ritfetch + +uninstall: + rm /usr/local/bin/ritfetch diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..01bc02a --- /dev/null +++ b/src/main.c @@ -0,0 +1,163 @@ +#undef _POSIX_C_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 +#define NUM_LENGTH 32 +#define MAX_LINES 64 +#define INIT_BUFFER_LEN 8 + +static char* get_line(char* buf, int len, FILE* file) { + char* ptr = fgets(buf, len, file); + if (ptr == NULL) return NULL; + buf[strcspn(buf, "\n")] = 0; + return ptr; +} + +#define LINE(buf, line) buf + line * LINE_LENGTH +#define MAX(a, b) a > b ? a : b +static char* read_logo(FILE* file, uint16_t* height) { + uint16_t capacity = INIT_BUFFER_LEN; + uint16_t h = 0; + + char* buf = malloc(LINE_LENGTH * capacity); + while (h < MAX_LINES && get_line(LINE(buf, h), LINE_LENGTH - 1, file) != NULL) { + h++; + if (h == capacity) { + capacity *= 2; + buf = realloc(buf, LINE_LENGTH * capacity); + } + } + + *height = h; + return buf; +} + +static char* read_data(FILE* file, uint16_t* height, uint16_t* offset) { + uint16_t capacity = INIT_BUFFER_LEN; + uint16_t h = 2, o = 0; + char accent_color[NUM_LENGTH], normal_color[NUM_LENGTH], offset_buffer[NUM_LENGTH], title_buffer[LINE_LENGTH]; + + char* end; + if (get_line(offset_buffer, NUM_LENGTH - 1, file) == NULL) { + printf("error: data file missing offset\n"); + exit(EXIT_FAILURE); + } + o = strtol(offset_buffer, &end, 10); + if (offset_buffer == end) { + printf("error: data offset is not a valid numver\n"); + exit(EXIT_FAILURE); + } + *offset = o; + + if (get_line(accent_color, NUM_LENGTH - 1, file) == NULL) { + printf("error: data file missing accent color\n"); + exit(EXIT_FAILURE); + } + + if (get_line(normal_color, NUM_LENGTH - 1, file) == NULL) { + printf("error: data file missing normal color\n"); + exit(EXIT_FAILURE); + } + + if (get_line(title_buffer, LINE_LENGTH - 1, file) == NULL) { + printf("error: data file missing title\n"); + exit(EXIT_FAILURE); + } + + char* buf = malloc(LINE_LENGTH * capacity); + + // funny stuff be goofy ahh'ing here + size_t title_len = strlen(title_buffer); + snprintf(LINE(buf, 1), LINE_LENGTH, "\x1b[%sm", normal_color); + size_t ansi_len = strlen(LINE(buf, 1)); + memset(LINE(buf, 1) + ansi_len, '~', title_len); + (LINE(buf, 1))[title_len + ansi_len] = 0; + snprintf(LINE(buf, 0), LINE_LENGTH, "\x1b[%sm%s", accent_color, title_buffer); + + char key[LINE_LENGTH]; + char value[LINE_LENGTH]; + + while(h < MAX_LINES) { + if (get_line(key, LINE_LENGTH - 1, file) == NULL) break; + if (get_line(value, LINE_LENGTH - 1, file) == NULL) break; + + #pragma GCC diagnostic ignored "-Wformat-truncation" + snprintf(LINE(buf, h), LINE_LENGTH, "\x1b[%sm%s\x1b[%sm: %s", accent_color, key, normal_color, value); + + h++; + if (h == capacity) { + capacity *= 2; + buf = realloc(buf, LINE_LENGTH * capacity); + } + } + + *height = h; + return buf; +} + +__attribute__ ((__format__(printf, 1, 2))) +static FILE* run_command(const char* format, ...) { + va_list valist; + va_start(valist, format); + + char buf[LINE_LENGTH]; + vsnprintf(buf, LINE_LENGTH, format, valist); + + FILE* out = popen(buf, "r"); + if (out == NULL) { + printf("error: failed to run command %s: %s\n", buf, strerror(errno)); + exit(EXIT_FAILURE); + } + return out; +} + +static void close_command(FILE* out) { + int code = pclose(out); + if (code != 0) { + printf("error: command errored with exit code %d\n", code); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char** argv) { + + if (argc != 2) { + printf("usage: ritfetch domain\n"); + return EXIT_FAILURE; + } + + FILE* out; + + out = run_command("curl -Lsf %s/.well-known/ritfetch/logo", argv[1]); + uint16_t logo_height; + char* logo = read_logo(out, &logo_height); + close_command(out); + + out = run_command("curl -Lsf %s/.well-known/ritfetch/data", argv[1]); + uint16_t data_height, offset; + char* data = read_data(out, &data_height, &offset); + close_command(out); + + uint16_t max_height = MAX(logo_height, data_height); + for (uint16_t i = 0; i < max_height; i++) { + if (i < logo_height) { + printf("%s", LINE(logo, i)); + } + if (i < data_height) { + printf("\x1b[%uG\x1b[m", offset); + printf("%s", LINE(data, i)); + } + printf("\n"); + } + + free(data); + free(logo); + + return EXIT_SUCCESS; +}