Merge branch 'maint'
[git] / progress.c
1 #include "git-compat-util.h"
2 #include "progress.h"
3
4 static volatile sig_atomic_t progress_update;
5
6 static void progress_interval(int signum)
7 {
8         progress_update = 1;
9 }
10
11 static void set_progress_signal(void)
12 {
13         struct sigaction sa;
14         struct itimerval v;
15
16         progress_update = 0;
17
18         memset(&sa, 0, sizeof(sa));
19         sa.sa_handler = progress_interval;
20         sigemptyset(&sa.sa_mask);
21         sa.sa_flags = SA_RESTART;
22         sigaction(SIGALRM, &sa, NULL);
23
24         v.it_interval.tv_sec = 1;
25         v.it_interval.tv_usec = 0;
26         v.it_value = v.it_interval;
27         setitimer(ITIMER_REAL, &v, NULL);
28 }
29
30 static void clear_progress_signal(void)
31 {
32         struct itimerval v = {{0,},};
33         setitimer(ITIMER_REAL, &v, NULL);
34         signal(SIGALRM, SIG_IGN);
35         progress_update = 0;
36 }
37
38 int display_progress(struct progress *progress, unsigned n)
39 {
40         if (progress->delay) {
41                 char buf[80];
42                 if (!progress_update || --progress->delay)
43                         return 0;
44                 if (progress->total) {
45                         unsigned percent = n * 100 / progress->total;
46                         if (percent > progress->delayed_percent_treshold) {
47                                 /* inhibit this progress report entirely */
48                                 clear_progress_signal();
49                                 progress->delay = -1;
50                                 progress->total = 0;
51                                 return 0;
52                         }
53                 }
54                 if (snprintf(buf, sizeof(buf),
55                              progress->delayed_title, progress->total))
56                         fprintf(stderr, "%s\n", buf);
57         }
58         if (progress->total) {
59                 unsigned percent = n * 100 / progress->total;
60                 if (percent != progress->last_percent || progress_update) {
61                         progress->last_percent = percent;
62                         fprintf(stderr, "%s%4u%% (%u/%u) done\r",
63                                 progress->prefix, percent, n, progress->total);
64                         progress_update = 0;
65                         progress->need_lf = 1;
66                         return 1;
67                 }
68         } else if (progress_update) {
69                 fprintf(stderr, "%s%u\r", progress->prefix, n);
70                 progress_update = 0;
71                 progress->need_lf = 1;
72                 return 1;
73         }
74         return 0;
75 }
76
77 void start_progress(struct progress *progress, const char *title,
78                     const char *prefix, unsigned total)
79 {
80         char buf[80];
81         progress->prefix = prefix;
82         progress->total = total;
83         progress->last_percent = -1;
84         progress->delay = 0;
85         progress->need_lf = 0;
86         if (snprintf(buf, sizeof(buf), title, total))
87                 fprintf(stderr, "%s\n", buf);
88         set_progress_signal();
89 }
90
91 void start_progress_delay(struct progress *progress, const char *title,
92                           const char *prefix, unsigned total,
93                           unsigned percent_treshold, unsigned delay)
94 {
95         progress->prefix = prefix;
96         progress->total = total;
97         progress->last_percent = -1;
98         progress->delayed_percent_treshold = percent_treshold;
99         progress->delayed_title = title;
100         progress->delay = delay;
101         progress->need_lf = 0;
102         set_progress_signal();
103 }
104
105 void stop_progress(struct progress *progress)
106 {
107         clear_progress_signal();
108         if (progress->need_lf)
109                 fputc('\n', stderr);
110 }