/**
* Copyright © 2013, 2015 Mattias Andrée (maandree@member.fsf.org)
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty. [GNU All Permissive License]
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <time.h>
#include <stddef.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/timerfd.h>
$<
d() {
echo '"'"$(echo "$1" | sed -e 's/X/ /g' -e 's/\[/\\033\[7m /g' -e 's/\]/\\033\[m /g')"'"'
}
$>
#define DX 16
#define DY 12
static const char* mongo_0[] = {$(d ' [XXXX] '),
$(d ' [XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [] [XX] '),
$(d '[XX] [] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d ' [XX] [XX] '),
$(d ' [XXXX] ')};
static const char* mongo_1[] = {$(d ' [XX] '),
$(d ' [XXXX] '),
$(d ' [XXXXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XXXXXXXXXX] ')};
static const char* mongo_2[] = {$(d ' [XXXXXXXX] '),
$(d '[XX] [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d '[XX] '),
$(d '[XX] [XX] '),
$(d '[XXXXXXXXXXXX] ')};
static const char* mongo_3[] = {$(d ' [XXXXXXXX] '),
$(d '[XX] [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XXXXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXX] ')};
static const char* mongo_4[] = {$(d ' [XX] '),
$(d ' [XXXX] '),
$(d ' [XXXXXX] '),
$(d ' [XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XXXXXXXXXXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XXXXXX] ')};
static const char* mongo_5[] = {$(d '[XXXXXXXXXXXX] '),
$(d '[XX] '),
$(d '[XX] '),
$(d '[XX] '),
$(d '[XX] '),
$(d '[XXXXXXXXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXX] ')};
static const char* mongo_6[] = {$(d ' [XXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d '[XX] '),
$(d '[XX] '),
$(d '[XXXXXXXXXX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXX] ')};
static const char* mongo_7[] = {$(d '[XXXXXXXXXXXX] '),
$(d '[XX] [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] ')};
static const char* mongo_8[] = {$(d ' [XXXXXXXX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXX] ')};
static const char* mongo_9[] = {$(d ' [XXXXXXXX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d '[XX] [XX] '),
$(d ' [XXXXXXXXXX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' [XXXX] ')};
#define DC 16
static const char* mongo_c[] = {$(d ' '),
$(d ' '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' '),
$(d ' '),
$(d ' '),
$(d ' '),
$(d ' [XX] '),
$(d ' [XX] '),
$(d ' '),
$(d ' ')};
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;
#define t(...) do if ((__VA_ARGS__) < 0) goto fail; while (0)
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] != NULL; c++)
fprintf(stdout, "%s", str[c][r]);
fprintf(stdout, "\033[0K");
}
fprintf(stdout, "\033[0J");
fflush(stdout);
}
int main(int argc, char* argv[])
{
time_t now_;
struct tm* now;
const char** digits[9];
size_t x = 0, y = 0;
struct winsize winsize;
int small = 0, fd = -1;
struct itimerspec itimerspec;
char _buf[8];
fprintf(stdout, "\033[?1049h\033[?25l");
t (clock_gettime(CLOCK_REALTIME, &(itimerspec.it_value)));
itimerspec.it_interval.tv_sec = 1;
itimerspec.it_interval.tv_nsec = 0;
itimerspec.it_value.tv_sec += 1;
itimerspec.it_value.tv_nsec = 0;
t (fd = timerfd_create(CLOCK_REALTIME, 0));
t (timerfd_settime(fd, TFD_TIMER_ABSTIME, &itimerspec, NULL));
signal(SIGTERM, sigterm);
signal(SIGQUIT, sigterm);
signal(SIGINT, sigterm);
signal(SIGWINCH, sigwinch);
siginterrupt(SIGTERM, 1);
siginterrupt(SIGQUIT, 1);
siginterrupt(SIGINT, 1);
siginterrupt(SIGWINCH, 1);
while (!caught_sigterm)
{
if (caught_sigwinch)
{
caught_sigwinch = 0;
t (TEMP_FAILURE_RETRY(ioctl(STDOUT_FILENO, (unsigned long)TIOCGWINSZ, &winsize)));
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;
}
now_ = time(NULL);
if (now_ == -1) goto fail;
now = localtime(&now_);
if (now == NULL) goto fail;
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];
digits[8] = NULL;
print_time(digits, y, x);
if (read(fd, _buf, (size_t)8) < 0)
if (errno != EINTR)
goto fail;
}
fprintf(stdout, "\033[?25h\n\033[?1049l");
fflush(stdout);
TEMP_FAILURE_RETRY(close(fd));
return 0;
fail:
perror(*argv);
fprintf(stdout, "\033[?25h\n\033[?1049l");
fflush(stdout);
if (fd >= 0)
TEMP_FAILURE_RETRY(close(fd));
return 1;
(void) argc;
}