118 lines
3.0 KiB
C
118 lines
3.0 KiB
C
#include<stdio.h>
|
|
#include<stdbool.h>
|
|
#include<stdarg.h>
|
|
#include<string.h>
|
|
#include<errno.h>
|
|
#include<unistd.h>
|
|
#include<termio.h>
|
|
#include<pthread.h>
|
|
|
|
#include "display_bar.h"
|
|
#include "timerhelper.h"
|
|
|
|
enum{
|
|
#ifndef DEFAULT_PROGRESS_BAR_WIDTH
|
|
PROGRESS_BAR_WIDTH = 30,
|
|
#else
|
|
PROGRESS_BAR_WIDTH = DEFAULT_PROGRESS_BAR_WIDTH;
|
|
#endif
|
|
#ifndef DEFAULT_MAX_TERMINAL_ROW
|
|
MAX_TERMINAL_ROW = 1000,
|
|
#else
|
|
MAX_TERMINAL_ROW = MAX_TERMINAL_ROW;
|
|
#endif
|
|
};
|
|
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static raw_progress_bar_t scrolled = 1;
|
|
|
|
void ready_progress_bar(){
|
|
fflush(stdout);
|
|
}
|
|
|
|
void lock_scrolled(){
|
|
pthread_mutex_lock(&mutex);
|
|
}
|
|
void unlock_scrolled(){
|
|
pthread_mutex_unlock(&mutex);
|
|
}
|
|
|
|
void add_scrolled_unlocked(unsigned int i){
|
|
scrolled += i;
|
|
}
|
|
raw_progress_bar_t create_raw_progress_bar(){
|
|
int ret;
|
|
lock_scrolled();
|
|
ret = scrolled;
|
|
//make space for progress bar
|
|
fprintf(stdout,"\n");
|
|
scrolled++;
|
|
unlock_scrolled();
|
|
return ret;
|
|
}
|
|
|
|
void RawDisplayProgressBar(raw_progress_bar_t bar,size_t offset,size_t total,const char * filename){
|
|
char buf[PROGRESS_BAR_WIDTH];
|
|
size_t i;
|
|
double cur_progress = ((double)offset)/(double)total *100.f;
|
|
size_t cur_pos = (cur_progress / 100.0 * PROGRESS_BAR_WIDTH); //must be less than SIZE_MAX. other value is undefined behavior.
|
|
int pos;
|
|
struct winsize wnd_size;
|
|
if (offset == total)
|
|
cur_pos = PROGRESS_BAR_WIDTH;
|
|
for (i = 0; i < PROGRESS_BAR_WIDTH; i++){
|
|
if (i < cur_pos)
|
|
buf[i] = '=';
|
|
else if(i == cur_pos)
|
|
buf[i] = '>';
|
|
else buf[i] = '.';
|
|
}
|
|
lock_scrolled();
|
|
pos = scrolled - bar;
|
|
if (pos > MAX_TERMINAL_ROW) {
|
|
unlock_scrolled();
|
|
return;
|
|
}//optimization.
|
|
//if ioctl failed? what should i do...
|
|
ioctl(STDIN_FILENO,TIOCGWINSZ,(char *)&wnd_size);
|
|
if (wnd_size.ws_row < pos) return;
|
|
fprintf(stdout,"\x1b[%dA[%s]: %.2f%% %s bytes: %ld/%ld \x1b[%dB\r",pos,buf,cur_progress,filename,total,offset,pos);
|
|
fflush(stdout);
|
|
unlock_scrolled();
|
|
}
|
|
bool isatty_file(FILE * file){
|
|
return isatty(fileno(file));
|
|
}
|
|
void myd_perror(const char * msg){
|
|
char buf[1024];
|
|
int err = errno;
|
|
strerror_r(errno,buf,sizeof(buf));
|
|
errno = err;
|
|
if (isatty(STDERR_FILENO)){
|
|
lock_scrolled();
|
|
scrolled++;
|
|
fprintf(stderr,"%s: %s\n",msg,buf);
|
|
unlock_scrolled();
|
|
}
|
|
}
|
|
|
|
void init_progress_bar(progress_bar_t * bar,int update_rate){
|
|
memset(bar,0,sizeof(*bar));
|
|
bar->bar = create_raw_progress_bar();
|
|
bar->update_rate = update_rate;
|
|
}
|
|
|
|
void DisplayProgressBar(progress_bar_t * bar,size_t offset,size_t total,const char * filename, bool sync){
|
|
unsigned diff;
|
|
struct timespec ts,dif;
|
|
clock_gettime(CLOCK_REALTIME,&ts);
|
|
if (!sync){
|
|
dif = timespec_sub(ts,bar->last_update);
|
|
diff = dif.tv_nsec / 1000000 + dif.tv_sec;
|
|
if (diff < bar->update_rate){
|
|
return;
|
|
}
|
|
}
|
|
bar->last_update = ts;
|
|
RawDisplayProgressBar(bar->bar,offset,total,filename);
|
|
} |