summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh1
-rw-r--r--daemon.c114
-rw-r--r--daemon.h23
-rw-r--r--log.h11
-rw-r--r--main.c26
-rwxr-xr-xpomodorobin0 -> 23120 bytes
-rw-r--r--pomodoro.c3
-rw-r--r--pomodoro.h15
-rw-r--r--string.c86
-rw-r--r--string.h37
-rw-r--r--timer.c95
-rw-r--r--timer.h30
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
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 <stdio.h>
+#include <stdlib.h>
+
+
+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 <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
new file mode 100755
index 0000000..1c69e87
--- /dev/null
+++ b/pomodoro
Binary files 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 <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
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 <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);
+ }
+ }
+}
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 <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