/* * atc.web.c: the update timer of Atc in the browser (fredygames.com). The game asks the system for a SIGALRM * every few seconds (setitimer/alarm) and runs update() in the signal handler, while it waits for a key. Here * there are no signals: setitimer() and alarm() only record the deadline, and atc_getchar() (which replaces * getchar(), see include.h) runs update() when the deadline passes while it waits for a key from the page * (curses-web/curses.c), which is what the signal did. * Copyright (C) 2026 FredyGames. Distributed under the MIT License (see curses-web/LICENSE). */ #include #include #include #include "curses.h" extern void update(int); extern void quit(int); static double deadline = -1.0; /* ms (emscripten_get_now), < 0: timer off */ static double interval = 0.0; /* ms, 0: one shot */ static double to_ms(const struct timeval *tv) { return tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0; } int setitimer(int which, const struct itimerval *restrict value, struct itimerval *restrict old) { (void)which; if (old != NULL) { double left = deadline < 0 ? 0 : deadline - emscripten_get_now(); if (left < 0) left = 0; old->it_value.tv_sec = (time_t)(left / 1000); old->it_value.tv_usec = (suseconds_t)((left - old->it_value.tv_sec * 1000.0) * 1000); old->it_interval.tv_sec = (time_t)(interval / 1000); old->it_interval.tv_usec = (suseconds_t)((interval - old->it_interval.tv_sec * 1000.0) * 1000); } if (value != NULL) { double first = to_ms(&value->it_value); interval = to_ms(&value->it_interval); deadline = first > 0 ? emscripten_get_now() + first : -1.0; } return 0; } unsigned int alarm(unsigned int seconds) { double left = deadline < 0 ? 0 : (deadline - emscripten_get_now()) / 1000; interval = 0; deadline = seconds > 0 ? emscripten_get_now() + seconds * 1000.0 : -1.0; return left > 0 ? (unsigned int)(left + 0.999) : 0; } int atc_getchar(void) { for (;;) { int wait = -1; if (deadline >= 0) { double now = emscripten_get_now(); if (now >= deadline) { deadline = interval > 0 ? deadline + interval : -1.0; if (deadline >= 0 && deadline < now) deadline = now + interval; update(0); continue; } wait = (int)(deadline - now + 0.999); } int k = cw_getkey(wait); if (k == 3) { /* ^C: SIGINT, which the game catches to ask "Really quit?" */ quit(0); continue; } if (k != ERR) return k == '\r' ? '\n' : k; /* the game sets ICRNL on the tty: Enter is '\n' */ } } /* flex's end-of-input hook (the game links -ll on Unix). */ int yywrap(void) { return 1; }