Code

make struct progress an opaque type
[git.git] / progress.c
index 05f7890314e0bd596eb2e4110cdb98eeea61c9da..c342e39c5d2e5673fc95e0cdc91856b0bc3cdd35 100644 (file)
@@ -1,6 +1,15 @@
 #include "git-compat-util.h"
 #include "progress.h"
 
+struct progress {
+       const char *title;
+       int last_value;
+       unsigned total;
+       unsigned last_percent;
+       unsigned delay;
+       unsigned delayed_percent_treshold;
+};
+
 static volatile sig_atomic_t progress_update;
 
 static void progress_interval(int signum)
@@ -35,10 +44,11 @@ static void clear_progress_signal(void)
        progress_update = 0;
 }
 
-int display_progress(struct progress *progress, unsigned n)
+static int display(struct progress *progress, unsigned n, int done)
 {
+       char *eol;
+
        if (progress->delay) {
-               char buf[80];
                if (!progress_update || --progress->delay)
                        return 0;
                if (progress->total) {
@@ -51,56 +61,68 @@ int display_progress(struct progress *progress, unsigned n)
                                return 0;
                        }
                }
-               if (snprintf(buf, sizeof(buf),
-                            progress->delayed_title, progress->total))
-                       fprintf(stderr, "%s\n", buf);
        }
+
+       progress->last_value = n;
+       eol = done ? ", done.   \n" : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
                        progress->last_percent = percent;
-                       fprintf(stderr, "%s%4u%% (%u/%u) done\r",
-                               progress->prefix, percent, n, progress->total);
+                       fprintf(stderr, "%s: %3u%% (%u/%u)%s", progress->title,
+                               percent, n, progress->total, eol);
                        progress_update = 0;
                        return 1;
                }
        } else if (progress_update) {
-               fprintf(stderr, "%s%u\r", progress->prefix, n);
+               fprintf(stderr, "%s: %u%s", progress->title, n, eol);
                progress_update = 0;
                return 1;
        }
+
        return 0;
 }
 
-void start_progress(struct progress *progress, const char *title,
-                   const char *prefix, unsigned total)
+int display_progress(struct progress *progress, unsigned n)
 {
-       char buf[80];
-       progress->prefix = prefix;
-       progress->total = total;
-       progress->last_percent = -1;
-       progress->delay = 0;
-       if (snprintf(buf, sizeof(buf), title, total))
-               fprintf(stderr, "%s\n", buf);
-       set_progress_signal();
+       return progress ? display(progress, n, 0) : 0;
 }
 
-void start_progress_delay(struct progress *progress, const char *title,
-                         const char *prefix, unsigned total,
-                         unsigned percent_treshold, unsigned delay)
+struct progress *start_progress_delay(const char *title, unsigned total,
+                                      unsigned percent_treshold, unsigned delay)
 {
-       progress->prefix = prefix;
+       struct progress *progress = malloc(sizeof(*progress));
+       if (!progress) {
+               /* unlikely, but here's a good fallback */
+               fprintf(stderr, "%s...\n", title);
+               return NULL;
+       }
+       progress->title = title;
        progress->total = total;
+       progress->last_value = -1;
        progress->last_percent = -1;
        progress->delayed_percent_treshold = percent_treshold;
-       progress->delayed_title = title;
        progress->delay = delay;
        set_progress_signal();
+       return progress;
 }
 
-void stop_progress(struct progress *progress)
+struct progress *start_progress(const char *title, unsigned total)
 {
+       return start_progress_delay(title, total, 0, 0);
+}
+
+void stop_progress(struct progress **p_progress)
+{
+       struct progress *progress = *p_progress;
+       if (!progress)
+               return;
+       *p_progress = NULL;
+       if (progress->last_value != -1) {
+               /* Force the last update */
+               progress_update = 1;
+               display(progress, progress->last_value, 1);
+       }
        clear_progress_signal();
-       if (progress->total)
-               fputc('\n', stderr);
+       free(progress);
 }