snore

sleep with feedback
git clone git://git.bitsmanent.org/snore
Log | Files | Refs | README | LICENSE

snore.c (2848B)


      1 /* See LICENSE for license details. */
      2 #include <errno.h>
      3 #include <limits.h>
      4 #include <stdarg.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <time.h>
      9 
     10 #define BILLION     1000000000.0;
     11 #define TICK        10000
     12 #define CLEAR	    "\33[2K\r"
     13 #define LENGTH(X)   (sizeof X / sizeof X[0])
     14 #define ISCHR(c)    (c >= 'a' && c <= 'z')
     15 
     16 typedef struct symbol_t {
     17 	char sym;
     18 	int mult;
     19 	int precision;
     20 } Symbol;
     21 
     22 void die(const char *errstr, ...);
     23 int sleepu(double usec);
     24 double time_to_sec(char *s);
     25 void time_print(double tm);
     26 
     27 /* must be in ascending order */
     28 static Symbol symbols[] = {
     29 	/* symbol  multiplier  precision */
     30 	{ 's',     1,          3 }, /* first is default (if no suffix) */
     31 	{ 'm',     60,         0 },
     32 	{ 'h',     3600,       0 },
     33 	{ 'd',     86400,      0 }, /* last is default (if no arguments) */
     34 };
     35 
     36 void
     37 die(const char *errstr, ...) {
     38 	va_list ap;
     39 
     40 	va_start(ap, errstr);
     41 	vfprintf(stderr, errstr, ap);
     42 	va_end(ap);
     43 	exit(1);
     44 }
     45 
     46 int
     47 sleepu(double usec) {
     48 	struct timespec req, rem;
     49 	int r;
     50 
     51 	req.tv_sec = 0;
     52 	req.tv_nsec = usec * 1000;
     53 	while((r = nanosleep(&req, &rem)) == -1 && errno == EINTR)
     54 		req = rem;
     55 	return r;
     56 }
     57 
     58 double
     59 time_to_sec(char *s) {
     60 	double calculated = 0.0, part;
     61 	char *parse_end, *string_end;
     62 	int j;
     63 
     64 	string_end = s + strlen(s);
     65 	while(s < string_end) {
     66 		part = strtod(s, &parse_end);
     67 		if(parse_end == s) {
     68 			/* error parsing float */
     69 			return -1;
     70 		}
     71 		s = parse_end;
     72 		if(s < string_end && ISCHR(s[0])) {
     73 			for(j = 0; j < LENGTH(symbols); ++j) {
     74 				if(s[0] == symbols[j].sym) {
     75 					part *= symbols[j].mult;
     76 					if(part >= INT_MAX)
     77 						return -1;
     78 					s++;
     79 					break;
     80 				}
     81 			}
     82 		}
     83 		calculated += part;
     84 	}
     85 	return calculated;
     86 }
     87 
     88 void
     89 time_print(double tm) {
     90 	double piece;
     91 	int i;
     92 
     93 	for(i = LENGTH(symbols) - 1; i >= 0; --i) {
     94 		piece = tm / symbols[i].mult;
     95 		if(!symbols[i].precision)
     96 			piece = (int)piece;
     97 		printf("%.*f%c%s", symbols[i].precision, piece, symbols[i].sym, i ? " " : "");
     98 		tm -= piece * symbols[i].mult;
     99 	}
    100 }
    101 
    102 int
    103 main(int argc, char *argv[]) {
    104 	struct timespec start, current;
    105 	double endtm = 0, tm;
    106 	int i;
    107 
    108 	clock_gettime(CLOCK_REALTIME, &start);
    109 	if(argc == 2 && !strcmp("-v", argv[1]))
    110 		die("snore-"VERSION"\n");
    111 	if(argc == 1) {
    112 		endtm = symbols[LENGTH(symbols) - 1].mult;
    113 	}
    114 	else {
    115 		for(i = 1; i < argc; ++i) {
    116 			tm = time_to_sec(argv[i]);
    117 			if(tm < 0)
    118 				die("%s: wrong time\n", argv[i]);
    119 			endtm += tm;
    120 			if(endtm >= INT_MAX)
    121 				die("%s: time too large\n", argv[0]);
    122 		}
    123 	}
    124 
    125 	for(tm = 0; tm < endtm; ) {
    126 		time_print(tm); /* ascending */
    127 		printf(" | ");
    128 		time_print(endtm - tm); /* descending */
    129 		fflush(stdout);
    130 		sleepu(TICK);
    131 		printf(CLEAR);
    132 		clock_gettime(CLOCK_REALTIME, &current);
    133 		tm = (current.tv_sec - start.tv_sec) + (current.tv_nsec - start.tv_nsec) / BILLION;
    134 	}
    135 	time_print(tm);
    136 	printf("\n");
    137 	return 0;
    138 }