-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathux.c
146 lines (114 loc) · 2.94 KB
/
ux.c
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
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include "qdl.h"
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define UX_PROGRESS_REFRESH_RATE 10
#define UX_PROGRESS_SIZE_MAX 120
static const char * const progress_hashes = "########################################################################################################################";
static const char * const progress_dashes = "------------------------------------------------------------------------------------------------------------------------";
static unsigned int ux_width;
static unsigned int ux_cur_line_length;
/*
* Levels of output:
*
* error: used to signal errors to the user
* info: used to inform the user about progress
* logs: log prints from the device
* debug: protocol logs
*/
/* Clear ux_cur_line_length characters of the progress bar from the screen */
static void ux_clear_line(void)
{
if (!ux_cur_line_length)
return;
printf("%*s\r", ux_cur_line_length, "");
fflush(stdout);
ux_cur_line_length = 0;
}
void ux_init(void)
{
struct winsize w;
int ret;
ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
if (!ret)
ux_width = MIN(w.ws_col, UX_PROGRESS_SIZE_MAX);
}
void ux_err(const char *fmt, ...)
{
va_list ap;
ux_clear_line();
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
}
void ux_info(const char *fmt, ...)
{
va_list ap;
ux_clear_line();
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fflush(stdout);
}
void ux_log(const char *fmt, ...)
{
va_list ap;
if (!qdl_debug)
return;
ux_clear_line();
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fflush(stdout);
}
void ux_debug(const char *fmt, ...)
{
va_list ap;
if (!qdl_debug)
return;
ux_clear_line();
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fflush(stdout);
}
void ux_progress(const char *fmt, unsigned int value, unsigned int max, ...)
{
static struct timeval last_progress_update;
unsigned long elapsed_us;
unsigned int bar_length;
unsigned int bars;
unsigned int dashes;
struct timeval now;
char task_name[32];
float percent;
va_list ap;
/* Don't print progress is window is too narrow, or if stdout is redirected */
if (ux_width < 30)
return;
/* Avoid updating the console more than UX_PROGRESS_REFRESH_RATE per second */
if (last_progress_update.tv_sec) {
gettimeofday(&now, NULL);
elapsed_us = (now.tv_sec - last_progress_update.tv_sec) * 1000000 +
(now.tv_usec - last_progress_update.tv_usec);
if (elapsed_us < (1000000 / UX_PROGRESS_REFRESH_RATE))
return;
}
va_start(ap, max);
vsnprintf(task_name, sizeof(task_name), fmt, ap);
va_end(ap);
bar_length = ux_width - (20 + 4 + 6);
percent = (float)value / max;
bars = percent * bar_length;
dashes = bar_length - bars;
printf("%-20.20s [%.*s%.*s] %1.2f%%%n\r", task_name,
bars, progress_hashes,
dashes, progress_dashes,
percent * 100,
&ux_cur_line_length);
fflush(stdout);
gettimeofday(&last_progress_update, NULL);
}