From 9a443189203376a630ac205ca4654c7ceb796d5b Mon Sep 17 00:00:00 2001 From: 0x221E <0x221E@0xinfinity.dev> Date: Sun, 12 Apr 2026 15:47:30 +0200 Subject: Initial Commit --- build.sh | 1 + daemon.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ daemon.h | 23 +++++++++++++ log.h | 11 ++++++ main.c | 26 ++++++++++++++ pomodoro | Bin 0 -> 23120 bytes pomodoro.c | 3 ++ pomodoro.h | 15 ++++++++ string.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ string.h | 37 ++++++++++++++++++++ timer.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ timer.h | 30 ++++++++++++++++ 12 files changed, 441 insertions(+) create mode 100755 build.sh create mode 100644 daemon.c create mode 100644 daemon.h create mode 100644 log.h create mode 100644 main.c create mode 100755 pomodoro create mode 100644 pomodoro.c create mode 100644 pomodoro.h create mode 100644 string.c create mode 100644 string.h create mode 100644 timer.c create mode 100644 timer.h diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7b5cbfb --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +gcc main.c string.c timer.c daemon.c -o pomodoro diff --git a/daemon.c b/daemon.c new file mode 100644 index 0000000..7b6ba09 --- /dev/null +++ b/daemon.c @@ -0,0 +1,114 @@ +#include "daemon.h" + +#include "timer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct sockaddr_un addr = (struct sockaddr_un){.sun_path = "/tmp/pomo.sock", .sun_family = AF_UNIX}; + +int socket_create() { + errno = 0; + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + printf("Socket creation failed! %s\n", strerror(errno)); + fflush(stdout); + exit(1); + } + return fd; +} + +void socket_set_server(int sockfd) { + errno = 0; + if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + printf("Socket bind failed! %s\n", strerror(errno)); + fflush(stdout); + exit(1); + } + errno = 0; + if (listen(sockfd, 1) == -1) { + printf("Socket listen() failed! %s\n", strerror(errno)); + exit(1); + } +} + +void socket_set_client(int sockfd) { + errno = 0; + if(connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + printf("Socket connect failed! %s\n", strerror(errno)); + fflush(stdout); + exit(1); + } +} + +void socket_bind_clean(int sig) { + unlink("/tmp/pomo.sock"); + exit(0); +} + +void daemon_init(Daemon* d) { + assert(d != NULL); + socket_set_server(d->sockfd); + signal(SIGINT, socket_bind_clean); + signal(SIGTERM, socket_bind_clean); + atexit((void *)socket_bind_clean); +} + +void* daemon_listener_loop(void *d) { + assert(d != NULL); + while(1) { + int clientfd = accept(((Daemon *)d)->sockfd, NULL, NULL); + + if (clientfd == -1) { + printf("Incoming connection failed.\n"); + continue; + } + + char buffer[1024]; + read(clientfd, buffer, 1024 - 1); + + // TODO: Create a mechanism to fetch commands without writing everything again. + // TODO: Make it so that a more efficient approach is used instead of a string. + if(strncmp(buffer, "start", sizeof("start")) == 0) { + timer_start(((Daemon *)d)->timer); + } + + if(strncmp(buffer, "toggle", sizeof("toggle")) == 0) { + timer_toggle_state(((Daemon *)d)->timer); + } + + if(strncmp(buffer, "reset", sizeof("reset")) == 0) { + timer_reset(((Daemon *)d)->timer); + } + + /* send(clientfd, "done", sizeof("done"), 0); */ + close(clientfd); + } + return NULL; +} + +void daemon_run(Daemon* d) { + assert(d != NULL); + + Timer t; + timer_init(&t, 3000); + d->timer = &t; + pthread_t thread; + if(pthread_create(&thread, NULL, daemon_listener_loop, d) != 0) { + printf("Error: daemon_listener_loop thread cannot be created!"); + exit(1); + } + + timer_loop(&t); + + void* retval; + pthread_join(thread, &retval); +} diff --git a/daemon.h b/daemon.h new file mode 100644 index 0000000..492764a --- /dev/null +++ b/daemon.h @@ -0,0 +1,23 @@ +#ifndef IPC_H +#define IPC_H + +typedef struct Timer Timer; + +int socket_create(); +void socket_set_server(int sockfd); +void socket_set_client(int sockfd); +void socket_bind_clean(int sig); + +struct Daemon { + int sockfd; + int statusfd; + Timer* timer; +}; + +typedef struct Daemon Daemon; + +void daemon_init(Daemon *d); +void *daemon_listener_loop(void *d); +void daemon_run(Daemon *d); + +#endif diff --git a/log.h b/log.h new file mode 100644 index 0000000..d9f65e2 --- /dev/null +++ b/log.h @@ -0,0 +1,11 @@ +#ifndef LOG_H +#define LOG_H + +#include +#include + + +void log_error() + + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..30b1755 --- /dev/null +++ b/main.c @@ -0,0 +1,26 @@ +#include "string.h" +#include "timer.h" +#include "daemon.h" + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + if (argc == 1) { + int sockfd = socket_create(); + Daemon d; + d.sockfd = sockfd; + daemon_init(&d); + daemon_run(&d); + return 0; + } + + int sockfd = socket_create(); + socket_set_client(sockfd); + write(sockfd, argv[1], sizeof(argv[1])); + + return 0; +} diff --git a/pomodoro b/pomodoro new file mode 100755 index 0000000..1c69e87 Binary files /dev/null and b/pomodoro differ diff --git a/pomodoro.c b/pomodoro.c new file mode 100644 index 0000000..10c1b57 --- /dev/null +++ b/pomodoro.c @@ -0,0 +1,3 @@ +#include "pomodoro.h" + + diff --git a/pomodoro.h b/pomodoro.h new file mode 100644 index 0000000..6888281 --- /dev/null +++ b/pomodoro.h @@ -0,0 +1,15 @@ +#ifndef POMODORO_H +#define POMODORO_H + +enum PomodoroState { + +}; + +struct Pomodoro { + +}; + +void pomodoro_init(Pomodoro *p); +void pomodoro_loop(Pomodoro *p); + +#endif diff --git a/string.c b/string.c new file mode 100644 index 0000000..68b01e4 --- /dev/null +++ b/string.c @@ -0,0 +1,86 @@ +#include "string.h" + +#include +#include +#include +#include +#include + +void sp_init(StringPool *sp, size_t len) { + assert(sp != NULL); + sp->mem = malloc(len); + if (sp->mem == NULL) { + printf("Malloc failed during sp_init!"); + exit(1); + } + sp->size = len; + sp->offset = 0; +} + +void* sp_reserve(StringPool *sp, size_t len) { + assert(sp != NULL); + if (sp->offset + len > sp->size) { + printf("String pool full!"); + exit(1); + } + + void *mem = sp->mem + sp->offset; + sp->offset += len; + return mem; +} + +StringView sv_create(StringPool *sp, char *str, size_t len) { + assert(str != NULL); + assert(len != 0); + void *mem = sp_reserve(sp, len); + memcpy(mem, str, len); + ((char*)mem)[len] = '\0'; + return (StringView){(char*)mem, len}; +} + +StringView sv_concat_ss(StringPool *sp, StringView a, StringView b) { + assert(sp != NULL); + + if (a.len == 0) return b; + if (b.len == 0) return a; // Handle the case where both strings are empty. + + size_t alen = a.len; + size_t blen = b.len; + + if (a.buf[a.len - 1] == '\0') alen -= 1; + if (b.buf[b.len - 1] == '\0') blen -= 1; + + size_t len = alen + blen; + char *mem = (char *)sp_reserve(sp, len + 1); + memcpy(mem, a.buf, alen); + memcpy(mem + alen, b.buf, blen); + mem[len] = '\0'; + return (StringView){.buf = mem, .len = len}; +} + +StringView sv_concat_ss_n(StringPool *sp, int n, ...) { + va_list args; + va_start(args, n); + StringView res = {.buf = "", .len = 0}; + for (int i = 0; i < n; i++) { + res = sv_concat_ss(sp, res, va_arg(args, StringView)); + } + va_end(args); + return res; +} + +StringView sv_sizet_to_string(StringPool *sp, size_t s) { + assert(sp != NULL); + size_t size = sizeof(size_t); + char* buf = sp_reserve(sp, size); + snprintf(buf, size, "%d", s); + size_t len = strlen(buf); + return (StringView){.buf = buf, .len = len}; +} + +void sv_printf_cs(char *fmt, ...) { + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} diff --git a/string.h b/string.h new file mode 100644 index 0000000..17e6bc6 --- /dev/null +++ b/string.h @@ -0,0 +1,37 @@ +#ifndef STRING_H +#define STRING_H + +#include + +#define SV(sp, str) sv_create(sp, str, sizeof(str)); + +struct StringView { + char *buf; + size_t len; +}; + +#define STRING_CONST {NULL, 0} + +struct StringPool { + void *mem; + size_t size; + size_t offset; +}; + +#define STRINGPOOL_CONST {NULL, 0, 0} + +typedef struct StringView StringView; +typedef struct StringPool StringPool; + +void sp_init(StringPool *sp, size_t len); +void* sp_reserve(StringPool *sp, size_t len); + +StringView sv_create(StringPool *sp, char *str, size_t len); +StringView sv_concat_ss(StringPool *sp, StringView a, StringView b); +StringView sv_concat_ss_n(StringPool *sp, int n, ...); + +StringView sv_sizet_to_string(StringPool *sp, size_t s); + +void sv_printf_cs(char *fmt, ...); + +#endif diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..58757d7 --- /dev/null +++ b/timer.c @@ -0,0 +1,95 @@ +#include "timer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +void timer_init(Timer *t, size_t sec) { + assert(t != NULL); + t->seconds = sec; + t->remaining_seconds = sec; + t->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if(t->timerfd == -1) { + fprintf(stdout, "Error: timerfd could not be created!"); + exit(1); + } +} + +void timer_reset(Timer *t) { + assert(t != NULL); + struct itimerspec spec = {0}; + timerfd_settime(t->timerfd, 0, &spec, NULL); + t->remaining_seconds = t->seconds; + size_t mins = t->remaining_seconds / 60; + size_t secs = t->remaining_seconds % 60; + fprintf(stdout, "{\"text\": \"Paused %02d:%02d\"}\n", mins, secs); + fflush(stdout); +} + +void timer_start(Timer *t) { + assert(t != NULL); + t->status = T_RUNNING; + struct itimerspec spec; + spec.it_interval.tv_sec = 1; + spec.it_interval.tv_nsec = 0; + spec.it_value.tv_sec = 1; + spec.it_value.tv_nsec = 0; + timerfd_settime(t->timerfd, 0, &spec, NULL); +} + +void timer_stop(Timer *t) { + assert(t != NULL); + t->status = T_STOPPED; + struct itimerspec spec = {0}; + timerfd_settime(t->timerfd, 0, &spec, NULL); +} + +void timer_toggle_state(Timer *t) { + assert(t != NULL); + if(t->status == T_RUNNING) + timer_stop(t); + else if (t->status == T_STOPPED) + timer_start(t); +} + +void timer_loop(Timer *t) { // May drift by a couple mili-seconds. However, just a pomodoro app, so that is not important. + assert(t != NULL); + + t->remaining_seconds = t->seconds; + size_t mins = t->remaining_seconds / 60; + size_t secs = t->remaining_seconds % 60; + fprintf(stdout, "{\"text\": \"Paused %02d:%02d\"}\n", mins, secs); + fflush(stdout); + + struct pollfd fds; + fds.fd = t->timerfd; + fds.events = POLLIN; + + while (1) { + if(poll(&fds, 1, -1) == -1) { + printf("Failed to poll events!"); + exit(1); + } + + if(fds.revents & POLLIN) { + uint64_t tick; + read(t->timerfd, &tick, sizeof(tick)); + if(t->remaining_seconds == 0) { + fprintf(stdout,"{\"text\": \"Completed\"}\n"); + uint64_t buf; + timer_stop(t); + } else { + t->remaining_seconds--; + size_t mins = t->remaining_seconds / 60; + size_t secs = t->remaining_seconds % 60; + fprintf(stdout,"{\"text\": \"Work %02d:%02d\"}\n", mins, secs); + } + fflush(stdout); + } + } +} diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..c24611a --- /dev/null +++ b/timer.h @@ -0,0 +1,30 @@ +#ifndef TIMER_H +#define TIMER_H + +#include + +enum TimerState : unsigned int { + T_STOPPED = 0, + T_RUNNING, +}; + +struct Timer { + size_t seconds; + size_t remaining_seconds; + int timerfd; + enum TimerState status; +}; + +typedef struct Timer Timer; +typedef enum TimerState TimerState; + +void timer_init(Timer *t, size_t sec); + +void timer_reset(Timer *t); +void timer_start(Timer *t); +void timer_stop(Timer *t); +void timer_toggle_state(Timer *t); +int timer_request_time(); +void timer_loop(Timer *t); + +#endif -- cgit v1.2.3