Contents of /trunk/coreutils/patches-5.94/coreutils-5.94-gen-progress-bar.patch
Parent Directory | Revision Log
Revision 115 -
(show annotations)
(download)
Sun Mar 18 15:57:37 2007 UTC (17 years, 6 months ago) by niro
File size: 12890 byte(s)
Sun Mar 18 15:57:37 2007 UTC (17 years, 6 months ago) by niro
File size: 12890 byte(s)
patches for 5.94
1 | Upstream has been contacted about this a few times ... |
2 | |
3 | they dont want progress bars in mv/cp: |
4 | http://lists.gnu.org/archive/html/bug-coreutils/2003-08/msg00114.html |
5 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00083.html |
6 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00084.html |
7 | |
8 | but they don't seem to mind a general util ... add this to future patchset: |
9 | http://lists.gnu.org/archive/html/bug-coreutils/2003-09/msg00101.html |
10 | http://lists.gnu.org/archive/html/bug-coreutils/2004-02/msg00071.html |
11 | |
12 | --- coreutils/src/copy.c |
13 | +++ coreutils/src/copy.c |
14 | @@ -17,6 +17,8 @@ |
15 | |
16 | /* Extracted from cp.c and librarified by Jim Meyering. */ |
17 | |
18 | +/* Progress bar support added by Miika Pekkarinen. miipekk@ihme.org */ |
19 | + |
20 | #include <config.h> |
21 | #include <stdio.h> |
22 | #include <assert.h> |
23 | @@ -29,6 +31,10 @@ |
24 | # include <priv.h> |
25 | #endif |
26 | |
27 | +#ifdef GWINSZ_IN_SYS_IOCTL |
28 | +# include <sys/ioctl.h> |
29 | +#endif |
30 | + |
31 | #include "system.h" |
32 | #include "backupfile.h" |
33 | #include "copy.h" |
34 | @@ -50,6 +56,7 @@ |
35 | #include "utimens.h" |
36 | #include "xreadlink.h" |
37 | #include "yesno.h" |
38 | +#include "xstrtol.h" |
39 | |
40 | #ifndef HAVE_FCHMOD |
41 | # define HAVE_FCHMOD false |
42 | @@ -85,6 +92,8 @@ struct F_triple |
43 | /* Initial size of the above hash table. */ |
44 | #define DEST_INFO_INITIAL_CAPACITY 61 |
45 | |
46 | +#define SAMPLE_MAX 10 |
47 | + |
48 | static bool copy_internal (char const *src_name, char const *dst_name, |
49 | bool new_dst, dev_t device, |
50 | struct dir_list *ancestors, |
51 | @@ -191,6 +200,62 @@ copy_dir (char const *src_name_in, char |
52 | return ok; |
53 | } |
54 | |
55 | +/* Shorten a string '/long path/long file' to 'long fi...' |
56 | + Also adds padding bytes to end of the string if necessary */ |
57 | +char *shorten_name(const char *str, size_t max_width) |
58 | +{ |
59 | + char *shortname; |
60 | + char *filename = (char *) (rindex(str, '/')); |
61 | + size_t len; |
62 | + |
63 | + if (filename == NULL) |
64 | + { |
65 | + filename = (char *) str; |
66 | + } |
67 | + else |
68 | + { |
69 | + filename = (char *) &filename[1]; |
70 | + } |
71 | + |
72 | + len = strlen(filename); |
73 | + shortname = (char *) xmalloc (max_width + 1); |
74 | + strncpy (shortname, filename, max_width); |
75 | + shortname[max_width] = '\0'; |
76 | + if (len > max_width) |
77 | + { |
78 | + memset(&shortname[max_width - 3], '.', 3); |
79 | + } |
80 | + else |
81 | + { |
82 | + memset(&shortname[len], ' ', max_width - len); |
83 | + } |
84 | + |
85 | + return shortname; |
86 | +} |
87 | + |
88 | +char *si_units(off_t size) |
89 | +{ |
90 | + const static int buf_size = 20; |
91 | + char *buf; |
92 | + static char *unit_array[] = { "B", "KiB", "MiB", "GiB", "" }; |
93 | + size_t i; |
94 | + |
95 | + buf = xmalloc(20); |
96 | + for (i = 0; size > 10000; i++) |
97 | + { |
98 | + if (unit_array[i][0] == '\0') |
99 | + { |
100 | + i--; |
101 | + break; |
102 | + } |
103 | + size /= 1024; |
104 | + } |
105 | + |
106 | + snprintf (buf, buf_size, "%lu %s", (unsigned long)size, unit_array[i]); |
107 | + |
108 | + return buf; |
109 | +} |
110 | + |
111 | /* Copy a regular file from SRC_NAME to DST_NAME. |
112 | If the source file contains holes, copies holes and blocks of zeros |
113 | in the source file as holes in the destination file. |
114 | @@ -222,6 +287,19 @@ copy_reg (char const *src_name, char con |
115 | off_t n_read_total = 0; |
116 | bool last_write_made_hole = false; |
117 | bool make_holes = false; |
118 | + time_t t_start; |
119 | + time_t t_last; |
120 | + time_t t_now; |
121 | + off_t last_bytes = 0; |
122 | + int progress_bar_printed = 0; |
123 | + char *shortname = NULL; |
124 | + off_t sample_window[SAMPLE_MAX]; |
125 | + off_t sample_sum = 0; |
126 | + int sample_count = 0; |
127 | + long int line_length = 0; |
128 | +#ifdef TIOCGWINSZ |
129 | + struct winsize ws; |
130 | +#endif |
131 | |
132 | source_desc = open (src_name, O_RDONLY | O_BINARY); |
133 | if (source_desc < 0) |
134 | @@ -326,6 +404,9 @@ copy_reg (char const *src_name, char con |
135 | buf = alloca (buf_size + sizeof (int) + buf_alignment - 1); |
136 | buf = ptr_align (buf, buf_alignment); |
137 | |
138 | + time (&t_start); |
139 | + t_last = t_start; |
140 | + |
141 | for (;;) |
142 | { |
143 | ssize_t n_read = read (source_desc, buf, buf_size); |
144 | @@ -390,6 +471,113 @@ copy_reg (char const *src_name, char con |
145 | } |
146 | last_write_made_hole = false; |
147 | } |
148 | + |
149 | + time (&t_now); |
150 | + |
151 | + /* Progress bar stuff */ |
152 | + if (! x->pbar_show || t_now - t_start < x->pbar_delay) |
153 | + { |
154 | + continue; |
155 | + } |
156 | + |
157 | + if (! progress_bar_printed) |
158 | + { |
159 | + /* Column width check code copied from ls.c */ |
160 | + char const *p = getenv ("COLUMNS"); |
161 | + if (p && *p) |
162 | + { |
163 | + long int tmp_long; |
164 | + if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK |
165 | + && 0 < tmp_long && tmp_long <= INT_MAX) |
166 | + { |
167 | + line_length = tmp_long; |
168 | + } |
169 | + else |
170 | + { |
171 | + error (0, 0, |
172 | + _("ignoring invalid width in environment \ |
173 | + variable COLUMNS: %s"), |
174 | + quotearg (p)); |
175 | + } |
176 | + } |
177 | + |
178 | +#ifdef TIOCGWINSZ |
179 | + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) |
180 | + { |
181 | + line_length = ws.ws_col; |
182 | + } |
183 | +#endif |
184 | + if (line_length < 50) |
185 | + { |
186 | + continue; |
187 | + } |
188 | + |
189 | + /* Take a short filename for progress bar */ |
190 | + shortname = shorten_name(src_name, line_length - 48); |
191 | + progress_bar_printed = 1; |
192 | + } |
193 | + |
194 | + if (t_now == t_last) |
195 | + { |
196 | + continue; |
197 | + } |
198 | + |
199 | + if (sample_count == SAMPLE_MAX) |
200 | + { |
201 | + int i; |
202 | + |
203 | + sample_sum -= sample_window[0]; |
204 | + for (i = 0; i < SAMPLE_MAX - 1; i++) |
205 | + { |
206 | + sample_window[i] = sample_window[i + 1]; |
207 | + } |
208 | + } |
209 | + else |
210 | + { |
211 | + sample_count++; |
212 | + } |
213 | + |
214 | + { |
215 | + char *str_size; |
216 | + char *str_speed; |
217 | + char etabuf[64]; |
218 | + time_t t_temp; |
219 | + |
220 | + sample_window[sample_count - 1] = (n_read_total - last_bytes) / |
221 | + (t_now - t_last); |
222 | + sample_sum += sample_window[sample_count - 1]; |
223 | + |
224 | + /* Calculate the remaining time */ |
225 | + t_temp = (src_open_sb.st_size - n_read_total) / (sample_sum / sample_count); |
226 | + |
227 | + /* Don't print the progress bar if the estimated remaining |
228 | + time is low. */ |
229 | + if (progress_bar_printed == 1 && t_temp < x->pbar_min_est) |
230 | + { |
231 | + continue; |
232 | + } |
233 | + progress_bar_printed = 2; |
234 | + |
235 | + str_size = si_units(src_open_sb.st_size); |
236 | + str_speed = si_units(sample_sum / sample_count); |
237 | + |
238 | + strftime(etabuf, sizeof etabuf, "%H:%M.%S", |
239 | + gmtime(&t_temp)); |
240 | + printf (_("%s | %3lu%% | %9s | %9s/s | ETA %s\r"), shortname, |
241 | + (unsigned long)(n_read_total * 100 / src_open_sb.st_size), |
242 | + str_size, str_speed, etabuf); |
243 | + fflush (stdout); |
244 | + free(str_size); |
245 | + free(str_speed); |
246 | + t_last = t_now; |
247 | + last_bytes = n_read_total; |
248 | + } |
249 | + } |
250 | + |
251 | + /* Print a newline if progress bar is enabled and has been shown */ |
252 | + if (progress_bar_printed == 2) |
253 | + { |
254 | + printf ("%s | 100%%\n", shortname); |
255 | } |
256 | |
257 | /* If the file ends with a `hole', something needs to be written at |
258 | @@ -488,6 +676,11 @@ close_src_desc: |
259 | return_val = false; |
260 | } |
261 | |
262 | + if (shortname != NULL) |
263 | + { |
264 | + free (shortname); |
265 | + } |
266 | + |
267 | return return_val; |
268 | } |
269 | |
270 | --- coreutils/src/copy.h |
271 | +++ coreutils/src/copy.h |
272 | @@ -175,6 +175,16 @@ struct cp_options |
273 | /* If true, display the names of the files before copying them. */ |
274 | bool verbose; |
275 | |
276 | + /* If true, display a progress bar when the following conditions are |
277 | + * met: |
278 | + - pbar_delay defines how many seconds to wait before considering to |
279 | + display the progress bar |
280 | + - pbar_min_est defines how many seconds estimated operation complete |
281 | + time should be at least to show the progress bar. */ |
282 | + bool pbar_show; |
283 | + int pbar_delay; |
284 | + int pbar_min_est; |
285 | + |
286 | /* If true, stdin is a tty. */ |
287 | bool stdin_tty; |
288 | |
289 | --- coreutils/src/cp.c |
290 | +++ coreutils/src/cp.c |
291 | @@ -81,6 +81,14 @@ enum |
292 | /* Initial number of entries in the inode hash table. */ |
293 | #define INITIAL_ENTRY_TAB_SIZE 70 |
294 | |
295 | +/* Initial settings for progress bar when it's enabled. |
296 | + PROGRESS_DELAY defines how many seconds to wait before even |
297 | + considering to display a proggress bar. |
298 | + PROGRESS_MIN_EST defines how many seconds estimated operation |
299 | + complete time should be at least to show the progress bar. */ |
300 | +#define PROGRESS_DELAY 5 |
301 | +#define PROGRESS_MIN_EST 5 |
302 | + |
303 | /* The invocation name of this program. */ |
304 | char *program_name; |
305 | |
306 | @@ -120,6 +128,7 @@ static struct option const long_opts[] = |
307 | {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, |
308 | {"dereference", no_argument, NULL, 'L'}, |
309 | {"force", no_argument, NULL, 'f'}, |
310 | + {"progress", no_argument, NULL, 'g'}, |
311 | {"interactive", no_argument, NULL, 'i'}, |
312 | {"link", no_argument, NULL, 'l'}, |
313 | {"no-dereference", no_argument, NULL, 'P'}, |
314 | @@ -176,6 +185,8 @@ Mandatory arguments to long options are |
315 | fputs (_("\ |
316 | -f, --force if an existing destination file cannot be\n\ |
317 | opened, remove it and try again\n\ |
318 | + -g, --progress show a progress bar if operation is going to\n\ |
319 | + take a long time\n\ |
320 | -i, --interactive prompt before overwrite\n\ |
321 | -H follow command-line symbolic links\n\ |
322 | "), stdout); |
323 | @@ -705,6 +716,11 @@ cp_option_init (struct cp_options *x) |
324 | |
325 | x->update = false; |
326 | x->verbose = false; |
327 | + |
328 | + x->pbar_show = false; |
329 | + x->pbar_delay = PROGRESS_DELAY; |
330 | + x->pbar_min_est = PROGRESS_MIN_EST; |
331 | + |
332 | x->dest_info = NULL; |
333 | x->src_info = NULL; |
334 | } |
335 | @@ -811,7 +827,7 @@ main (int argc, char **argv) |
336 | we'll actually use backup_suffix_string. */ |
337 | backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); |
338 | |
339 | - while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T", |
340 | + while ((c = getopt_long (argc, argv, "abdfgHilLprst:uvxPRS:T", |
341 | long_opts, NULL)) |
342 | != -1) |
343 | { |
344 | @@ -871,6 +887,10 @@ main (int argc, char **argv) |
345 | x.dereference = DEREF_NEVER; |
346 | break; |
347 | |
348 | + case 'g': |
349 | + x.pbar_show = 1; |
350 | + break; |
351 | + |
352 | case NO_PRESERVE_ATTRIBUTES_OPTION: |
353 | decode_preserve_arg (optarg, &x, false); |
354 | break; |
355 | --- coreutils/src/mv.c |
356 | +++ coreutils/src/mv.c |
357 | @@ -45,6 +45,14 @@ |
358 | /* Initial number of entries in the inode hash table. */ |
359 | #define INITIAL_ENTRY_TAB_SIZE 70 |
360 | |
361 | +/* Initial settings for progress bar when it's enabled. |
362 | + PROGRESS_DELAY defines how many seconds to wait before even |
363 | + considering to display a proggress bar. |
364 | + PROGRESS_MIN_EST defines how many seconds estimated operation |
365 | + complete time should be at least to show the progress bar. */ |
366 | +#define PROGRESS_DELAY 5 |
367 | +#define PROGRESS_MIN_EST 5 |
368 | + |
369 | /* For long options that have no equivalent short option, use a |
370 | non-character as a pseudo short option, starting with CHAR_MAX + 1. */ |
371 | enum |
372 | @@ -75,6 +83,7 @@ static struct option const long_options[ |
373 | { |
374 | {"backup", optional_argument, NULL, 'b'}, |
375 | {"force", no_argument, NULL, 'f'}, |
376 | + {"progress", no_argument, NULL, 'g'}, |
377 | {"interactive", no_argument, NULL, 'i'}, |
378 | {"no-target-directory", no_argument, NULL, 'T'}, |
379 | {"reply", required_argument, NULL, REPLY_OPTION}, /* Deprecated 2005-07-03, |
380 | @@ -104,6 +113,10 @@ rm_option_init (struct rm_options *x) |
381 | |
382 | x->verbose = false; |
383 | |
384 | + x->pbar_show = false; |
385 | + x->pbar_delay = PROGRESS_DELAY; |
386 | + x->pbar_min_est = PROGRESS_MIN_EST; |
387 | + |
388 | /* Since this program may well have to process additional command |
389 | line arguments after any call to `rm', that function must preserve |
390 | the initial working directory, in case one of those is a |
391 | @@ -312,6 +325,8 @@ Mandatory arguments to long options are |
392 | --backup[=CONTROL] make a backup of each existing destination file\n\ |
393 | -b like --backup but does not accept an argument\n\ |
394 | -f, --force do not prompt before overwriting\n\ |
395 | + -g, --progress show a progress bar if operation is going to\n\ |
396 | + take a long time\n\ |
397 | -i, --interactive prompt before overwrite\n\ |
398 | "), stdout); |
399 | fputs (_("\ |
400 | @@ -375,7 +393,7 @@ main (int argc, char **argv) |
401 | we'll actually use backup_suffix_string. */ |
402 | backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); |
403 | |
404 | - while ((c = getopt_long (argc, argv, "bfit:uvS:T", long_options, NULL)) |
405 | + while ((c = getopt_long (argc, argv, "bfgit:uvS:T", long_options, NULL)) |
406 | != -1) |
407 | { |
408 | switch (c) |
409 | @@ -388,6 +406,9 @@ main (int argc, char **argv) |
410 | case 'f': |
411 | x.interactive = I_ALWAYS_YES; |
412 | break; |
413 | + case 'g': |
414 | + x.pbar_show = 1; |
415 | + break; |
416 | case 'i': |
417 | x.interactive = I_ASK_USER; |
418 | break; |
419 | --- coreutils/src/remove.h |
420 | +++ coreutils/src/remove.h |
421 | @@ -48,6 +48,16 @@ struct rm_options |
422 | /* If true, display the name of each file removed. */ |
423 | bool verbose; |
424 | |
425 | + /* If true, display a progress bar when the following conditions are |
426 | + * met: |
427 | + - pbar_delay defines how many seconds to wait before considering to |
428 | + display the progress bar |
429 | + - pbar_min_est defines how many seconds estimated operation complete |
430 | + time should be at least to show the progress bar. */ |
431 | + bool pbar_show; |
432 | + int pbar_delay; |
433 | + int pbar_min_est; |
434 | + |
435 | /* If true, treat the failure by the rm function to restore the |
436 | current working directory as a fatal error. I.e., if this field |
437 | is true and the rm function cannot restore cwd, it must exit with |