};
struct cli_progressbar;
+struct cli_progressbar_widget;
+
+typedef ssize_t (*print_callback)(struct cli_progressbar* p,
+ struct cli_progressbar_widget* widget, unsigned int width, void* data);
+typedef void (*free_callback)(void* data);
struct cli_progressbar_widget {
STAILQ_ENTRY(cli_progressbar_widget) nodes;
int expandable;
void* data;
- const char* (*print)(struct cli_progressbar* p,
- struct cli_progressbar_widget* widget, unsigned int width, void* data);
- void (*free)(void* data);
+ // Callbacks
+ print_callback print;
+ free_callback free;
char* buffer;
};
return r;
unsigned int cols_left = cols - p->num_widgets - 2;
- unsigned int i = 0;
-
- // Create an array with the result of all print functions
- const char* elements[p->num_widgets];
-
- // Reset all elements
- for (i = 0; i < p->num_widgets; i++)
- elements[i] = NULL;
- // Reset i
- i = 0;
+ // Count how many widgets we have processed
+ unsigned int widgets = 0;
// Process all non-expandable widgets in the first pass
STAILQ_FOREACH(widget, &p->widgets, nodes) {
- const char* element = NULL;
-
if (!widget->expandable) {
- element = widget->print(p, widget, 0, widget->data);
- if (element)
- cols_left -= strlen(element);
- }
+ r = widget->print(p, widget, 0, widget->data);
+ if (r < 0)
+ return r;
- elements[i++] = element;
+ // Take away used space
+ cols_left -= strlen(widget->buffer);
+
+ // Count the widget
+ widgets++;
+ }
}
// How many expandable widgets are left?
- int num_expandables = p->num_widgets - i;
+ int num_expandables = p->num_widgets - widgets;
// How much space do we allocate to each of them?
- int width = cols_left - num_expandables;
-
- i = 0;
+ int width = cols_left / num_expandables;
// Process all expandable widgets
STAILQ_FOREACH(widget, &p->widgets, nodes) {
- const char* element = elements[i];
-
- if (widget->expandable)
- element = widget->print(p, widget, width, widget->data);
-
- elements[i++] = element;
+ if (widget->expandable) {
+ r = widget->print(p, widget, width, widget->data);
+ if (r < 0)
+ return r;
+ }
}
// Reset the line
fputs("\r", p->f);
- // Print all elements
- for (i = 0; i < p->num_widgets; i++) {
- // Skip anything that returned nothing
- if (!elements[i])
+ // Print all buffers
+ STAILQ_FOREACH(widget, &p->widgets, nodes) {
+ if (!widget->buffer || !*widget->buffer)
continue;
fputs(" ", p->f);
- fputs(elements[i], p->f);
+ fputs(widget->buffer, p->f);
}
// Flush everything
}
static int cli_progressbar_add_widget(struct cli_progressbar* p,
- const char* (*print)(struct cli_progressbar* p,
- struct cli_progressbar_widget* widget, unsigned int width, void* data),
- void (*free)(void* data), int expandable, void* data) {
+ print_callback print, free_callback free, int expandable, void* data) {
// Allocate the widget
struct cli_progressbar_widget* widget = calloc(1, sizeof(*widget));
if (!widget)
return 0;
}
-static const char* cli_progressbar_string(struct cli_progressbar* p,
+static ssize_t cli_progressbar_string(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
- return (const char*)data;
+ widget->buffer = data;
+
+ return strlen(widget->buffer);
}
static int cli_progressbar_add_string(struct cli_progressbar* p, const char* format, ...)
return cli_progressbar_add_widget(p, cli_progressbar_string, free, 0, s);
}
-static const char* cli_progressbar_title(struct cli_progressbar* p,
+static ssize_t cli_progressbar_title(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
- return pakfire_progress_get_title(p->progress);
+ const char* title = NULL;
+ int r;
+
+ if (!widget->buffer) {
+ title = pakfire_progress_get_title(p->progress);
+ if (!title)
+ return 0;
+
+ r = asprintf(&widget->buffer, "%s", title);
+ if (r < 0)
+ return r;
+ }
+
+ return strlen(widget->buffer);
}
static int cli_progressbar_add_title(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_title, NULL, 0, NULL);
}
-static const char* cli_progressbar_counter(struct cli_progressbar* p,
+static ssize_t cli_progressbar_counter(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
int r;
// Format the result
r = asprintf(&widget->buffer, "%lu/%lu", value, max_value);
if (r < 0)
- return NULL;
+ return -errno;
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_counter(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_counter, NULL, 0, NULL);
}
-static const char* cli_progressbar_percentage(struct cli_progressbar* p,
+static ssize_t cli_progressbar_percentage(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
int r;
// Format to string
r = asprintf(&widget->buffer, "%3.0f%%", percentage);
if (r < 0)
- return NULL;
+ return -errno;
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_percentage(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_percentage, NULL, 0, NULL);
}
-static const char* cli_progressbar_bar(struct cli_progressbar* p,
+static ssize_t cli_progressbar_bar(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
// Allocate or adjust the buffer
widget->buffer = realloc(widget->buffer, width + 1);
// Fail if we could not allocate the buffer
if (!widget->buffer)
- return NULL;
+ return -errno;
// Remove the bar when we are finished so that the terminal is not so cluttered
if (!p->is_running) {
widget->buffer[i] = ' ';
widget->buffer[width] = '\0';
- return widget->buffer;
+ return width;
}
unsigned int fill = pakfire_progress_get_percentage(p->progress) * (width - 2) / 100;
// Terminate the string
widget->buffer[width] = '\0';
- return widget->buffer;
+ return width;
}
static int cli_progressbar_add_bar(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_bar, NULL, 1, NULL);
}
-static const char* cli_progressbar_elapsed_time(struct cli_progressbar* p,
+static ssize_t cli_progressbar_elapsed_time(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
int r;
// Fetch the elapsed time
time_t t = pakfire_progress_get_elapsed_time(p->progress);
if (t < 0)
- return NULL;
+ return -errno;
// Format the time
r = asprintf(&widget->buffer, "%02ld:%02ld", t / 60, t % 60);
- if (r)
- return NULL;
+ if (r < 0)
+ return -errno;
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_elapsed_time(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_elapsed_time, NULL, 0, NULL);
}
-static const char* cli_progressbar_eta(struct cli_progressbar* p,
+static ssize_t cli_progressbar_eta(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
int r;
if (t <= 0) {
r = asprintf(&widget->buffer, "%-5s: --:--:--", _("ETA"));
if (r < 0)
- return NULL;
+ return -errno;
// Otherwise show the ETA
} else {
r = asprintf(&widget->buffer, "%-5s: %02ld:%02ld", _("ETA"), t / 60, t % 60);
if (r < 0)
- return NULL;
+ return -errno;
}
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_eta(struct cli_progressbar* p) {
}
#pragma GCC diagnostic pop
-static const char* cli_progressbar_bytes_transferred(struct cli_progressbar* p,
+static ssize_t cli_progressbar_bytes_transferred(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
char buffer[16];
int r;
// Format the size
r = cli_progressbar_format_size(buffer, value);
if (r < 0)
- return NULL;
+ return r;
// Add padding so that the string is always at least five characters long
r = asprintf(&widget->buffer, "%-5s", buffer);
if (r < 0)
- return NULL;
+ return -errno;
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_bytes_transferred(struct cli_progressbar* p) {
return cli_progressbar_add_widget(p, cli_progressbar_bytes_transferred, NULL, 0, NULL);
}
-static const char* cli_progressbar_transfer_speed(struct cli_progressbar* p,
+static ssize_t cli_progressbar_transfer_speed(struct cli_progressbar* p,
struct cli_progressbar_widget* widget, unsigned int width, void* data) {
int r;
// Fetch the speed
double speed = pakfire_progress_get_transfer_speed(p->progress);
if (speed < 0)
- return NULL;
+ return -errno;
// Format the speed
r = cli_progressbar_format_speed(&widget->buffer, speed);
if (r < 0)
- return NULL;
+ return r;
- return widget->buffer;
+ return r;
}
static int cli_progressbar_add_transfer_speed(struct cli_progressbar* p) {