File:  [DragonFly] / src / games / grdc / grdc.c
Revision 1.4: download - view: text, annotated - select for diffs
Thu Mar 25 23:55:13 2004 UTC (10 years, 6 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Four new features and a bugfix.

- Center the clock on the user's terminal.
- Check that the terminal is sufficiently large to fully display the
  clock (about 61x9.)  If not, exit immediately with an error.
- Introduce a short delay in the scrolling when -s is given, so that
  it can be better appreciated on syscons(4) and local xterm(1).  The
  default delay is 120 milliseconds.
- Add a new option, -d, to allow changing the scroll delay to any
  duration from 0 to 5000 milliseconds.  The -d option implies -s.
- Make it so that, when the optional argument is omitted, the clock
  really does run forever.  (Before this, it would have stopped after
  about 65536 seconds due to wraparound.)

    1: /*
    2:  * Grand digital clock for curses compatible terminals
    3:  * Usage: grdc [-s] [-d msecs] [n]   -- run for n seconds (default infinity)
    4:  * Flags:	-s: scroll (default scroll duration 120msec)
    5:  *	-d msecs: specify scroll duration (implies -s)
    6:  *
    7:  * modified 10-18-89 for curses (jrl)
    8:  * 10-18-89 added signal handling
    9:  * 03-23-04 added centering, scroll delay (cap)
   10:  *
   11:  * $FreeBSD: src/games/grdc/grdc.c,v 1.8.2.1 2001/10/02 11:51:49 ru Exp $
   12:  * $DragonFly: src/games/grdc/grdc.c,v 1.4 2004/03/25 23:55:13 cpressey Exp $
   13:  */
   14: 
   15: #include <err.h>
   16: #include <time.h>
   17: #include <signal.h>
   18: #include <ncurses.h>
   19: #include <stdlib.h>
   20: #ifndef NONPOSIX
   21: #include <unistd.h>
   22: #endif
   23: #include <time.h>
   24: 
   25: #define XLENGTH 58
   26: #define YDEPTH  7
   27: 
   28: time_t now;
   29: struct tm *tm;
   30: 
   31: short disp[11] = {
   32: 	075557, 011111, 071747, 071717, 055711,
   33: 	074717, 074757, 071111, 075757, 075717, 002020
   34: };
   35: long old[6], next[6], new[6], mask;
   36: 
   37: volatile sig_atomic_t sigtermed;
   38: 
   39: int hascolor = 0;
   40: long int scroll_msecs = 120;
   41: int xbase, ybase, xmax, ymax;
   42: 
   43: static void set(int, int);
   44: static void standt(int);
   45: static void sighndl(int);
   46: static void usage(void);
   47: static void draw_row(int, int);
   48: static void snooze(long int);
   49: 
   50: void sighndl(int signo)
   51: {
   52: 	sigtermed = signo;
   53: }
   54: 
   55: int
   56: main(int argc, char **argv)
   57: {
   58: 	int i, s, k;
   59: 	int n;
   60: 	int ch;
   61: 	int scrol;
   62: 	int forever = 1;
   63: 
   64: 	scrol = 0;
   65: 
   66: 	while ((ch = getopt(argc, argv, "d:s")) != -1)
   67: 		switch (ch) {
   68: 		case 'd':
   69: 			scroll_msecs = atol(optarg);
   70: 			if (scroll_msecs < 0)
   71: 				errx(1, "scroll duration may not be negative");
   72: 			/* FALLTHROUGH */
   73: 		case 's':
   74: 			scrol = 1;
   75: 			break;
   76: 		case '?':
   77: 		default:
   78: 			usage();
   79: 			/* NOTREACHED */
   80: 		}
   81: 	argc -= optind;
   82: 	argv += optind;
   83: 
   84: 	if (argc > 1) {
   85: 		usage();
   86: 		/* NOTREACHED */
   87: 	}
   88: 
   89: 	if (argc > 0) {
   90: 		n = atoi(*argv);
   91: 		forever = 0;
   92: 	}
   93: 
   94: 	initscr();
   95: 
   96: 	getmaxyx(stdscr, ymax, xmax);
   97: 	if (ymax < YDEPTH + 2 || xmax < XLENGTH + 4) {
   98: 		endwin();
   99: 		errx(1, "terminal too small");
  100: 	}
  101: 	xbase = (xmax - XLENGTH) / 2 + 2;
  102: 	ybase = (ymax - YDEPTH) / 2 + 1;
  103: 
  104: 	signal(SIGINT, sighndl);
  105: 	signal(SIGTERM, sighndl);
  106: 	signal(SIGHUP, sighndl);
  107: 
  108: 	cbreak();
  109: 	noecho();
  110: 	curs_set(0);
  111: 
  112: 	hascolor = has_colors();
  113: 
  114: 	if (hascolor) {
  115: 		start_color();
  116: 		init_pair(1, COLOR_BLACK, COLOR_RED);
  117: 		init_pair(2, COLOR_RED, COLOR_BLACK);
  118: 		init_pair(3, COLOR_WHITE, COLOR_BLACK);
  119: 		attrset(COLOR_PAIR(2));
  120: 	}
  121: 
  122: 	clear();
  123: 	refresh();
  124: 
  125: 	if (hascolor) {
  126: 		attrset(COLOR_PAIR(3));
  127: 
  128: 		mvaddch(ybase - 2, xbase - 3, ACS_ULCORNER);
  129: 		hline(ACS_HLINE, XLENGTH);
  130: 		mvaddch(ybase - 2, xbase - 2 + XLENGTH, ACS_URCORNER);
  131: 
  132: 		mvaddch(ybase + YDEPTH - 1, xbase - 3, ACS_LLCORNER);
  133: 		hline(ACS_HLINE, XLENGTH);
  134: 		mvaddch(ybase + YDEPTH - 1, xbase - 2 + XLENGTH, ACS_LRCORNER);
  135: 
  136: 		move(ybase - 1, xbase - 3);
  137: 		vline(ACS_VLINE, YDEPTH);
  138: 
  139: 		move(ybase - 1, xbase - 2 + XLENGTH);
  140: 		vline(ACS_VLINE, YDEPTH);
  141: 
  142: 		attrset(COLOR_PAIR(2));
  143: 		refresh();
  144: 	}
  145: 	do {
  146: 		mask = 0;
  147: 		time(&now);
  148: 		tm = localtime(&now);
  149: 		set(tm->tm_sec % 10, 0);
  150: 		set(tm->tm_sec / 10, 4);
  151: 		set(tm->tm_min % 10, 10);
  152: 		set(tm->tm_min / 10, 14);
  153: 		set(tm->tm_hour % 10, 20);
  154: 		set(tm->tm_hour / 10, 24);
  155: 		set(10, 7);
  156: 		set(10, 17);
  157: 		for(k = 0; k < 6; k++) {
  158: 			if (scrol) {
  159: 				snooze(scroll_msecs / 6);
  160: 				for(i = 0; i < 5; i++)
  161: 					new[i] = (new[i] & ~mask) |
  162: 						 (new[i+1] & mask);
  163: 				new[5] = (new[5] & ~mask) | (next[k] & mask);
  164: 			} else
  165: 				new[k] = (new[k] & ~mask) | (next[k] & mask);
  166: 			next[k] = 0;
  167: 			for (s = 1; s >= 0; s--) {
  168: 				standt(s);
  169: 				for (i = 0; i < 6; i++) {
  170: 					draw_row(i, s);
  171: 				}
  172: 				if (!s) {
  173: 					move(ybase, 0);
  174: 					refresh();
  175: 				}
  176: 			}
  177: 		}
  178: 		move(ybase, 0);
  179: 		refresh();
  180: 		snooze(1000 - (scrol ? scroll_msecs : 0));
  181: 	} while (forever ? 1 : --n);
  182: 	standend();
  183: 	clear();
  184: 	refresh();
  185: 	endwin();
  186: 	return(0);
  187: }
  188: 
  189: void
  190: snooze(long int msecs)
  191: {
  192: 	struct timespec ts;
  193:   
  194: 	ts.tv_sec = 0;
  195: 	ts.tv_nsec = 1000000 * msecs;
  196: 
  197: 	nanosleep(&ts, NULL);
  198: 
  199: 	if (sigtermed) {
  200: 		standend();
  201: 		clear();
  202: 		refresh();
  203: 		endwin();
  204: 		errx(1, "terminated by signal %d", (int)sigtermed);
  205: 	}
  206: }
  207: 
  208: void
  209: draw_row(int i, int s)
  210: {
  211: 	long a, t;
  212: 	int j;
  213: 
  214: 	if ((a = (new[i] ^ old[i]) & (s ? new : old)[i]) != 0) {
  215: 		for (j = 0, t = 1 << 26; t; t >>= 1, j++) {
  216: 			if (a & t) {
  217: 				if (!(a & (t << 1))) {
  218: 					move(ybase + i, xbase + 2 * j);
  219: 				}
  220: 				addstr("  ");
  221: 			}
  222: 		}
  223: 	}
  224: 	if (!s) {
  225: 		old[i] = new[i];
  226: 	}
  227: }
  228: 
  229: void
  230: set(int t, int n)
  231: {
  232: 	int i, m;
  233: 
  234: 	m = 7 << n;
  235: 	for (i = 0; i < 5; i++) {
  236: 		next[i] |= ((disp[t] >> (4 - i) * 3) & 07) << n;
  237: 		mask |= (next[i] ^ old[i]) & m;
  238: 	}
  239: 	if (mask & m)
  240: 		mask |= m;
  241: }
  242: 
  243: void
  244: standt(int on)
  245: {
  246: 	if (on) {
  247: 		if (hascolor) {
  248: 			attron(COLOR_PAIR(1));
  249: 		} else {
  250: 			attron(A_STANDOUT);
  251: 		}
  252: 	} else {
  253: 		if (hascolor) {
  254: 			attron(COLOR_PAIR(2));
  255: 		} else {
  256: 			attroff(A_STANDOUT);
  257: 		}
  258: 	}
  259: }
  260: 
  261: void
  262: usage(void)
  263: {
  264: 	fprintf(stderr, "usage: grdc [-s] [-d msecs] [n]\n");
  265: 	exit(1);
  266: }