/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include #include #include #ifdef USE_ADJTIMEX # include #endif #include "arg.h" #define DX 16 #define DY 12 #define DC 16 #include "mongo_0.h" #include "mongo_1.h" #include "mongo_2.h" #include "mongo_3.h" #include "mongo_4.h" #include "mongo_5.h" #include "mongo_6.h" #include "mongo_7.h" #include "mongo_8.h" #include "mongo_9.h" #include "mongo_c.h" static const char **mongo_ds[] = { mongo_0, mongo_1, mongo_2, mongo_3, mongo_4, mongo_5, mongo_6, mongo_7, mongo_8, mongo_9 }; static volatile sig_atomic_t caught_sigterm = 0; static volatile sig_atomic_t caught_sigwinch = 1; char *argv0; static void usage(void) { fprintf(stderr, "usage: %s [-s]\n", argv0); exit(1); } static void sigterm(int signo) { caught_sigterm = 1; (void) signo; } static void sigwinch(int signo) { caught_sigwinch = 1; (void) signo; } static void print_time(const char ***str, size_t y, size_t x) { size_t r, c; fprintf(stdout, "\033[%zu;1H\033[1J", y + 1); for (r = 0; r < DY; r++) { fprintf(stdout, "\033[%zu;%zuH\033[1K", y + r + 1, x + 1); for (c = 0; str[c]; c++) fprintf(stdout, "%s", str[c][r]); fprintf(stdout, "\033[0K"); } fprintf(stdout, "\033[0J"); fflush(stdout); } static int display_time(int timerfd) { const char **digits[9]; int small = 0; uint64_t _overrun; struct winsize winsize; size_t x = 0, y = 0; struct tm *now; #ifdef USE_ADJTIMEX struct timex timex; int r; #else time_t now_; #endif #ifdef USE_ADJTIMEX memset(&timex, 0, sizeof(timex)); #endif digits[8] = NULL; while (!caught_sigterm) { if (caught_sigwinch) { if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) { if (errno == EINTR) continue; goto fail; } caught_sigwinch = 0; y = winsize.ws_row; x = winsize.ws_col; if (y < DY) small = 2; else if (x < 4 * DX + DC) small = 2; else if (x < 6 * DX + 2 * DC) small = 1; else small = 0; y -= DY; x -= 4 * DX + DC; if (!small) x -= 2 * DX + DC; y /= 2; x /= 2; } if (small == 2) { fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small"); fflush(stdout); pause(); continue; } #ifdef USE_ADJTIMEX r = adjtimex(&timex); if (r == -1) goto fail; if (timex.time.tv_sec % (24 * 60 * 60) == 0) { if (r == TIME_INS) { timex.time.tv_sec -= 1; now = localtime(&timex.time.tv_sec); if (!now) goto fail; now->tm_sec += 1; goto now_checked; } else if (r == TIME_DEL) { timex.time.tv_sec += 1; now = localtime(&timex.time.tv_sec); } else { now = localtime(&timex.time.tv_sec); } } else if (r == TIME_OOP) { now = localtime(&timex.time.tv_sec); now->tm_sec += 1; } else { now = localtime(&timex.time.tv_sec); } if (!now) goto fail; now_checked: #else now_ = time(NULL); if (now_ == -1) goto fail; now = localtime(&now_); if (now == NULL) goto fail; #endif digits[0] = mongo_ds[now->tm_hour / 10]; digits[1] = mongo_ds[now->tm_hour % 10]; digits[2] = mongo_c; digits[3] = mongo_ds[now->tm_min / 10]; digits[4] = mongo_ds[now->tm_min % 10]; digits[5] = small ? NULL : mongo_c; digits[6] = mongo_ds[now->tm_sec / 10]; digits[7] = mongo_ds[now->tm_sec % 10]; print_time(digits, y, x); if (read(timerfd, &_overrun, sizeof(_overrun)) < 0) if (errno != EINTR) goto fail; } return 0; fail: return -1; } static int display_posixtime(int timerfd) { const char **digits[21]; uint64_t _overrun; struct winsize winsize; size_t w = 0, h = 0, x, y; time_t now; size_t first_digit, ndigits; digits[20] = NULL; while (!caught_sigterm) { if (caught_sigwinch) { if (ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize) < 0) { if (errno == EINTR) continue; goto fail; } caught_sigwinch = 0; h = winsize.ws_row; w = winsize.ws_col; } now = time(NULL); if (now < 0) goto fail; first_digit = 20; do { if (!first_digit) abort(); digits[--first_digit] = mongo_ds[now % 10]; } while (now /= 10); ndigits = 20 - first_digit; if (h < DY || w < ndigits * DX) { fprintf(stdout, "\033[H\033[2J%s\n", "Screen is too small"); fflush(stdout); pause(); continue; } y = (h - DY) / 2; x = (w - ndigits * DX) / 2; print_time(&digits[first_digit], y, x); if (read(timerfd, &_overrun, sizeof(_overrun)) < 0) if (errno != EINTR) goto fail; } return 0; fail: return -1; } int main(int argc, char *argv[]) { int timerfd = -1; int posixtime = 0; struct itimerspec itimerspec; struct sigaction sigact; ARGBEGIN { case 's': posixtime = 1; break; default: usage(); } ARGEND; if (argc) usage(); fprintf(stdout, "\033[?1049h\033[?25l"); if (clock_gettime(CLOCK_REALTIME, &itimerspec.it_value)) goto fail; itimerspec.it_interval.tv_sec = 1; itimerspec.it_interval.tv_nsec = 0; itimerspec.it_value.tv_sec += 1; itimerspec.it_value.tv_nsec = 0; timerfd = timerfd_create(CLOCK_REALTIME, 0); if (timerfd < 0) goto fail; if (timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &itimerspec, NULL)) goto fail; memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = sigterm; sigaction(SIGTERM, &sigact, NULL); sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGINT, &sigact, NULL); sigact.sa_handler = sigwinch; sigaction(SIGWINCH, &sigact, NULL); if (posixtime ? display_posixtime(timerfd) : display_time(timerfd)) goto fail; fprintf(stdout, "\033[?25h\n\033[?1049l"); fflush(stdout); close(timerfd); return 0; fail: perror(argv0 ? argv0 : "mongoclock"); fprintf(stdout, "\033[?25h\n\033[?1049l"); fflush(stdout); if (timerfd >= 0) close(timerfd); return 1; }