/* * Supercharged multi-baton twirling action. * By Ted Percival, 2006-06-24 * I hereby release this code into the public domain. * */ #include #include #include #include #include #include #define BATON_COUNT 30 #define DEFAULT_ITERATION_TIME 2000 /* number of microseconds between updates */ #define DEFAULT_GLYPHS "_.-`-." typedef unsigned char state_t; enum { MODE_CYCLIC, MODE_SLIDE_LEFT, MODE_SLIDE_RIGHT } g_mode; int g_baton_count; void fill(char* glyphs, char* batons, state_t* states); state_t next(const state_t* states, int baton, int nglyphs); void usage(const char* invoked_as); int main(int argc, char* argv[]) { int i; state_t states[BATON_COUNT]; char batons[BATON_COUNT+1]; struct timeval tvtracker, tvnow; unsigned long timetaken, iteration_time; char* glyphs = DEFAULT_GLYPHS; g_mode = MODE_SLIDE_RIGHT; iteration_time = DEFAULT_ITERATION_TIME; while (-1 != (i = getopt(argc, argv, "clrhd:n:"))) { switch(i) { case 'c': g_mode = MODE_CYCLIC; break; case 'l': g_mode = MODE_SLIDE_LEFT; break; case 'r': g_mode = MODE_SLIDE_RIGHT; break; case 'd': iteration_time = strtoul(optarg, NULL, 10); iteration_time = iteration_time ? iteration_time * 1000 : DEFAULT_ITERATION_TIME; break; case '?': default: case 'h': usage(argv[0]); exit(0); } } if (optind < argc && strlen(argv[optind])) glyphs = argv[optind]; else glyphs = DEFAULT_GLYPHS; batons[BATON_COUNT] = '\0'; /* null-terminate */ fill(glyphs, batons, states); for (i = 0; i < BATON_COUNT; ++i) printf("%c ", batons[i]); if (0 != gettimeofday(&tvtracker, NULL)) exit(1); while (1) { for (i = 0; i < BATON_COUNT; ++i) { if (i == 0) printf("\r"); states[i] = next(states, i, strlen(glyphs)); batons[i] = glyphs[states[i]]; printf("%c ", batons[i]); fflush(stdout); if (0 != gettimeofday(&tvnow, NULL)) exit(1); timetaken = (tvnow.tv_sec - tvtracker.tv_sec) * 1000000; timetaken += tvnow.tv_usec - tvtracker.tv_usec; tvtracker = tvnow; if (iteration_time > timetaken) usleep(iteration_time - timetaken); } } } void fill(char* glyphs, char* batons, state_t* states) { int i; for (i = 0; i < BATON_COUNT; ++i) { states[i] = 0; batons[i] = glyphs[0]; } } state_t next(const state_t* states, int baton, int nglyphs) { state_t newstate; switch(g_mode) { case MODE_CYCLIC: newstate = states[baton] + 1; break; case MODE_SLIDE_LEFT: if (baton == 0) newstate = states[baton]; else newstate = states[baton - 1]; ++newstate; break; case MODE_SLIDE_RIGHT: /* Because there could be any number of batons and they're drawn * left-to-right, this case gets a bit hairy. */ if (baton == BATON_COUNT - 1) newstate = states[baton] + 1; else newstate = states[BATON_COUNT - 1] + BATON_COUNT - baton; break; default: newstate = 0; } newstate %= nglyphs; return newstate; } void usage(const char* invoked_as) { fprintf(stderr, "Usage: %s [-c|-l|-r] [-d delay] [sequence]\n" "\n" "-c\tCyclic\n" "-l\tSlide left\n" "-r\tSlide right\n" "-d\tThe delay (in milliseconds) between each item being drawn. Default 2.\n" "-h\tThis help (usage) message\n" "\n" "sequence is the sequence of characters to draw for the animation.\n" "The default sequence is \"" DEFAULT_GLYPHS "\".\n\n", invoked_as); }