diff options
| -rwxr-xr-x | build.sh | 1 | ||||
| -rw-r--r-- | daemon.c | 114 | ||||
| -rw-r--r-- | daemon.h | 23 | ||||
| -rw-r--r-- | log.h | 11 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rwxr-xr-x | pomodoro | bin | 0 -> 23120 bytes | |||
| -rw-r--r-- | pomodoro.c | 3 | ||||
| -rw-r--r-- | pomodoro.h | 15 | ||||
| -rw-r--r-- | string.c | 86 | ||||
| -rw-r--r-- | string.h | 37 | ||||
| -rw-r--r-- | timer.c | 95 | ||||
| -rw-r--r-- | timer.h | 30 |
12 files changed, 441 insertions, 0 deletions
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 <signal.h> +#include <errno.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthread.h> +#include <assert.h> + +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 @@ -0,0 +1,11 @@ +#ifndef LOG_H +#define LOG_H + +#include <stdio.h> +#include <stdlib.h> + + +void log_error() + + +#endif @@ -0,0 +1,26 @@ +#include "string.h" +#include "timer.h" +#include "daemon.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <string.h> + +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 Binary files differnew file mode 100755 index 0000000..1c69e87 --- /dev/null +++ b/pomodoro 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 <stdlib.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + +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 <stddef.h> + +#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 @@ -0,0 +1,95 @@ +#include "timer.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <sys/timerfd.h> +#include <sys/eventfd.h> +#include <poll.h> + +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); + } + } +} @@ -0,0 +1,30 @@ +#ifndef TIMER_H +#define TIMER_H + +#include <stddef.h> + +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 |
