gdc.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /****************************************************************************
  2. * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. *
  3. * *
  4. * Permission is hereby granted, free of charge, to any person obtaining a *
  5. * copy of this software and associated documentation files (the *
  6. * "Software"), to deal in the Software without restriction, including *
  7. * without limitation the rights to use, copy, modify, merge, publish, *
  8. * distribute, distribute with modifications, sublicense, and/or sell *
  9. * copies of the Software, and to permit persons to whom the Software is *
  10. * furnished to do so, subject to the following conditions: *
  11. * *
  12. * The above copyright notice and this permission notice shall be included *
  13. * in all copies or substantial portions of the Software. *
  14. * *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
  16. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
  18. * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
  19. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
  20. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
  21. * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
  22. * *
  23. * Except as contained in this notice, the name(s) of the above copyright *
  24. * holders shall not be used in advertising or otherwise to promote the *
  25. * sale, use or other dealings in this Software without prior written *
  26. * authorization. *
  27. ****************************************************************************/
  28. /*
  29. * Grand digital clock for curses compatible terminals
  30. * Usage: gdc [-s] [n] -- run for n seconds (default infinity)
  31. * Flags: -s: scroll
  32. *
  33. * modified 10-18-89 for curses (jrl)
  34. * 10-18-89 added signal handling
  35. *
  36. * $Id: gdc.c,v 1.31 2008/08/03 23:58:42 tom Exp $
  37. */
  38. #include <test.priv.h>
  39. #include <time.h>
  40. #define YBASE 10
  41. #define XBASE 10
  42. #define XLENGTH 54
  43. #define YDEPTH 5
  44. #define PAIR_DIGITS 1
  45. #define PAIR_OTHERS 2
  46. #define PAIR_FRAMES 3
  47. static short disp[11] =
  48. {
  49. 075557, 011111, 071747, 071717, 055711,
  50. 074717, 074757, 071111, 075757, 075717, 002020
  51. };
  52. static long older[6], next[6], newer[6], mask;
  53. static int sigtermed = 0;
  54. static bool redirected = FALSE;
  55. static bool hascolor = FALSE;
  56. static RETSIGTYPE
  57. sighndl(int signo)
  58. {
  59. signal(signo, sighndl);
  60. sigtermed = signo;
  61. if (redirected) {
  62. endwin();
  63. ExitProgram(EXIT_FAILURE);
  64. }
  65. }
  66. static void
  67. drawbox(bool scrolling)
  68. {
  69. chtype bottom[XLENGTH + 1];
  70. int n;
  71. if (hascolor)
  72. attrset(COLOR_PAIR(PAIR_FRAMES));
  73. mvaddch(YBASE - 1, XBASE - 1, ACS_ULCORNER);
  74. hline(ACS_HLINE, XLENGTH);
  75. mvaddch(YBASE - 1, XBASE + XLENGTH, ACS_URCORNER);
  76. mvaddch(YBASE + YDEPTH, XBASE - 1, ACS_LLCORNER);
  77. if ((mvinchnstr(YBASE + YDEPTH, XBASE, bottom, XLENGTH)) != ERR) {
  78. for (n = 0; n < XLENGTH; n++) {
  79. if (!scrolling)
  80. bottom[n] &= ~A_COLOR;
  81. bottom[n] = ACS_HLINE | (bottom[n] & (A_ATTRIBUTES | A_COLOR));
  82. }
  83. mvaddchnstr(YBASE + YDEPTH, XBASE, bottom, XLENGTH);
  84. }
  85. mvaddch(YBASE + YDEPTH, XBASE + XLENGTH, ACS_LRCORNER);
  86. move(YBASE, XBASE - 1);
  87. vline(ACS_VLINE, YDEPTH);
  88. move(YBASE, XBASE + XLENGTH);
  89. vline(ACS_VLINE, YDEPTH);
  90. if (hascolor)
  91. attrset(COLOR_PAIR(PAIR_OTHERS));
  92. }
  93. static void
  94. standt(int on)
  95. {
  96. if (on) {
  97. if (hascolor) {
  98. attron(COLOR_PAIR(PAIR_DIGITS));
  99. } else {
  100. attron(A_STANDOUT);
  101. }
  102. } else {
  103. if (hascolor) {
  104. attron(COLOR_PAIR(PAIR_OTHERS));
  105. } else {
  106. attroff(A_STANDOUT);
  107. }
  108. }
  109. }
  110. static void
  111. set(int t, int n)
  112. {
  113. int i, m;
  114. m = 7 << n;
  115. for (i = 0; i < 5; i++) {
  116. next[i] |= ((disp[t] >> ((4 - i) * 3)) & 07) << n;
  117. mask |= (next[i] ^ older[i]) & m;
  118. }
  119. if (mask & m)
  120. mask |= m;
  121. }
  122. static void
  123. usage(void)
  124. {
  125. static const char *msg[] =
  126. {
  127. "Usage: gdc [options] [count]"
  128. ,""
  129. ,"Options:"
  130. ," -n redirect input to /dev/null"
  131. ," -s scroll each number into place, rather than flipping"
  132. ,""
  133. ,"If you specify a count, gdc runs for that number of seconds"
  134. };
  135. unsigned j;
  136. for (j = 0; j < SIZEOF(msg); j++)
  137. fprintf(stderr, "%s\n", msg[j]);
  138. ExitProgram(EXIT_FAILURE);
  139. }
  140. int
  141. main(int argc, char *argv[])
  142. {
  143. time_t now;
  144. struct tm *tm;
  145. long t, a;
  146. int i, j, s, k;
  147. int count = 0;
  148. FILE *ofp = stdout;
  149. FILE *ifp = stdin;
  150. bool scrol = FALSE;
  151. setlocale(LC_ALL, "");
  152. CATCHALL(sighndl);
  153. while ((k = getopt(argc, argv, "sn")) != -1) {
  154. switch (k) {
  155. case 's':
  156. scrol = TRUE;
  157. break;
  158. case 'n':
  159. ifp = fopen("/dev/null", "r");
  160. redirected = TRUE;
  161. break;
  162. default:
  163. usage();
  164. }
  165. }
  166. if (optind < argc) {
  167. count = atoi(argv[optind++]);
  168. assert(count >= 0);
  169. }
  170. if (optind < argc)
  171. usage();
  172. if (redirected) {
  173. char *name = getenv("TERM");
  174. if (name == 0
  175. || newterm(name, ofp, ifp) == 0) {
  176. fprintf(stderr, "cannot open terminal\n");
  177. ExitProgram(EXIT_FAILURE);
  178. }
  179. } else {
  180. initscr();
  181. }
  182. cbreak();
  183. noecho();
  184. nodelay(stdscr, 1);
  185. curs_set(0);
  186. hascolor = has_colors();
  187. if (hascolor) {
  188. int bg = COLOR_BLACK;
  189. start_color();
  190. #if HAVE_USE_DEFAULT_COLORS
  191. if (use_default_colors() == OK)
  192. bg = -1;
  193. #endif
  194. init_pair(PAIR_DIGITS, COLOR_BLACK, COLOR_RED);
  195. init_pair(PAIR_OTHERS, COLOR_RED, bg);
  196. init_pair(PAIR_FRAMES, COLOR_WHITE, bg);
  197. attrset(COLOR_PAIR(PAIR_OTHERS));
  198. }
  199. restart:
  200. for (j = 0; j < 5; j++)
  201. older[j] = newer[j] = next[j] = 0;
  202. clear();
  203. drawbox(FALSE);
  204. do {
  205. char buf[30];
  206. time(&now);
  207. tm = localtime(&now);
  208. mask = 0;
  209. set(tm->tm_sec % 10, 0);
  210. set(tm->tm_sec / 10, 4);
  211. set(tm->tm_min % 10, 10);
  212. set(tm->tm_min / 10, 14);
  213. set(tm->tm_hour % 10, 20);
  214. set(tm->tm_hour / 10, 24);
  215. set(10, 7);
  216. set(10, 17);
  217. for (k = 0; k < 6; k++) {
  218. if (scrol) {
  219. for (i = 0; i < 5; i++)
  220. newer[i] = (newer[i] & ~mask) | (newer[i + 1] & mask);
  221. newer[5] = (newer[5] & ~mask) | (next[k] & mask);
  222. } else
  223. newer[k] = (newer[k] & ~mask) | (next[k] & mask);
  224. next[k] = 0;
  225. for (s = 1; s >= 0; s--) {
  226. standt(s);
  227. for (i = 0; i < 6; i++) {
  228. if ((a = (newer[i] ^ older[i]) & (s ? newer : older)[i])
  229. != 0) {
  230. for (j = 0, t = 1 << 26; t; t >>= 1, j++) {
  231. if (a & t) {
  232. if (!(a & (t << 1))) {
  233. move(YBASE + i, XBASE + 2 * j);
  234. }
  235. addstr(" ");
  236. }
  237. }
  238. }
  239. if (!s) {
  240. older[i] = newer[i];
  241. }
  242. }
  243. if (!s) {
  244. if (scrol)
  245. drawbox(TRUE);
  246. refresh();
  247. /*
  248. * If we're scrolling, space out the refreshes to fake
  249. * movement. That's 7 frames, or 6 intervals, which would
  250. * be 166 msec if we spread it out over a second. It looks
  251. * better (but will work on a slow terminal, e.g., less
  252. * than 9600bd) to squeeze that into a half-second, and use
  253. * half of 170 msec to ensure that the program doesn't eat
  254. * a lot of time when asking what time it is, at the top of
  255. * this loop -T.Dickey
  256. */
  257. if (scrol)
  258. napms(85);
  259. }
  260. }
  261. }
  262. /* this depends on the detailed format of ctime(3) */
  263. (void) strcpy(buf, ctime(&now));
  264. (void) strcpy(buf + 10, buf + 19);
  265. mvaddstr(16, 30, buf);
  266. move(6, 0);
  267. drawbox(FALSE);
  268. refresh();
  269. /*
  270. * If we're not scrolling, wait 1000 msec (1 sec). Use napms() rather
  271. * than sleep() because the latter does odd things on some systems,
  272. * e.g., suspending output as well.
  273. */
  274. if (scrol)
  275. napms(500);
  276. else
  277. napms(1000);
  278. /*
  279. * This is a safe way to check if we're interrupted - making the signal
  280. * handler set a flag that we can check. Since we're running
  281. * nodelay(), the wgetch() call returns immediately, and in particular
  282. * will return an error if interrupted. This works only if we can
  283. * read from the input, of course.
  284. */
  285. switch (wgetch(stdscr)) {
  286. case 'q':
  287. count = 1;
  288. break;
  289. case 's':
  290. nodelay(stdscr, FALSE);
  291. break;
  292. case ' ':
  293. nodelay(stdscr, TRUE);
  294. break;
  295. #ifdef KEY_RESIZE
  296. case KEY_RESIZE:
  297. #endif
  298. case '?':
  299. goto restart;
  300. case ERR:
  301. if (sigtermed) {
  302. standend();
  303. endwin();
  304. fprintf(stderr, "gdc terminated by signal %d\n", sigtermed);
  305. ExitProgram(EXIT_FAILURE);
  306. }
  307. /* FALLTHRU */
  308. default:
  309. continue;
  310. }
  311. } while (--count);
  312. standend();
  313. endwin();
  314. ExitProgram(EXIT_SUCCESS);
  315. }