]>
Commit | Line | Data |
---|---|---|
836ec036 PZ |
1 | diff -ur wget-1.9.1/src/progress.c wget-1.9.1-patrys/src/progress.c |
2 | --- wget-1.9.1/src/progress.c 2003-09-23 22:48:10.000000000 +0200 | |
3 | +++ wget-1.9.1-patrys/src/progress.c 2004-05-28 12:32:20.964152440 +0200 | |
4 | @@ -69,9 +69,15 @@ | |
5 | static void bar_finish PARAMS ((void *, double)); | |
6 | static void bar_set_params PARAMS ((const char *)); | |
b8452f90 | 7 | |
836ec036 PZ |
8 | +static void *porn_create PARAMS ((long, long)); |
9 | +static void porn_update PARAMS ((void *, long, double)); | |
10 | +static void porn_finish PARAMS ((void *, double)); | |
11 | +static void porn_set_params PARAMS ((const char *)); | |
12 | + | |
13 | static struct progress_implementation implementations[] = { | |
14 | { "dot", dot_create, dot_update, dot_finish, dot_set_params }, | |
15 | - { "bar", bar_create, bar_update, bar_finish, bar_set_params } | |
16 | + { "bar", bar_create, bar_update, bar_finish, bar_set_params }, | |
17 | + { "porn", porn_create, porn_update, porn_finish, porn_set_params } | |
18 | }; | |
19 | static struct progress_implementation *current_impl; | |
20 | static int current_impl_locked; | |
21 | @@ -473,6 +479,7 @@ | |
22 | ||
23 | static void create_image PARAMS ((struct bar_progress *, double)); | |
24 | static void display_image PARAMS ((char *)); | |
25 | +static void porn_create_image PARAMS ((struct bar_progress *, double)); | |
b8452f90 | 26 | |
836ec036 PZ |
27 | static void * |
28 | bar_create (long initial, long total) | |
29 | @@ -888,6 +895,339 @@ | |
30 | screen_width = sw; | |
31 | } | |
32 | ||
33 | + | |
34 | +static void * | |
35 | +porn_create (long initial, long total) | |
36 | +{ | |
37 | + struct bar_progress *bp = xmalloc (sizeof (struct bar_progress)); | |
38 | + | |
39 | + memset (bp, 0, sizeof (*bp)); | |
40 | + | |
41 | + /* In theory, our callers should take care of this pathological | |
42 | + case, but it can sometimes happen. */ | |
43 | + if (initial > total) | |
44 | + total = initial; | |
45 | + | |
46 | + bp->initial_length = initial; | |
47 | + bp->total_length = total; | |
48 | + | |
49 | + /* - 1 because we don't want to use the last screen column. */ | |
50 | + bp->width = screen_width - 1; | |
51 | + /* + 1 for the terminating zero. */ | |
52 | + bp->buffer = xmalloc (bp->width + 1); | |
53 | + | |
54 | + logputs (LOG_VERBOSE, "\n"); | |
55 | + | |
56 | + porn_create_image (bp, 0); | |
57 | + display_image (bp->buffer); | |
58 | + | |
59 | + return bp; | |
60 | +} | |
61 | + | |
62 | +static void | |
63 | +porn_update (void *progress, long howmuch, double dltime) | |
64 | +{ | |
65 | + struct bar_progress *bp = progress; | |
66 | + int force_screen_update = 0; | |
67 | + | |
68 | + bp->count += howmuch; | |
69 | + if (bp->total_length > 0 | |
70 | + && bp->count + bp->initial_length > bp->total_length) | |
71 | + /* We could be downloading more than total_length, e.g. when the | |
72 | + server sends an incorrect Content-Length header. In that case, | |
73 | + adjust bp->total_length to the new reality, so that the code in | |
74 | + create_image() that depends on total size being smaller or | |
75 | + equal to the expected size doesn't abort. */ | |
76 | + bp->total_length = bp->initial_length + bp->count; | |
77 | + | |
78 | + update_speed_ring (bp, howmuch, dltime); | |
79 | + | |
80 | + if (screen_width - 1 != bp->width) | |
81 | + { | |
82 | + bp->width = screen_width - 1; | |
83 | + bp->buffer = xrealloc (bp->buffer, bp->width + 1); | |
84 | + force_screen_update = 1; | |
85 | + } | |
86 | + | |
87 | + if (dltime - bp->last_screen_update < 200 && !force_screen_update) | |
88 | + /* Don't update more often than five times per second. */ | |
89 | + return; | |
90 | + | |
91 | + porn_create_image (bp, dltime); | |
92 | + display_image (bp->buffer); | |
93 | + bp->last_screen_update = dltime; | |
94 | +} | |
95 | + | |
96 | +static void | |
97 | +porn_finish (void *progress, double dltime) | |
98 | +{ | |
99 | + struct bar_progress *bp = progress; | |
100 | + | |
101 | + if (bp->total_length > 0 | |
102 | + && bp->count + bp->initial_length > bp->total_length) | |
103 | + /* See bar_update() for explanation. */ | |
104 | + bp->total_length = bp->initial_length + bp->count; | |
105 | + | |
106 | + porn_create_image (bp, dltime); | |
107 | + display_image (bp->buffer); | |
108 | + | |
109 | + logputs (LOG_VERBOSE, "\n\n"); | |
110 | + | |
111 | + xfree (bp->buffer); | |
112 | + xfree (bp); | |
113 | +} | |
114 | + | |
115 | +static void | |
116 | +porn_create_image (struct bar_progress *bp, double dl_total_time) | |
117 | +{ | |
118 | + char *p = bp->buffer; | |
119 | + long size = bp->initial_length + bp->count; | |
120 | + | |
121 | + char *size_legible = legible (size); | |
122 | + int size_legible_len = strlen (size_legible); | |
123 | + | |
124 | + struct bar_progress_hist *hist = &bp->hist; | |
125 | + | |
126 | + /* The progress bar should look like this: | |
127 | + xx% [=======> ] nn,nnn 12.34K/s ETA 00:00 | |
128 | + | |
129 | + Calculate the geometry. The idea is to assign as much room as | |
130 | + possible to the progress bar. The other idea is to never let | |
131 | + things "jitter", i.e. pad elements that vary in size so that | |
132 | + their variance does not affect the placement of other elements. | |
133 | + It would be especially bad for the progress bar to be resized | |
134 | + randomly. | |
135 | + | |
136 | + "xx% " or "100%" - percentage - 4 chars | |
137 | + "8(_o_)" - progress bar decorations - 6 chars | |
138 | + " nnn,nnn,nnn" - downloaded bytes - 12 chars or very rarely more | |
139 | + " 1012.56K/s" - dl rate - 11 chars | |
140 | + " ETA xx:xx:xx" - ETA - 13 chars | |
141 | + | |
b8452f90 | 142 | + "=====D..." - progress bar - the rest |
836ec036 PZ |
143 | + */ |
144 | + int dlbytes_size = 1 + MAX (size_legible_len, 11); | |
b8452f90 | 145 | + int progress_size = bp->width - (4 + 6 + dlbytes_size + 11 + 13); |
900c7964 | 146 | + |
147 | + int percentage = (int)(100.0 * size / bp->total_length); | |
148 | + | |
149 | + assert (percentage <= 100); | |
836ec036 PZ |
150 | + |
151 | + if (progress_size < 5) | |
152 | + progress_size = 0; | |
153 | + | |
154 | + /* "xx% " */ | |
155 | + if (bp->total_length > 0) | |
156 | + { | |
157 | + | |
158 | + if (percentage < 100) | |
159 | + sprintf (p, "%2d%% ", percentage); | |
160 | + else | |
161 | + strcpy (p, "100%"); | |
162 | + p += 4; | |
163 | + } | |
164 | + else | |
165 | + APPEND_LITERAL (" "); | |
166 | + | |
167 | + /* The progress bar: "[====> ]" or "[++==> ]". */ | |
168 | + if (progress_size && bp->total_length > 0) | |
169 | + { | |
170 | + /* Size of the initial portion. */ | |
171 | + int insz = (double)bp->initial_length / bp->total_length * progress_size; | |
172 | + | |
173 | + /* Size of the downloaded portion. */ | |
174 | + int dlsz = (double)size / bp->total_length * progress_size; | |
175 | + | |
176 | + char *begin; | |
177 | + int i; | |
178 | + | |
179 | + assert (dlsz <= progress_size); | |
180 | + assert (insz <= dlsz); | |
181 | + | |
d1f321ac | 182 | + *p++ = '8'; |
836ec036 PZ |
183 | + begin = p; |
184 | + | |
185 | + /* Print the initial portion of the download with '+' chars, the | |
186 | + rest with '=' and one '>'. */ | |
187 | + for (i = 0; i < insz; i++) | |
188 | + *p++ = '+'; | |
189 | + dlsz -= insz; | |
190 | + if (dlsz > 0) | |
191 | + { | |
192 | + for (i = 0; i < dlsz - 1; i++) | |
193 | + *p++ = '='; | |
d1f321ac | 194 | + *p++ = 'D'; |
836ec036 PZ |
195 | + } |
196 | + | |
197 | + while (p - begin < progress_size) | |
198 | + *p++ = ' '; | |
b8452f90 | 199 | + *p++ = '('; |
200 | + *p++ = '_'; | |
900c7964 | 201 | + if (percentage < 25) |
202 | + *p++ = '.'; | |
203 | + else if (percentage < 50) | |
204 | + *p++ = 'o'; | |
205 | + else if (percentage < 75) | |
206 | + *p++ = '0'; | |
207 | + else | |
208 | + *p++ = 'O'; | |
b8452f90 | 209 | + *p++ = '_'; |
210 | + *p++ = ')'; | |
836ec036 PZ |
211 | + } |
212 | + else if (progress_size) | |
213 | + { | |
214 | + /* If we can't draw a real progress bar, then at least show | |
215 | + *something* to the user. */ | |
216 | + int ind = bp->tick % (progress_size * 2 - 6); | |
217 | + int i, pos; | |
218 | + | |
219 | + /* Make the star move in two directions. */ | |
220 | + if (ind < progress_size - 2) | |
221 | + pos = ind + 1; | |
222 | + else | |
223 | + pos = progress_size - (ind - progress_size + 5); | |
224 | + | |
225 | + *p++ = '['; | |
226 | + for (i = 0; i < progress_size; i++) | |
227 | + { | |
228 | + if (i == pos - 1) *p++ = '8'; | |
229 | + else if (i == pos ) *p++ = '='; | |
230 | + else if (i == pos + 1) *p++ = 'D'; | |
231 | + else | |
232 | + *p++ = ' '; | |
233 | + } | |
234 | + *p++ = ']'; | |
235 | + | |
236 | + ++bp->tick; | |
237 | + } | |
238 | + | |
239 | + /* " 234,567,890" */ | |
240 | + sprintf (p, " %-11s", legible (size)); | |
241 | + p += strlen (p); | |
242 | + | |
243 | + /* " 1012.45K/s" */ | |
244 | + if (hist->total_time && hist->total_bytes) | |
245 | + { | |
246 | + static char *short_units[] = { "B/s", "K/s", "M/s", "G/s" }; | |
247 | + int units = 0; | |
248 | + /* Calculate the download speed using the history ring and | |
249 | + recent data that hasn't made it to the ring yet. */ | |
250 | + long dlquant = hist->total_bytes + bp->recent_bytes; | |
251 | + double dltime = hist->total_time + (dl_total_time - bp->recent_start); | |
252 | + double dlspeed = calc_rate (dlquant, dltime, &units); | |
253 | + sprintf (p, " %7.2f%s", dlspeed, short_units[units]); | |
254 | + p += strlen (p); | |
255 | + } | |
256 | + else | |
257 | + APPEND_LITERAL (" --.--K/s"); | |
258 | + | |
259 | + /* " ETA xx:xx:xx"; wait for three seconds before displaying the ETA. | |
260 | + That's because the ETA value needs a while to become | |
261 | + reliable. */ | |
262 | + if (bp->total_length > 0 && dl_total_time > 3000) | |
263 | + { | |
264 | + long eta; | |
265 | + int eta_hrs, eta_min, eta_sec; | |
266 | + | |
267 | + /* Don't change the value of ETA more than approximately once | |
268 | + per second; doing so would cause flashing without providing | |
269 | + any value to the user. */ | |
270 | + if (bp->total_length != size | |
271 | + && bp->last_eta_value != 0 | |
272 | + && dl_total_time - bp->last_eta_time < 900) | |
273 | + eta = bp->last_eta_value; | |
274 | + else | |
275 | + { | |
276 | + /* Calculate ETA using the average download speed to predict | |
277 | + the future speed. If you want to use a speed averaged | |
278 | + over a more recent period, replace dl_total_time with | |
279 | + hist->total_time and bp->count with hist->total_bytes. | |
280 | + I found that doing that results in a very jerky and | |
281 | + ultimately unreliable ETA. */ | |
282 | + double time_sofar = (double)dl_total_time / 1000; | |
283 | + long bytes_remaining = bp->total_length - size; | |
284 | + eta = (long) (time_sofar * bytes_remaining / bp->count); | |
285 | + bp->last_eta_value = eta; | |
286 | + bp->last_eta_time = dl_total_time; | |
287 | + } | |
288 | + | |
289 | + eta_hrs = eta / 3600, eta %= 3600; | |
290 | + eta_min = eta / 60, eta %= 60; | |
291 | + eta_sec = eta; | |
292 | + | |
293 | + if (eta_hrs > 99) | |
294 | + goto no_eta; | |
295 | + | |
296 | + if (eta_hrs == 0) | |
297 | + { | |
298 | + /* Hours not printed: pad with three spaces. */ | |
299 | + APPEND_LITERAL (" "); | |
300 | + sprintf (p, " ETA %02d:%02d", eta_min, eta_sec); | |
301 | + } | |
302 | + else | |
303 | + { | |
304 | + if (eta_hrs < 10) | |
305 | + /* Hours printed with one digit: pad with one space. */ | |
306 | + *p++ = ' '; | |
307 | + sprintf (p, " ETA %d:%02d:%02d", eta_hrs, eta_min, eta_sec); | |
308 | + } | |
309 | + p += strlen (p); | |
310 | + } | |
311 | + else if (bp->total_length > 0) | |
312 | + { | |
313 | + no_eta: | |
314 | + APPEND_LITERAL (" "); | |
315 | + } | |
316 | + | |
317 | + assert (p - bp->buffer <= bp->width); | |
318 | + | |
319 | + while (p < bp->buffer + bp->width) | |
320 | + *p++ = ' '; | |
321 | + *p = '\0'; | |
322 | +} | |
323 | + | |
324 | +static void | |
325 | +porn_set_params (const char *params) | |
326 | +{ | |
327 | + int sw; | |
328 | + char *term = getenv ("TERM"); | |
329 | + | |
330 | + if (params | |
331 | + && 0 == strcmp (params, "force")) | |
332 | + current_impl_locked = 1; | |
333 | + | |
334 | + if ((opt.lfilename | |
335 | +#ifdef HAVE_ISATTY | |
336 | + /* The progress bar doesn't make sense if the output is not a | |
337 | + TTY -- when logging to file, it is better to review the | |
338 | + dots. */ | |
339 | + || !isatty (fileno (stderr)) | |
340 | +#else | |
341 | + 1 | |
342 | +#endif | |
343 | + /* Normally we don't depend on terminal type because the | |
344 | + progress bar only uses ^M to move the cursor to the | |
345 | + beginning of line, which works even on dumb terminals. But | |
346 | + Jamie Zawinski reports that ^M and ^H tricks don't work in | |
347 | + Emacs shell buffers, and only make a mess. */ | |
348 | + || (term && 0 == strcmp (term, "emacs")) | |
349 | + ) | |
350 | + && !current_impl_locked) | |
351 | + { | |
352 | + /* We're not printing to a TTY, so revert to the fallback | |
353 | + display. #### We're recursively calling | |
354 | + set_progress_implementation here, which is slightly kludgy. | |
355 | + It would be nicer if we provided that function a return value | |
356 | + indicating a failure of some sort. */ | |
357 | + set_progress_implementation (FALLBACK_PROGRESS_IMPLEMENTATION); | |
358 | + return; | |
359 | + } | |
360 | + | |
361 | + sw = determine_screen_width (); | |
362 | + if (sw && sw >= MINIMUM_SCREEN_WIDTH) | |
363 | + screen_width = sw; | |
364 | +} | |
365 | + | |
366 | #ifdef SIGWINCH | |
367 | RETSIGTYPE | |
368 | progress_handle_sigwinch (int sig) |