diff options
author | lns <matzeton@googlemail.com> | 2019-11-17 20:58:23 +0100 |
---|---|---|
committer | lns <matzeton@googlemail.com> | 2019-11-17 20:58:23 +0100 |
commit | 2f5fd62f43cd0ab98b6d1650d11cb8c80b520c53 (patch) | |
tree | 26bf61627c381a6d4ff1b52570ff5e7b3ebefa7c | |
parent | ba18c15d4173e204fde6eaac9f287a2adf6bea91 (diff) |
simple af terminal progressbar watches position of a fd of a file
-rw-r--r-- | progressbar.c | 156 |
1 files changed, 154 insertions, 2 deletions
diff --git a/progressbar.c b/progressbar.c index 6209c68..a1fc173 100644 --- a/progressbar.c +++ b/progressbar.c @@ -2,12 +2,14 @@ #include <dirent.h> #include <stdio.h> #include <stdlib.h> +#include <stdarg.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdbool.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/ioctl.h> struct filtered_dir_entries { @@ -111,6 +113,12 @@ struct file_info { int proc_fdinfo_fd; long int current_position; long int max_size; + struct { + struct winsize dimensions; + char output[BUFSIZ]; + size_t printable_chars; + size_t unprintable_chars; + } terminal; }; static int setup_file_info(struct file_info * const finfo, int proc_fd_fd, int proc_fdinfo_fd) @@ -156,6 +164,144 @@ static int read_and_parse_fd_pos(struct file_info * const finfo) return 0; } +static int reset_terminal_output(struct file_info * const finfo) +{ + finfo->terminal.output[0] = '\r'; + finfo->terminal.output[1] = '\0'; + finfo->terminal.unprintable_chars = 1; + finfo->terminal.printable_chars = 0; + return ioctl(0, TIOCGWINSZ, &finfo->terminal.dimensions); +} + +static size_t remaining_printable_chars(struct file_info * const finfo) +{ + return finfo->terminal.dimensions.ws_col - + strnlen(finfo->terminal.output, finfo->terminal.printable_chars); +} + +static int vadd_printable_buf(struct file_info * const finfo, const char * format, va_list ap) +{ + char tmp_buf[BUFSIZ]; + int snprintf_retval; + size_t remaining_len; + + remaining_len = remaining_printable_chars(finfo); + if (!remaining_len) { + return -1; + } + + snprintf_retval = vsnprintf(tmp_buf, sizeof tmp_buf, format, ap); + if (snprintf_retval > 0) { + if (snprintf_retval > remaining_len) { + return -1; + } + memcpy(finfo->terminal.output + finfo->terminal.printable_chars + + finfo->terminal.unprintable_chars, + tmp_buf, snprintf_retval); + finfo->terminal.printable_chars += snprintf_retval; + } + return snprintf_retval; +} + +static int add_printable_buf(struct file_info * const finfo, const char * format, ...) +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = vadd_printable_buf(finfo, format, ap); + va_end(ap); + return ret; +} + +enum unit_prefix { + NONE, KILO, MEGA, GIGA +}; + +static enum unit_prefix choose_appropriate_unit(long int bytes, float *result) +{ + float pretty_bytes; + + pretty_bytes = (float)bytes / (1024.0f * 1024.0f * 1024.0f); + if (pretty_bytes >= 1.0f) { + *result = pretty_bytes; + return GIGA; + } + + pretty_bytes = (float)bytes / (1024.0f * 1024.0f); + if (pretty_bytes >= 1.0f) { + *result = pretty_bytes; + return MEGA; + } + + pretty_bytes = (float)bytes / 1024.0f; + if (pretty_bytes >= 1.0f) { + *result = pretty_bytes; + return KILO; + } + + return NONE; +} + +static void prettify_with_units(long int bytes, char * buf, size_t siz) +{ + float unit_bytes = 0.0f; + enum unit_prefix up = choose_appropriate_unit(bytes, &unit_bytes); + + switch (up) { + case KILO: + snprintf(buf, siz, "%.2fK", unit_bytes); + break; + case MEGA: + snprintf(buf, siz, "%.2fM", unit_bytes); + break; + case GIGA: + snprintf(buf, siz, "%.2fG", unit_bytes); + break; + + case NONE: + default: + snprintf(buf, siz, "%ld", bytes); + break; + } +} + +static void show_positions(struct file_info * const finfo) +{ + char curpos[66]; + char maxpos[66]; + + prettify_with_units(finfo->current_position, curpos, sizeof curpos); + prettify_with_units(finfo->max_size, maxpos, sizeof maxpos); + + add_printable_buf(finfo, "[%s..%s]", curpos, maxpos); +} + +static void show_progressbar(struct file_info * const finfo) +{ + char buf[BUFSIZ]; + size_t remaining_len; + + remaining_len = remaining_printable_chars(finfo); + if (remaining_len < 8 || remaining_len >= sizeof buf) { + return; + } + + float progress = (float)finfo->current_position / finfo->max_size; + add_printable_buf(finfo, "[%.2f%%]", progress * 100.0f); + + remaining_len = remaining_printable_chars(finfo); + if (remaining_len < 3 || remaining_len >= sizeof buf) { + return; + } + + float printable_progress = progress * remaining_len; + memset(buf, '-', remaining_len - 2); + memset(buf, '#', (size_t)printable_progress); + buf[remaining_len - 2] = '\0'; + add_printable_buf(finfo, "[%s]", buf); +} + int main(int argc, char **argv) { struct filtered_dir_entries proc_pid_entries = {}; @@ -231,14 +377,20 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - struct file_info finfo; + struct file_info finfo = {}; if (setup_file_info(&finfo, proc_fd_fd, proc_fdinfo_fd)) { exit(EXIT_FAILURE); } close(proc_fd_fd); while (!read_and_parse_fd_pos(&finfo)) { - printf("\r[%ld..%ld] ", finfo.current_position, finfo.max_size); + if (reset_terminal_output(&finfo) < 0) { + break; + } + show_positions(&finfo); + show_progressbar(&finfo); + + printf("%s", finfo.terminal.output); fflush(stdout); sleep(1); } |