]> git.ipfire.org Git - pakfire.git/commitdiff
cli: progressbar: Remove the elements array
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 22 Oct 2024 16:35:25 +0000 (16:35 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 22 Oct 2024 16:35:25 +0000 (16:35 +0000)
This was a dynamically allocated array which was difficult to track as
it was filled in two passes.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/cli/lib/progressbar.c

index bf2f083efe73ba5838eeb18ec2e4c699d20fa662..0fbce4a38effed4964c99723b05e0072e9c695db 100644 (file)
@@ -40,6 +40,11 @@ static const struct timespec TIMER = {
 };
 
 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;
@@ -47,9 +52,9 @@ struct cli_progressbar_widget {
        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;
 };
@@ -144,60 +149,50 @@ static int cli_progressbar_draw(struct cli_progressbar* p) {
                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
@@ -272,9 +267,7 @@ static int cli_progressbar_finish(struct pakfire_ctx* ctx, struct pakfire_progre
 }
 
 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)
@@ -293,9 +286,11 @@ static int cli_progressbar_add_widget(struct cli_progressbar* p,
        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, ...)
@@ -315,16 +310,29 @@ static int cli_progressbar_add_string(struct cli_progressbar* p, const char* for
        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;
 
@@ -335,16 +343,16 @@ static const char* cli_progressbar_counter(struct cli_progressbar* p,
        // 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;
 
@@ -354,23 +362,23 @@ static const char* cli_progressbar_percentage(struct cli_progressbar* p,
        // 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) {
@@ -378,7 +386,7 @@ static const char* cli_progressbar_bar(struct cli_progressbar* p,
                        widget->buffer[i] = ' ';
                widget->buffer[width] = '\0';
 
-               return widget->buffer;
+               return width;
        }
 
        unsigned int fill = pakfire_progress_get_percentage(p->progress) * (width - 2) / 100;
@@ -398,35 +406,35 @@ static const char* cli_progressbar_bar(struct cli_progressbar* p,
        // 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;
 
@@ -441,16 +449,16 @@ static const char* cli_progressbar_eta(struct cli_progressbar* p,
        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) {
@@ -519,7 +527,7 @@ static int __cli_progressbar_format_size(char* s, const size_t length, double va
 }
 #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;
@@ -530,35 +538,35 @@ static const char* cli_progressbar_bytes_transferred(struct cli_progressbar* p,
        // 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) {