|
#ifndef RLIB_TERMINAL_H
|
|
#define RLIB_TERMINAL_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "rtest.h"
|
|
|
|
char *rfcaptured = NULL;
|
|
|
|
void rfcapture(FILE *f, char *buff, size_t size) {
|
|
rfcaptured = buff;
|
|
setvbuf(f, rfcaptured, _IOFBF, size);
|
|
}
|
|
void rfstopcapture(FILE *f) { setvbuf(f, 0, _IOFBF, 0); }
|
|
|
|
bool _r_disable_stdout_toggle = false;
|
|
|
|
FILE *_r_original_stdout = NULL;
|
|
|
|
bool rr_enable_stdout() {
|
|
if (_r_disable_stdout_toggle)
|
|
return false;
|
|
if (!_r_original_stdout) {
|
|
stdout = fopen("/dev/null", "rb");
|
|
return false;
|
|
}
|
|
if (_r_original_stdout && _r_original_stdout != stdout) {
|
|
fclose(stdout);
|
|
}
|
|
stdout = _r_original_stdout;
|
|
return true;
|
|
}
|
|
bool rr_disable_stdout() {
|
|
if (_r_disable_stdout_toggle) {
|
|
return false;
|
|
}
|
|
if (_r_original_stdout == NULL) {
|
|
_r_original_stdout = stdout;
|
|
}
|
|
if (stdout == _r_original_stdout) {
|
|
stdout = fopen("/dev/null", "rb");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool rr_toggle_stdout() {
|
|
if (!_r_original_stdout) {
|
|
rr_disable_stdout();
|
|
return true;
|
|
} else if (stdout != _r_original_stdout) {
|
|
rr_enable_stdout();
|
|
return true;
|
|
} else {
|
|
rr_disable_stdout();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
typedef struct rprogressbar_t {
|
|
unsigned long current_value;
|
|
unsigned long min_value;
|
|
unsigned long max_value;
|
|
unsigned int length;
|
|
bool changed;
|
|
double percentage;
|
|
unsigned int width;
|
|
unsigned long draws;
|
|
FILE *fout;
|
|
} rprogressbar_t;
|
|
|
|
rprogressbar_t *rprogressbar_new(long min_value, long max_value, unsigned int width, FILE *fout) {
|
|
rprogressbar_t *pbar = (rprogressbar_t *)malloc(sizeof(rprogressbar_t));
|
|
pbar->min_value = min_value;
|
|
pbar->max_value = max_value;
|
|
pbar->current_value = min_value;
|
|
pbar->width = width;
|
|
pbar->draws = 0;
|
|
pbar->length = 0;
|
|
pbar->changed = false;
|
|
pbar->fout = fout ? fout : stdout;
|
|
return pbar;
|
|
}
|
|
|
|
void rprogressbar_free(rprogressbar_t *pbar) { free(pbar); }
|
|
|
|
void rprogressbar_draw(rprogressbar_t *pbar) {
|
|
if (!pbar->changed) {
|
|
return;
|
|
} else {
|
|
pbar->changed = false;
|
|
}
|
|
pbar->draws++;
|
|
char draws_text[22];
|
|
draws_text[0] = 0;
|
|
sprintf(draws_text, "%ld", pbar->draws);
|
|
char *draws_textp = draws_text;
|
|
// bool draws_text_len = strlen(draws_text);
|
|
char bar_begin_char = ' ';
|
|
char bar_progress_char = ' ';
|
|
char bar_empty_char = ' ';
|
|
char bar_end_char = ' ';
|
|
char content[4096] = {0};
|
|
char bar_content[1024];
|
|
char buff[2048] = {0};
|
|
bar_content[0] = '\r';
|
|
bar_content[1] = bar_begin_char;
|
|
unsigned int index = 2;
|
|
for (unsigned long i = 0; i < pbar->length; i++) {
|
|
if (*draws_textp) {
|
|
bar_content[index] = *draws_textp;
|
|
draws_textp++;
|
|
} else {
|
|
bar_content[index] = bar_progress_char;
|
|
}
|
|
index++;
|
|
}
|
|
char infix[] = "\033[0m";
|
|
for (unsigned long i = 0; i < strlen(infix); i++) {
|
|
bar_content[index] = infix[i];
|
|
index++;
|
|
}
|
|
for (unsigned long i = 0; i < pbar->width - pbar->length; i++) {
|
|
bar_content[index] = bar_empty_char;
|
|
index++;
|
|
}
|
|
bar_content[index] = bar_end_char;
|
|
bar_content[index + 1] = '\0';
|
|
sprintf(buff, "\033[43m%s\033[0m \033[33m%.2f%%\033[0m ", bar_content, pbar->percentage * 100);
|
|
strcat(content, buff);
|
|
if (pbar->width == pbar->length) {
|
|
strcat(content, "\r");
|
|
for (unsigned long i = 0; i < pbar->width + 10; i++) {
|
|
strcat(content, " ");
|
|
}
|
|
strcat(content, "\r");
|
|
}
|
|
fprintf(pbar->fout, "%s", content);
|
|
fflush(pbar->fout);
|
|
}
|
|
|
|
bool rprogressbar_update(rprogressbar_t *pbar, unsigned long value) {
|
|
if (value == pbar->current_value) {
|
|
return false;
|
|
}
|
|
pbar->current_value = value;
|
|
pbar->percentage = (double)pbar->current_value / (double)(pbar->max_value - pbar->min_value);
|
|
unsigned long new_length = (unsigned long)(pbar->percentage * pbar->width);
|
|
pbar->changed = new_length != pbar->length;
|
|
if (pbar->changed) {
|
|
pbar->length = new_length;
|
|
rprogressbar_draw(pbar);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
size_t rreadline(char *data, size_t len, bool strip_ln) {
|
|
__attribute__((unused)) char *unused = fgets(data, len, stdin);
|
|
size_t length = strlen(data);
|
|
if (length && strip_ln)
|
|
data[length - 1] = 0;
|
|
return length;
|
|
}
|
|
|
|
void rlib_test_progressbar() {
|
|
rtest_banner("Progress bar");
|
|
rprogressbar_t *pbar = rprogressbar_new(0, 1000, 10, stderr);
|
|
rprogressbar_draw(pbar);
|
|
// No draws executed, nothing to show
|
|
rassert(pbar->draws == 0);
|
|
rprogressbar_update(pbar, 500);
|
|
rassert(pbar->percentage == 0.5);
|
|
rprogressbar_update(pbar, 500);
|
|
rprogressbar_update(pbar, 501);
|
|
rprogressbar_update(pbar, 502);
|
|
// Should only have drawn one time since value did change, but percentage
|
|
// did not
|
|
rassert(pbar->draws == 1);
|
|
// Changed is false because update function calls draw
|
|
rassert(pbar->changed == false);
|
|
rprogressbar_update(pbar, 777);
|
|
rassert(pbar->percentage == 0.777);
|
|
rprogressbar_update(pbar, 1000);
|
|
rassert(pbar->percentage == 1);
|
|
}
|
|
|
|
#endif |