bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: cp progress bar


From: Andrea Di Pasquale
Subject: Re: cp progress bar
Date: Mon, 31 Dec 2007 04:27:35 +0100

Mike write:
you didnt say whether your host was a 32bit or 64bit system

Hi!
I tested it on 32bit & 64bit x86/UltraSPARC/PowerPC machines.

Changelog:
==========

copy.c:
  - Added progress_bar_check():
      Source file size check
      Max console line length check
  - Fixed progress_bar_print_speed():
      New algorythm for determining copying speed size
  - Progress_bar_print_size() rewritten
  - Fixed progress_bar_print_eta()

cp.c:
  - Fixed help

patch code (coreutils 5.97):

--- copy.c      2006-05-12 09:04:29.000000000 +0200
+++ copy.c      2007-12-31 03:04:24.000000000 +0100
@@ -17,6 +17,8 @@
 
 /* Extracted from cp.c and librarified by Jim Meyering.  */
 
+/* Progress bar support add by Andrea Di Pasquale (whyx) email:
address@hidden */
+
 #include <config.h>
 #include <stdio.h>
 #include <assert.h>
@@ -29,6 +31,10 @@
 # include <priv.h>
 #endif
 
+#if HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
 #include "system.h"
 #include "backupfile.h"
 #include "copy.h"
@@ -43,6 +49,7 @@
 #include "hash.h"
 #include "hash-pjw.h"
 #include "quote.h"
+#include "quotearg.h"
 #include "same.h"
 #include "savedir.h"
 #include "stat-time.h"
@@ -50,6 +57,7 @@
 #include "utimens.h"
 #include "xreadlink.h"
 #include "yesno.h"
+#include "xstrtol.h"
 
 #ifndef HAVE_FCHMOD
 # define HAVE_FCHMOD false
@@ -191,6 +199,228 @@
   return ok;
 }
 
