52 #define _XOPEN_SOURCE 500 53 #define _DARWIN_C_SOURCE 1 54 #define __BSD_VISIBLE 1 66 #include <sys/ioctl.h> 88 #include "animation.h" 95 const char * colors[256] = {NULL};
101 const char * output =
" ";
111 int show_counter = 1;
117 unsigned int frame_count = 0;
123 int clear_screen = 1;
144 int digits(
int val) {
146 if (val >= 0)
for (c = 10; c <= val; c *= 10) d++;
147 else for (c = -10 ; c >= val; c *= 10) d++;
148 return (c < 0) ? ++d : d;
163 int terminal_width = 80;
164 int terminal_height = 24;
169 char using_automatic_width = 0;
170 char using_automatic_height = 0;
178 printf(
"\033[?25h\033[0m\033[H\033[2J");
189 void SIGINT_handler(
int sig){
198 void SIGALRM_handler(
int sig) {
201 longjmp(environment, 1);
209 void SIGPIPE_handler(
int sig) {
214 void SIGWINCH_handler(
int sig) {
217 ioctl(0, TIOCGWINSZ, &w);
218 terminal_width = w.ws_col;
219 terminal_height = w.ws_row;
221 if (using_automatic_width) {
222 min_col = (FRAME_WIDTH - terminal_width/2) / 2;
223 max_col = (FRAME_WIDTH + terminal_width/2) / 2;
226 if (using_automatic_height) {
227 min_row = (FRAME_HEIGHT - (terminal_height-1)) / 2;
228 max_row = (FRAME_HEIGHT + (terminal_height-1)) / 2;
231 signal(SIGWINCH, SIGWINCH_handler);
238 void newline(
int n) {
240 for (i = 0; i < n; ++i) {
258 unsigned char telnet_options[256] = { 0 };
259 unsigned char telnet_willack[256] = { 0 };
266 unsigned char telnet_do_set[256] = { 0 };
267 unsigned char telnet_will_set[256]= { 0 };
274 telnet_options[ECHO] = WONT;
276 telnet_options[SGA] = WILL;
278 telnet_options[NEW_ENVIRON] = WONT;
281 telnet_willack[ECHO] = DO;
283 telnet_willack[SGA] = DO;
285 telnet_willack[NAWS] = DO;
287 telnet_willack[TTYPE] = DO;
289 telnet_willack[LINEMODE] = DONT;
291 telnet_willack[NEW_ENVIRON] = DO;
298 void send_command(
int cmd,
int opt) {
300 if (cmd == DO || cmd == DONT) {
302 if (((cmd == DO) && (telnet_do_set[opt] != DO)) ||
303 ((cmd == DONT) && (telnet_do_set[opt] != DONT))) {
305 telnet_do_set[opt] = cmd;
306 printf(
"%c%c%c", IAC, cmd, opt);
308 }
else if (cmd == WILL || cmd == WONT) {
310 if (((cmd == WILL) && (telnet_will_set[opt] != WILL)) ||
311 ((cmd == WONT) && (telnet_will_set[opt] != WONT))) {
313 telnet_will_set[opt] = cmd;
314 printf(
"%c%c%c", IAC, cmd, opt);
318 printf(
"%c%c", IAC, cmd);
325 void usage(
char * argv[]) {
329 "usage: %s [-hitn] [-f \033[3mframes\033[0m]\n" 331 " -i --intro \033[3mShow the introduction / about information at startup.\033[0m\n" 332 " -t --telnet \033[3mTelnet mode.\033[0m\n" 333 " -n --no-counter \033[3mDo not display the timer\033[0m\n" 334 " -s --no-title \033[3mDo not set the titlebar text\033[0m\n" 335 " -e --no-clear \033[3mDo not clear the display between frames\033[0m\n" 336 " -f --frames \033[3mDisplay the requested number of frames, then quit\033[0m\n" 337 " -r --min-rows \033[3mCrop the animation from the top\033[0m\n" 338 " -R --max-rows \033[3mCrop the animation from the bottom\033[0m\n" 339 " -c --min-cols \033[3mCrop the animation from the left\033[0m\n" 340 " -C --max-cols \033[3mCrop the animation from the right\033[0m\n" 341 " -W --width \033[3mCrop the animation to the given width\033[0m\n" 342 " -H --height \033[3mCrop the animation to the given height\033[0m\n" 343 " -h --help \033[3mShow this help message.\033[0m\n",
347 int main(
int argc,
char ** argv) {
350 char term[1024] = {
'a',
'n',
's',
'i', 0};
353 uint32_t option = 0, done = 0, sb_mode = 0;
356 unsigned short sb_len = 0;
363 static struct option long_opts[] = {
364 {
"help", no_argument, 0,
'h'},
365 {
"telnet", no_argument, 0,
't'},
366 {
"intro", no_argument, 0,
'i'},
367 {
"skip-intro", no_argument, 0,
'I'},
368 {
"no-counter", no_argument, 0,
'n'},
369 {
"no-title", no_argument, 0,
's'},
370 {
"no-clear", no_argument, 0,
'e'},
371 {
"frames", required_argument, 0,
'f'},
372 {
"min-rows", required_argument, 0,
'r'},
373 {
"max-rows", required_argument, 0,
'R'},
374 {
"min-cols", required_argument, 0,
'c'},
375 {
"max-cols", required_argument, 0,
'C'},
376 {
"width", required_argument, 0,
'W'},
377 {
"height", required_argument, 0,
'H'},
383 while ((c = getopt_long(argc, argv,
"eshiItnf:r:R:c:C:W:H:", long_opts, &index)) != -1) {
385 if (long_opts[index].flag == 0) {
386 c = long_opts[index].val;
413 frame_count = atoi(optarg);
416 min_row = atoi(optarg);
419 max_row = atoi(optarg);
422 min_col = atoi(optarg);
425 max_col = atoi(optarg);
428 min_col = (FRAME_WIDTH - atoi(optarg)) / 2;
429 max_col = (FRAME_WIDTH + atoi(optarg)) / 2;
432 min_row = (FRAME_HEIGHT - atoi(optarg)) / 2;
433 max_row = (FRAME_HEIGHT + atoi(optarg)) / 2;
444 show_intro = (skip_intro == 0) ? 1 : 0;
450 for (option = 0; option < 256; option++) {
451 if (telnet_options[option]) {
452 send_command(telnet_options[option], option);
456 for (option = 0; option < 256; option++) {
457 if (telnet_willack[option]) {
458 send_command(telnet_willack[option], option);
464 signal(SIGALRM, SIGALRM_handler);
467 if (!setjmp(environment)) {
472 while (!feof(stdin) && done < 2) {
474 unsigned char i = getchar();
475 unsigned char opt = 0;
483 if (sb[0] == TTYPE) {
487 strcpy(term, &sb[2]);
490 else if (sb[0] == NAWS) {
494 terminal_width = (sb[1] << 8) | sb[2];
495 terminal_height = (sb[3] << 8) | sb[4];
501 send_command(NOP, 0);
508 if (!telnet_willack[opt]) {
510 telnet_willack[opt] = WONT;
512 send_command(telnet_willack[opt], opt);
514 if ((i == WILL) && (opt == TTYPE)) {
516 printf(
"%c%c%c%c%c%c", IAC, SB, TTYPE, SEND, IAC, SE);
524 if (!telnet_options[opt]) {
526 telnet_options[opt] = DONT;
528 send_command(telnet_options[opt], opt);
535 memset(sb, 0,
sizeof(sb));
544 }
else if (sb_mode) {
546 if (sb_len <
sizeof(sb) - 1) {
564 char * nterm = getenv(
"TERM");
571 ioctl(0, TIOCGWINSZ, &w);
572 terminal_width = w.ws_col;
573 terminal_height = w.ws_row;
577 for (k = 0; k < strlen(term); ++k) {
578 term[k] = tolower(term[k]);
582 if (strstr(term,
"xterm")) {
584 }
else if (strstr(term,
"toaru")) {
586 }
else if (strstr(term,
"linux")) {
588 }
else if (strstr(term,
"vtnt")) {
590 }
else if (strstr(term,
"cygwin")) {
592 }
else if (strstr(term,
"vt220")) {
594 }
else if (strstr(term,
"fallback")) {
596 }
else if (strstr(term,
"rxvt")) {
598 }
else if (strstr(term,
"vt100") && terminal_width == 40) {
600 }
else if (!strncmp(term,
"st", 2)) {
606 int always_escape = 0;
609 signal(SIGINT, SIGINT_handler);
612 signal(SIGPIPE, SIGPIPE_handler);
616 signal(SIGWINCH, SIGWINCH_handler);
621 colors[
','] =
"\033[48;5;17m";
622 colors[
'.'] =
"\033[48;5;231m";
623 colors[
'\''] =
"\033[48;5;16m";
624 colors[
'@'] =
"\033[48;5;230m";
625 colors[
'$'] =
"\033[48;5;175m";
626 colors[
'-'] =
"\033[48;5;162m";
627 colors[
'>'] =
"\033[48;5;196m";
628 colors[
'&'] =
"\033[48;5;214m";
629 colors[
'+'] =
"\033[48;5;226m";
630 colors[
'#'] =
"\033[48;5;118m";
631 colors[
'='] =
"\033[48;5;33m";
632 colors[
';'] =
"\033[48;5;19m";
633 colors[
'*'] =
"\033[48;5;240m";
634 colors[
'%'] =
"\033[48;5;175m";
637 colors[
','] =
"\033[104m";
638 colors[
'.'] =
"\033[107m";
639 colors[
'\''] =
"\033[40m";
640 colors[
'@'] =
"\033[47m";
641 colors[
'$'] =
"\033[105m";
642 colors[
'-'] =
"\033[101m";
643 colors[
'>'] =
"\033[101m";
644 colors[
'&'] =
"\033[43m";
645 colors[
'+'] =
"\033[103m";
646 colors[
'#'] =
"\033[102m";
647 colors[
'='] =
"\033[104m";
648 colors[
';'] =
"\033[44m";
649 colors[
'*'] =
"\033[100m";
650 colors[
'%'] =
"\033[105m";
653 colors[
','] =
"\033[25;44m";
654 colors[
'.'] =
"\033[5;47m";
655 colors[
'\''] =
"\033[25;40m";
656 colors[
'@'] =
"\033[5;47m";
657 colors[
'$'] =
"\033[5;45m";
658 colors[
'-'] =
"\033[5;41m";
659 colors[
'>'] =
"\033[5;41m";
660 colors[
'&'] =
"\033[25;43m";
661 colors[
'+'] =
"\033[5;43m";
662 colors[
'#'] =
"\033[5;42m";
663 colors[
'='] =
"\033[25;44m";
664 colors[
';'] =
"\033[5;44m";
665 colors[
'*'] =
"\033[5;40m";
666 colors[
'%'] =
"\033[5;45m";
669 colors[
','] =
"\033[0;34;44m";
670 colors[
'.'] =
"\033[1;37;47m";
671 colors[
'\''] =
"\033[0;30;40m";
672 colors[
'@'] =
"\033[1;37;47m";
673 colors[
'$'] =
"\033[1;35;45m";
674 colors[
'-'] =
"\033[1;31;41m";
675 colors[
'>'] =
"\033[1;31;41m";
676 colors[
'&'] =
"\033[0;33;43m";
677 colors[
'+'] =
"\033[1;33;43m";
678 colors[
'#'] =
"\033[1;32;42m";
679 colors[
'='] =
"\033[1;34;44m";
680 colors[
';'] =
"\033[0;34;44m";
681 colors[
'*'] =
"\033[1;30;40m";
682 colors[
'%'] =
"\033[1;35;45m";
686 colors[
','] =
"\033[0;34;44m";
687 colors[
'.'] =
"\033[1;37;47m";
688 colors[
'\''] =
"\033[0;30;40m";
689 colors[
'@'] =
"\033[1;37;47m";
690 colors[
'$'] =
"\033[1;35;45m";
691 colors[
'-'] =
"\033[1;31;41m";
692 colors[
'>'] =
"\033[1;31;41m";
693 colors[
'&'] =
"\033[0;33;43m";
694 colors[
'+'] =
"\033[1;33;43m";
695 colors[
'#'] =
"\033[1;32;42m";
696 colors[
'='] =
"\033[1;34;44m";
697 colors[
';'] =
"\033[0;34;44m";
698 colors[
'*'] =
"\033[1;30;40m";
699 colors[
'%'] =
"\033[1;35;45m";
741 if (min_col == max_col) {
742 min_col = (FRAME_WIDTH - terminal_width/2) / 2;
743 max_col = (FRAME_WIDTH + terminal_width/2) / 2;
744 using_automatic_width = 1;
747 if (min_row == max_row) {
748 min_row = (FRAME_HEIGHT - (terminal_height-1)) / 2;
749 max_row = (FRAME_HEIGHT + (terminal_height-1)) / 2;
750 using_automatic_height = 1;
755 printf(
"\033kNyanyanyanyanyanyanya...\033\134");
756 printf(
"\033]1;Nyanyanyanyanyanyanya...\007");
757 printf(
"\033]2;Nyanyanyanyanyanyanya...\007");
762 printf(
"\033[H\033[2J\033[?25l");
769 unsigned int countdown_clock = 5;
770 for (k = 0; k < countdown_clock; ++k) {
772 printf(
" \033[1mNyancat Telnet Server\033[0m");
774 printf(
" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m");
776 printf(
" If things don't look right, try:");
778 printf(
" TERM=fallback telnet ...");
780 printf(
" Or on Windows:");
782 printf(
" telnet -t vtnt ...");
784 printf(
" Problems? Check the website:");
786 printf(
" \033[1;34mhttp://nyancat.dakko.us\033[0m");
788 printf(
" This is a telnet server, remember your escape keys!");
790 printf(
" \033[1;31m^]quit\033[0m to exit");
792 printf(
" Starting in %d... \n", countdown_clock-k);
805 printf(
"\033[H\033[2J\033[?25l");
810 time_t start, current;
826 for (y = min_row; y < max_row; ++y) {
827 for (x = min_col; x < max_col; ++x) {
829 if (y > 23 && y < 43 && x < 0) {
835 int mod_x = ((-x+2) % 16) / 8;
842 const char *rainbow =
",,>>&&&+++###==;;;,,";
843 color = rainbow[mod_x + y-23];
844 if (color == 0) color =
',';
845 }
else if (x < 0 || y < 0 || y >= FRAME_HEIGHT || x >= FRAME_WIDTH) {
850 color = frames[i][y][x];
854 printf(
"%s", colors[(
int)color]);
856 if (color != last && colors[(
int)color]) {
859 printf(
"%s%s", colors[(
int)color], output);
862 printf(
"%s", output);
872 double diff = difftime(current, start);
874 int nLen = digits((
int)diff);
880 int width = (terminal_width - 29 - nLen) / 2;
892 printf(
"\033[1;37mYou have nyaned for %0.0f seconds!\033[J\033[0m", diff);
898 if (frame_count != 0 && f == frame_count) {