1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
/*
* Simple progress bar implementation in C.
*
*
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>
#include <progress.h>
/* Specify how wide the progress bar should be. */
#define PROGRESS_BAR_WIDTH 50
/*
* Alternative progress bar where each block grows
* vertically instead of horizontally.
*/
/* #define VERTICAL */
/* Various unicode character definitions. */
#define BAR_START "\u2595"
#define BAR_STOP "\u258F"
#define PROGRESS_BLOCK "\u2588"
#ifdef VERTICAL
static const char * subprogress_blocks[] = { " ",
"\u2581",
"\u2582",
"\u2583",
"\u2584",
"\u2585",
"\u2586",
"\u2587"
};
#else
static const char * subprogress_blocks[] = { " ",
"\u258F",
"\u258E",
"\u258D",
"\u258C",
"\u258B",
"\u258A",
"\u2589"
};
#endif
#define NUM_SUBBLOCKS (sizeof(subprogress_blocks) / sizeof(subprogress_blocks[0]))
/* Get file size */
off_t get_file_size(const char *filename)
{
struct stat stat_buf;
off_t rc = stat(filename, &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
/* Helper function to get the current time in usecs past the epoch. */
uint64_t get_timestamp(void) {
struct timeval tv;
uint64_t stamp = 0;
gettimeofday(&tv, NULL);
stamp = tv.tv_sec * 1000000 + tv.tv_usec;
return stamp;
}
/* Helper function to print a usecs value as a duration. */
static void print_timedelta(uint64_t delta) {
uint64_t delta_secs = delta / 1000000;
uint64_t hours = delta_secs / 3600;
uint64_t minutes = (delta_secs - hours * 3600) / 60;
uint64_t seconds = (delta_secs - hours * 3600 - minutes * 60);
uint64_t mseconds = (delta / 100000) % 10;
if (hours) {
fprintf(stderr,"%lluh %llum %llus ", hours, minutes, seconds);
}
else if (minutes) {
fprintf(stderr,"%llum %02llus ", minutes, seconds);
}
else {
fprintf(stderr,"%llu.%llus ", seconds, mseconds);
}
}
/*
* Main interface function for updating the progress bar. This
* function doesn't print a newline, so you can call it iteratively
* and have the progress bar grow across the screen. The caller can
* print a newline when the're ready to go to a new line.
*
* percentage: a double between 0.0 and 100.0 indicating the progress.
* start: usecs timestamp for when the task started, for calculating
* remaining time.
*/
void print_progress(double percentage, uint64_t start) {
size_t i;
size_t total_blocks = PROGRESS_BAR_WIDTH * NUM_SUBBLOCKS;
size_t done = round(percentage / 100.0 * total_blocks);
size_t num_blocks = done / NUM_SUBBLOCKS;
size_t num_subblocks = done % NUM_SUBBLOCKS;
uint64_t now = get_timestamp();
uint64_t elapsed = now - start;
uint64_t estimated_total = elapsed / (percentage / 100.0);
uint64_t remaining = estimated_total - elapsed;
if (percentage < 0.0 || percentage > 100.0) return;
fprintf(stderr," Progress: %6.2f%% \t%s", percentage, BAR_START);
for (i = 0; i < num_blocks; i++) {
fprintf(stderr,"%s", PROGRESS_BLOCK);
}
if (num_subblocks) {
fprintf(stderr,"%s", subprogress_blocks[num_subblocks]);
i++;
}
for (; i < PROGRESS_BAR_WIDTH; i++) {
fprintf(stderr," ");
}
fprintf(stderr,"%s\t", BAR_STOP);
if (percentage < 100.0) {
fprintf(stderr,"ETA: ");
print_timedelta(remaining);
}
else {
fprintf(stderr," ");
}
fprintf(stderr,"\r");
fflush(stdout);
}
#ifdef WITH_MAIN
int main(int argc, char **argv) {
int i;
double amount = 0.0;
uint64_t start = get_timestamp();
for (i = 0; i < 10000; i++) {
amount += 0.01;
print_progress(amount, start);
usleep(2000000 / (i + 1));
}
fprintf(stderr,"\n");
}
#endif
|