+/* This function check:
+     - src dim tot
+     - console line lenght
+   If the progress flag is set */
+
+int
+progress_bar_check(const char *src_name, size_t dim_tot)
+{
+  size_t line_length = 0;
+
+  /* Check:
+     if filesize is very little, exit */
+  if (! (dim_tot / 1024))
+    {
+      printf("%s: is very little (1 KB required), " \
+             "you can't to use progress bar\n",
+             src_name);  
+      
+      return -1;
+    }
+
+  /* By ls.c code */  
+  {
+    char const *p = getenv("COLUMNS");
+    
+    if (p && *p)
+      {
+        unsigned long int tmp_ulong;
+        
+       if (xstrtoul (p, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
+            && 0 < tmp_ulong && tmp_ulong <= SIZE_MAX)
+          line_length = tmp_ulong;
+        else
+          error(0, 0,
+                _("ignoring invalid width in environment variable
COLUMNS: %s"),
+                quotearg (p));
+      }
+  }
+
+#ifdef TIOCGWINSZ
+  {
+    struct winsize ws;
+
+    if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1
+       && 0 < ws.ws_col && ws.ws_col == (size_t) ws.ws_col)
+      line_length = ws.ws_col;
+  }
+#endif
+
+  if (line_length < 125)
+    {
+      if (! line_length)
+        printf("(null): COLUMNS not found, " \
+              "you can't to use progress bar\n");
+      else 
+        printf("%d: console line lenght is very short, " \
+               "you can't to use progress bar\n", line_length);
+
+      return -1;
+    }
+
+  return 0;
+}
+
+/* This function displays a progress bar
+   if the progress flag is set.
+   It uses a 1:2 scales. */
+
+void 
+progress_bar_print(size_t dim_tot, size_t dim_cur)
+{
+  int i;
+  size_t per_tot, per_cur, per_tot_scl, per_cur_scl;
+
+  /* Size in KiB */
+  dim_tot /= 1024;
+  dim_cur /= 1024;
+
+  per_tot = 100;       
+  /* total percentage */
+  per_cur = (per_tot * dim_cur) / dim_tot; 
+  /* current percentage */
+
+  /* 1:2 scale */
+  per_tot_scl = per_tot / 2;
+  per_cur_scl = per_cur / 2;
+
+  /* Refresh ther bar indicator */
+  printf("\r [");
+
+  /* Display the bar indicator:
+     - =   : indicates a part the bar
+     - >   : indicates the end of the bar 
+             (if it's finish, convert '>' to '='*/
+  for (i = 0; i < per_cur_scl; i++)
+    if ((i + 1) == per_cur_scl)
+      if (per_cur_scl == 50)
+        putchar('=');
+      else
+        putchar('>');
+    else
+      putchar('=');
+
+  for (i = per_cur_scl; i < per_tot_scl; i++)
+    putchar(' ');
+
+  printf("] %3d\% | ", per_cur);
+  
+  fflush(stdout);
+}
+
+/* This function displays speed copy 
+   if the progress flag is set. */
+
+void
+progress_bar_print_speed(struct tm *tm_init, 
+                        size_t *speed, size_t *speed_last) 
+{
+  time_t time_cur;
+  struct tm tm_cur;
+  size_t speed_si;
+  float speed_last_, speed_si_;
+  int type = 0;
+  
+  time_cur = time(NULL);
+  tm_cur = *(struct tm *) localtime(&time_cur);
+
+  if (tm_init->tm_sec == tm_cur.tm_sec)
+    {
+      if (tm_init->tm_sec == 60)
+        tm_init->tm_sec = 0;
+      else
+        tm_init->tm_sec += 1;
+       
+      *speed_last = *speed;
+      *speed = 0;
+    }
+  else if (tm_init->tm_sec != tm_cur.tm_sec + 1)
+      /* If the disk crashes, again */
+      tm_init->tm_sec = tm_cur.tm_sec + 1;
+     
+  if (*speed_last == 0)
+    *speed_last = *speed;
+
+  /* Convert to max type */
+  for (speed_si = 1024; *speed_last / speed_si; speed_si *= 1024)
+    type++;
+
+  speed_si_ = (float) (speed_si / 1024);
+  speed_last_ = ((float) *speed_last) / speed_si_;
+
+  printf("%12.02f %s | ", speed_last_,
+        type == 1 ? "KiB/s" : type == 2 ? "MiB/s" :
+         type == 3 ? "GiB/s" : type == 4 ? "TiB/s" :
+         type == 5 ? "PiB/s" : type == 6 ? "EiB/s" : 
+        type == 7 ? "ZiB/s" : "YiB/s");
+         
+  fflush(stdout);
+}
+
+/* This function displays source/dest size files
+   if the progress flag is set. */
+
+void
+progress_bar_print_size(size_t dim_tot, size_t dim_cur)
+{
+  size_t dim_si;
+  float dim_tot_, dim_cur_, dim_si_;
+  int type = 0;
+
+  /* Convert to max type */
+  for (dim_si = 1024; dim_tot / dim_si; dim_si *= 1024)
+    type++;
+
+  dim_si_ = (float) (dim_si / 1024);
+  dim_tot_ = ((float) dim_tot) / dim_si_;
+  dim_cur_ = ((float) dim_cur) / dim_si_;
+
+  printf("%10.02f/%.02f %s | ", dim_cur_, dim_tot_, 
+         type == 1 ? "KiB" : type == 2 ? "MiB" : 
+        type == 3 ? "GiB" : type == 4 ? "TiB" : 
+        type == 5 ? "PiB" : type == 6 ? "EiB" :
+        type == 7 ? "ZiB" : "YiB");
+  
+  fflush(stdout);
+}
+
+/* This function displays ETA copy 
+   if the progress flag is set. */
+
+void
+progress_bar_print_eta(size_t dim_tot, size_t dim_cur, 
+                      size_t speed_last)
+{
+  size_t dim_diff = 0,
+        eta = 0;
+  int sec, min, hour;
+
+  /* Convert in KiB */
+  dim_tot /= 1024;
+  dim_cur /= 1024;
+
+  dim_diff = dim_tot - dim_cur;
+  speed_last /= 1024;
+
+  /* speed_last : 1 sec = dim_diff : eta 
+   
+     eta = 1 * dim_diff
+           ------------
+           speed_last  */
+
+  eta = dim_diff / speed_last;
+
+  min = eta / 60;
+  sec = eta - (min * 60);
+  hour = min / 60;
+
+  printf("ETA: %02d:%02d:%02d  ", hour, min, sec);
+
+  fflush(stdout);
+}
+
 /* Copy a regular file from SRC_NAME to DST_NAME.
    If the source file contains holes, copies holes and blocks of zeros
    in the source file as holes in the destination file.
@@ -222,6 +452,15 @@
   off_t n_read_total = 0;
   bool last_write_made_hole = false;
   bool make_holes = false;
+  /* Progress bar */
+  int pb_check;
+  size_t dim_tot = 0, 
+         dim_cur = 0;
+  /* speed time */
+  time_t time_init;
+  struct tm tm_init;
+  size_t speed = 0,
+         speed_last = 0;
 
   source_desc = open (src_name, O_RDONLY | O_BINARY);
   if (source_desc < 0)
@@ -326,6 +565,18 @@
   buf = alloca (buf_size + sizeof (int) + buf_alignment - 1);
   buf = ptr_align (buf, buf_alignment);
 
+  if (x->progress)
+    {
+      dim_tot = src_sb->st_size;
+
+      if (! (pb_check = progress_bar_check(src_name, dim_tot)))
+        {
+         time_init = time(NULL);
+          tm_init = *(struct tm *) localtime(&time_init);
+          tm_init.tm_sec += 1;
+        }
+    }
+
   for (;;)
     {
       ssize_t n_read = read (source_desc, buf, buf_size);
@@ -388,10 +639,34 @@
              return_val = false;
              goto close_src_and_dst_desc;
            }
+
+         /* if the progress flag is set, it uses a progress bar */
+         if (x->progress && ! pb_check)
+           {
+             dim_cur += n;
+
+             /* print progress bar */
+             progress_bar_print(dim_tot, dim_cur);
+
+             speed += n;
+             
+             /* print progress bar speed */
+             progress_bar_print_speed(&tm_init, &speed, &speed_last);
+
+             /* print progress bar size */
+             progress_bar_print_size(dim_tot, dim_cur);
+           
+             /* print progress bar ETA */
+             progress_bar_print_eta(dim_tot, dim_cur, speed_last);
+           }
+
          last_write_made_hole = false;
        }
     }
 
+  if (x->progress && ! pb_check)
+    putchar('\n');
+
   /* If the file ends with a `hole', something needs to be written at
      the end.  Otherwise the kernel would truncate the file at the end
      of the last write operation.  */

--- copy.h      2005-07-03 11:31:19.000000000 +0200
+++ copy.h      2007-12-21 02:31:22.000000000 +0100
@@ -83,6 +83,9 @@
 {
   enum backup_type backup_type;
 
+  /* If true, Display a progress bar */
+  bool progress;
+
   /* If true, copy all files except (directories and, if not
dereferencing
      them, symbolic links,) as if they were regular files.  */
   bool copy_as_regular;

--- cp.c        2005-09-16 09:50:33.000000000 +0200
+++ cp.c        2007-12-30 23:48:48.000000000 +0100
@@ -117,6 +117,7 @@
 {
   {"archive", no_argument, NULL, 'a'},
   {"backup", optional_argument, NULL, 'b'},
+  {"progress", no_argument, NULL, 'B'},
   {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION},
   {"dereference", no_argument, NULL, 'L'},
   {"force", no_argument, NULL, 'f'},
@@ -170,6 +171,8 @@
   -a, --archive                same as -dpR\n\
       --backup[=CONTROL]       make a backup of each existing
destination file\n\
   -b                           like --backup but does not accept an
argument\n\
+  -B  --progress               show a progress bar\n\
+                                 (filesize > 1 KB / console line lenght
>= 125)\n\
       --copy-contents          copy contents of special files when
recursive\n\
   -d                           same as --no-dereference --preserve=link
\n\
 "), stdout);
@@ -672,6 +675,7 @@
 static void
 cp_option_init (struct cp_options *x)
 {
+  x->progress = false;
   x->copy_as_regular = true;
   x->dereference = DEREF_UNDEFINED;
   x->unlink_dest_before_opening = false;
@@ -811,7 +815,7 @@
      we'll actually use backup_suffix_string.  */
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
-  while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T",
+  while ((c = getopt_long (argc, argv, "abBdfHilLprst:uvxPRS:T",
                           long_opts, NULL))
         != -1)
     {
@@ -838,6 +842,10 @@
            version_control_string = optarg;
          break;
 
+       case 'B':
+         x.progress = true;
+         break;
+
        case COPY_CONTENTS_OPTION:
          copy_contents = true;
          break;

Thank You
Andrea

Attachment: cp-progress_bar-coreutils-5.97.tar.gz
Description: application/compressed-tar

Attachment: cp-progress_bar-coreutils-6.9.tar.gz
Description: application/compressed-tar


reply via email to

[Prev in Thread] Current Thread [Next in Thread]