display.c

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include "headers.h"
00004 #include "types.h"
00005 #include "error.h"
00006 #include "io.h"
00007 #include "display.h"
00008 
00009 #ifdef HAVE_UNISTD_H
00010 #       ifdef HAVE_SIGNAL_H
00011 #               ifdef HAVE_TERMIOS_H
00012 #                       ifdef HAVE_SYS_IOCTL_H
00013 #                               define CAN_RESIZE
00014 #                       endif
00015 #               endif
00016 #       endif
00017 #endif
00018 
00019 display d;
00020 
00021 #ifdef CAN_RESIZE
00022 static void displayGetSize(void)
00023 {
00024         struct winsize size;
00025 
00026         if (d.manual_width)
00027                 return;
00028         if (ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&size) < 0)
00029                 return;
00030         d.screen_width = size.ws_col;
00031         if (d.screen_width_minus_one)
00032                 d.screen_width--;
00033 }
00034 
00035 int displaySetSigWinch(void);
00036 
00037 static void sig_winch(int signo)
00038 {
00039         displayGetSize();
00040         displaySetSigWinch();
00041 }
00042 
00043 int displaySetSigWinch(void)
00044 {
00045         if (isatty(STDERR_FILENO) != 0) {
00046                 if (signal(SIGWINCH, sig_winch) == SIG_ERR) {
00047                         return(1);
00048                 }
00049         }
00050         return(0);
00051 }
00052 #endif
00053 
00054 int displayInit(void)
00055 {
00056         int c;
00057 
00058         d.start_time = 0;
00059         d.total_time = 0;
00060         d.current_time = 0;
00061         d.elapsed_time = 0;
00062         d.percent_complete = 0.0;
00063         d.display_interval = 1;
00064         d.overtime_flag = 0;
00065         d.k = 1024;
00066         d.twiddle = '-';
00067         for (c = 0; c < 80; c++)
00068                 d.title[c] = 0;
00069         d.screen_width = 79;
00070         d.manual_width = 0;
00071         d.screen_width_minus_one = DEFAULT_SW_MINUS_ONE;
00072         d.display_twiddle = DEFAULT_DISPLAY_TWIDDLE;
00073         d.display_title = 1;
00074         d.display_datacount = 1;
00075         d.display_throughput = 1;
00076         d.display_time = 1;
00077         d.display_elapsed_only = 0;
00078         d.display_percent = 1;
00079         d.display_bar = 1;
00080         d.display_summary = 1;
00081         d.display_ansi = 0;
00082         d.display_throughput_bits = 0;
00083         d.display_count_bits = 0;
00084         d.space_bg_color = 0;
00085         d.twiddle_fg_color = ""; /* green */
00086         d.twiddle_bg_color = 0;
00087         d.twiddle_fg_bold = 0;
00088         d.title_fg_color = ""; /* yellow */
00089         d.title_bg_color = 0;
00090         d.title_fg_bold = 0;
00091         d.datacount_fg_color = ""; /* green */
00092         d.datacount_bg_color = 0;
00093         d.datacount_fg_bold = 1; /* bold */
00094         d.throughput_label_fg_color = 0;
00095         d.throughput_label_bg_color = 0;
00096         d.throughput_label_fg_bold = 0;
00097         d.throughput_fg_color = ""; /* green */
00098         d.throughput_bg_color = 0;
00099         d.throughput_fg_bold = 1; /* bold */
00100         d.time_label_fg_color = 0;
00101         d.time_label_bg_color = 0;
00102         d.time_label_fg_bold = 0;
00103         d.time_fg_color = ""; /* green */
00104         d.time_bg_color = 0;
00105         d.time_fg_bold = 1; /* bold */
00106         d.percent_fg_color = ""; /* green */
00107         d.percent_bg_color = 0;
00108         d.percent_fg_bold = 1; /* bold */
00109         d.bar_fg_color = ""; /* yellow */
00110         d.bar_bg_color = 0;
00111         d.bar_fg_bold = 1; /* bold */
00112         d.barbrace_fg_color = ""; /* red */
00113         d.barbrace_bg_color = 0;
00114         d.barbrace_fg_bold = 0;
00115         d.total_display_percent = 1;
00116         return(0);
00117 }
00118 
00119 int displayBegin(void)
00120 {
00121         d.start_time = time(0);
00122         d.current_time = time(0);
00123 
00124 #ifdef CAN_RESIZE
00125         displayGetSize();
00126         if (displaySetSigWinch() != 0) {
00127                 print_error(stderr, "Could not install SIGWINCH signal handler");
00128                 print_esup(stderr, "Window resize events will be ignored");
00129         }
00130 #endif
00131 
00132         return(0);
00133 }
00134 
00135 #define sec_per_hour 3600
00136 #define sec_per_minute 60
00137 
00138 int calculateCountDisplay(
00139         uint64 *total_count,
00140         char **total_count_units,
00141         float *short_count,
00142         char **short_count_units
00143         )
00144 {
00145         uint64 num = 0;
00146         uint64 div = 1;
00147 
00148         *total_count = io.total_write;
00149         if (d.display_count_bits)
00150                 *total_count_units = "b";
00151         else
00152                 *total_count_units = "B";
00153 
00154         num = io.total_write;
00155 
00156         if (d.display_count_bits) {
00157                 *short_count_units = "b ";
00158                 num *= 8;
00159         }
00160         else {
00161                 *short_count_units = "B ";
00162         }
00163 
00164         *short_count = 0.0;
00165 
00166         if (num >= d.k) {
00167                 if (d.display_count_bits)
00168                         *short_count_units = "Kb";
00169                 else
00170                         *short_count_units = "KB";
00171                 div = d.k;
00172         }
00173         if (num >= (d.k * d.k)) {
00174                 if (d.display_count_bits)
00175                         *short_count_units = "Mb";
00176                 else
00177                         *short_count_units = "MB";
00178                 num /= d.k;
00179         }
00180         if (num >= (d.k * d.k)) {
00181                 if (d.display_count_bits)
00182                         *short_count_units = "Gb";
00183                 else
00184                         *short_count_units = "GB";
00185                 num /= d.k;
00186         }
00187         if (num >= (d.k * d.k)) {
00188                 if (d.display_count_bits)
00189                         *short_count_units = "Tb";
00190                 else
00191                         *short_count_units = "TB";
00192                 num /= d.k;
00193         }
00194         if (num >= (d.k * d.k)) {
00195                 if (d.display_count_bits)
00196                         *short_count_units = "Pb";
00197                 else
00198                         *short_count_units = "PB";
00199                 num /= d.k;
00200         }
00201         if (num >= (d.k * d.k)) {
00202                 if (d.display_count_bits)
00203                         *short_count_units = "Eb";
00204                 else
00205                         *short_count_units = "EB";
00206                 num /= d.k;
00207         }
00208 
00209         *short_count = ((float)num / div);
00210         return(0);
00211 }
00212 
00213 int calculateThroughputDisplay(
00214         uint64 *total_throughput,
00215         char **total_throughput_units,
00216         float *short_throughput,
00217         char **short_throughput_units
00218         )
00219 {
00220         uint64 num = 0;
00221         uint64 div = 1;
00222 
00223         if (d.elapsed_time > 0) {
00224                 *total_throughput = io.total_write / d.elapsed_time;
00225                 num = io.total_write / d.elapsed_time;
00226         }
00227         else {
00228                 *total_throughput = 0;
00229                 num = 0;
00230         }
00231         if (d.display_throughput_bits) {
00232                 *total_throughput *= 8;
00233                 *total_throughput_units = "b";
00234                 *short_throughput_units = "b/s ";
00235                 num *= 8;
00236         }
00237         else {
00238                 *total_throughput_units = "B";
00239                 *short_throughput_units = "B/s ";
00240         }
00241 
00242         *short_throughput = 0.0;
00243 
00244         if (num >= d.k) {
00245                 if (d.display_throughput_bits)
00246                         *short_throughput_units = "Kb/s";
00247                 else
00248                         *short_throughput_units = "KB/s";
00249                 div = d.k;
00250         }
00251         if (num >= (d.k * d.k)) { 
00252                 if (d.display_throughput_bits)
00253                         *short_throughput_units = "Mb/s";
00254                 else
00255                         *short_throughput_units = "MB/s";
00256                 num /= d.k;
00257         }
00258         if (num >= (d.k * d.k)) { 
00259                 if (d.display_throughput_bits)
00260                         *short_throughput_units = "Gb/s";
00261                 else
00262                         *short_throughput_units = "GB/s";
00263                 num /= d.k; 
00264         }
00265         if (num >= (d.k * d.k)) { 
00266                 if (d.display_throughput_bits)
00267                         *short_throughput_units = "Tb/s";
00268                 else
00269                         *short_throughput_units = "TB/s";
00270                 num /= d.k;
00271         }
00272         *short_throughput = ((float)num / div);
00273         return(0);
00274 }
00275 
00276 int calculateTimeDisplay(uint64 *sptr, uint64 *mptr, uint64 *hptr)
00277 {
00278         if (*sptr >= sec_per_hour) {
00279                 *hptr = *sptr / sec_per_hour;
00280                 *sptr -= *hptr * sec_per_hour;
00281         }
00282         if (*sptr >= sec_per_minute) {
00283                 *mptr = *sptr / sec_per_minute;
00284                 *sptr -= *mptr * sec_per_minute;
00285         }
00286         return(0);
00287 }
00288 
00289 int calculatePercentComplete(void)
00290 {
00291         if (io.total_size_known && (io.total_size > 0)) {
00292                 d.percent_complete = (float)(io.total_write * 100.0 / io.total_size);
00293                 if (d.percent_complete < 0) {
00294                         d.percent_complete = 9999.9;
00295                 }
00296         }
00297         return(0);
00298 }
00299 
00300 void displayAnsiNormal(void)
00301 {
00302         if (d.display_ansi) {
00303                 fprintf(stderr, "");
00304         }
00305 }
00306 
00307 void displayAnsi(char *fg, char *bg, int b)
00308 {
00309         if (d.display_ansi) {
00310                 if (fg != 0) {
00311                         fprintf(stderr, fg);
00312                 }
00313                 if (bg != 0) {
00314                         fprintf(stderr, bg);
00315                 }
00316                 if (b) {
00317                         fprintf(stderr, "");
00318                 }
00319         }
00320 }
00321 
00322 void displayTwiddle(void)
00323 {
00324         static uint64 last_write = 0;
00325         static time_t last_time = 0;
00326 
00327         if (last_time == 0) last_time = time(0);
00328         if (last_time == time(0)) return;
00329         if (last_write == io.total_write) return;
00330 
00331         last_time = time(0);
00332         last_write = io.total_write;
00333 
00334         switch (d.twiddle) {
00335                 case '\\': d.twiddle = '|';  break;
00336                 case '|':  d.twiddle = '/';  break;
00337                 case '/':  d.twiddle = '-';  break;
00338                 case '-':  d.twiddle = '\\'; break;
00339         }
00340         displayAnsi(d.twiddle_fg_color, d.twiddle_bg_color, d.twiddle_fg_bold);
00341         fprintf(stderr, "%c\r", d.twiddle);
00342 }
00343 
00344 int displayPrint(void)
00345 {
00346         uint64 eta = 0;
00347         uint64 total_throughput = 0;
00348         char *total_throughput_units = "";
00349         float short_throughput = 0.0;
00350         char* short_throughput_units = "";
00351         uint64 hours = 0;
00352         uint64 minutes = 0;
00353         uint64 seconds = 0;
00354         uint64 total_count = 0;
00355         char *total_count_units = "";
00356         float short_count = 0.0;
00357         char *short_count_units = "";
00358         char *time_title = "eta";
00359         int screen_used = 0;
00360         int this_width = 0;
00361 
00362         d.current_time = time(0);
00363         d.elapsed_time = d.current_time - d.start_time;
00364 
00365         if (
00366                 calculateThroughputDisplay(
00367                         &total_throughput,
00368                         &total_throughput_units,
00369                         &short_throughput,
00370                         &short_throughput_units
00371                         )
00372                 != 0
00373                 )
00374         {
00375                 return(1);
00376         }
00377 
00378         if (calculatePercentComplete() != 0) {
00379                 return(1);
00380         }
00381 
00382         if ((io.total_size_known == 1) && (!d.display_elapsed_only)) {
00383                 if (io.total_write > 0) {
00384                         if (io.total_size >= io.total_write) {
00385                                 if (d.percent_complete > 0.0) {
00386                                         eta = 
00387                                                 (uint64)(
00388                                                         100 * d.elapsed_time / d.percent_complete
00389                                                 )
00390                                                 - d.elapsed_time;
00391                                 }
00392                                 else {
00393                                         eta = (uint64)(-1);
00394                                 }
00395                         }
00396                         else {
00397                                 if (!d.overtime_flag) {
00398                                         d.overtime_flag = 1;
00399                                         d.total_time = d.elapsed_time;
00400                                 }
00401                                 eta = d.elapsed_time - d.total_time;
00402                                 time_title = "ovr";
00403                         }
00404                 }
00405                 else {
00406                         eta = 0;
00407                 }
00408                 seconds = eta;
00409         }
00410         else
00411         {
00412                 seconds = d.elapsed_time;
00413                 time_title = "elapsed";
00414         }
00415         if (calculateTimeDisplay(&seconds, &minutes, &hours) != 0) {
00416                 return(1);
00417         }
00418 
00419         if (
00420                 calculateCountDisplay(
00421                         &total_count,
00422                         &total_count_units,
00423                         &short_count,
00424                         &short_count_units)
00425                 != 0)
00426         {
00427                 return(1);
00428         }
00429 
00430         /*
00431          * Display twiddle
00432          */
00433         this_width = 1;
00434         if ((d.display_twiddle) && (screen_used+this_width < d.screen_width)) {
00435                 displayAnsi(
00436                         d.twiddle_fg_color, 
00437                         d.twiddle_bg_color, 
00438                         d.twiddle_fg_bold);
00439                 fprintf(stderr, "%c", d.twiddle);
00440                 screen_used += this_width;
00441         }
00442 
00443         /*
00444          * Display title, if set
00445          */
00446         if ((d.display_title) && (d.title[0] != 0)) {
00447                 this_width = strlen(d.title);
00448                 if (screen_used > 0) {
00449                         displayAnsiNormal();
00450                         displayAnsi(0,d.space_bg_color,0);
00451                         fprintf(stderr, " ");
00452                         this_width++;
00453                 }
00454                 displayAnsiNormal();
00455                 displayAnsi(
00456                         d.title_fg_color,
00457                         d.title_bg_color,
00458                         d.title_fg_bold);
00459                 fprintf(stderr, "%s", d.title);
00460                 screen_used += this_width;
00461         }
00462 
00463         /*
00464          * Display data count
00465          */
00466         this_width = 8;
00467         if (screen_used > 0)
00468                 this_width++;
00469         if ((d.display_datacount) && (screen_used+this_width < d.screen_width)) {
00470                 if (screen_used > 0) {
00471                         displayAnsiNormal();
00472                         displayAnsi(0,d.space_bg_color,0);
00473                         fprintf(stderr, " ");
00474                 }
00475                 displayAnsiNormal();
00476                 displayAnsi(
00477                         d.datacount_fg_color,
00478                         d.datacount_bg_color,
00479                         d.datacount_fg_bold);
00480                 if (short_count > 9999.9) {
00481                         fprintf(stderr, "+999.9%2.2s", short_count_units);
00482                 }
00483                 else {
00484                         fprintf(stderr, "%6.1f%2.2s", short_count, short_count_units);
00485                 }
00486                 screen_used += this_width;
00487         }
00488                 
00489         /*
00490          * Display throughput
00491          */
00492         this_width = 13;
00493         if (!d.display_datacount)
00494                 this_width -= 3;
00495         if (screen_used > 0)
00496                 this_width++;
00497         if ((d.display_throughput) && (screen_used+this_width < d.screen_width)) {
00498                 if (screen_used > 0) {
00499                         displayAnsiNormal();
00500                         displayAnsi(0,d.space_bg_color,0);
00501                         fprintf(stderr, " ");
00502                 }
00503                 if (d.display_datacount) {
00504                         displayAnsiNormal();
00505                         displayAnsi(
00506                                 d.throughput_label_fg_color,
00507                                 d.throughput_label_bg_color,
00508                                 d.throughput_label_fg_bold);
00509                         fprintf(stderr, "at");
00510                         displayAnsiNormal();
00511                         displayAnsi(0,d.space_bg_color,0);
00512                         fprintf(stderr, " ");
00513                 }
00514                 displayAnsiNormal();
00515                 displayAnsi(
00516                         d.throughput_fg_color,
00517                         d.throughput_bg_color,
00518                         d.throughput_fg_bold);
00519                 fprintf(stderr, "%6.1f%4.4s", short_throughput, short_throughput_units);
00520                 screen_used += this_width;
00521         }
00522 
00523         /*
00524          * Display time
00525          */
00526         this_width = 11+strlen(time_title);
00527         if (screen_used > 0)
00528                 this_width += 2;
00529         if ((d.display_time) && (screen_used+this_width < d.screen_width)) {
00530                 if (screen_used > 0) {
00531                         displayAnsiNormal();
00532                         displayAnsi(0,d.space_bg_color,0);
00533                         fprintf(stderr, "  ");
00534                 }
00535                 displayAnsiNormal();
00536                 displayAnsi(
00537                         d.time_label_fg_color,
00538                         d.time_label_bg_color,
00539                         d.time_label_fg_bold);
00540                 fprintf(stderr, "%s:", time_title);
00541                 displayAnsiNormal();
00542                 displayAnsi(0,d.space_bg_color,0);
00543                 fprintf(stderr, " ");
00544                 displayAnsiNormal();
00545                 displayAnsi(
00546                         d.time_fg_color,
00547                         d.time_bg_color,
00548                         d.time_fg_bold);
00549                 if (hours > 99) {
00550                         fprintf(stderr, "+99:99:99");
00551                 }
00552                 else
00553                         fprintf(stderr, "%3u:%2.2u:%2.2u", 
00554                                 (unsigned int)hours, 
00555                                 (unsigned int)minutes, 
00556                                 (unsigned int)seconds);
00557                 screen_used += this_width;
00558         }
00559 
00560         /*
00561          * Display percent
00562          */
00563         this_width = 5;
00564         if (screen_used > 0)
00565                 this_width++;
00566         if ((d.display_percent) && (io.total_size_known)
00567                 && (screen_used+this_width < d.screen_width))
00568         {
00569                 if (screen_used > 0) {
00570                         displayAnsiNormal();
00571                         displayAnsi(0,d.space_bg_color,0);
00572                         fprintf(stderr, " ");
00573                 }
00574                 displayAnsiNormal();
00575                 displayAnsi(
00576                         d.percent_fg_color,
00577                         d.percent_bg_color,
00578                         d.percent_fg_bold);
00579                 if (d.percent_complete > 999) {
00580                         fprintf(stderr, "+999%%");
00581                 }
00582                 else {
00583                         fprintf(stderr, "%4d%%", (int)d.percent_complete);
00584                 }
00585                 screen_used += this_width;
00586         }
00587 
00588         /*
00589          * Display progress bar
00590          */
00591         this_width = 5;
00592         if (screen_used > 0)
00593                 this_width++;
00594         if ((d.display_bar) && (io.total_size_known)
00595                 && (screen_used+this_width < d.screen_width))
00596         {
00597                 int c;
00598                 int line_length;
00599                 int completed_length = 0;
00600 
00601                 if (screen_used > 0) {
00602                         displayAnsiNormal();
00603                         displayAnsi(0,d.space_bg_color,0);
00604                         fprintf(stderr, " ");
00605                         screen_used++;
00606                 }
00607                 this_width = d.screen_width - screen_used + 1;
00608                 line_length = this_width - 3;
00609                 completed_length = line_length * d.percent_complete / 100;
00610                 displayAnsiNormal();
00611                 displayAnsi(
00612                         d.barbrace_fg_color,
00613                         d.barbrace_bg_color,
00614                         d.barbrace_fg_bold);
00615                 fprintf(stderr, "[");
00616                 displayAnsiNormal();
00617                 displayAnsi(
00618                         d.bar_fg_color,
00619                         d.bar_bg_color,
00620                         d.bar_fg_bold);
00621                 for (c = 0; c < line_length; c++) {
00622                         if (c <= completed_length) {
00623                                 fprintf(stderr, "=");
00624                         }
00625                         else {
00626                                 fprintf(stderr, " ");
00627                         }
00628                 }
00629                 displayAnsiNormal();
00630                 displayAnsi(
00631                         d.barbrace_fg_color,
00632                         d.barbrace_bg_color,
00633                         d.barbrace_fg_bold);
00634                 fprintf(stderr, "]");
00635         }
00636 
00637         displayAnsiNormal();
00638         fprintf(stderr, "\r");
00639 
00640         return(0);
00641 }
00642 
00643 int displayUpdate(void)
00644 {
00645         if (d.display_twiddle) displayTwiddle();
00646         if (time(0) < d.current_time + d.display_interval) return(0);
00647         if (displayPrint() != 0) return(1);
00648         return(0);
00649 }
00650 
00651 int displayEnd(void)
00652 {
00653         uint64 total_throughput = 0;
00654         char *total_throughput_units = "";
00655         float short_throughput = 0.0;
00656         char *short_throughput_units = "";
00657         uint64 total_count = 0;
00658         char *total_count_units = "";
00659         float short_count = 0.0;
00660         char *short_count_units = "";
00661         uint64 hours = 0;
00662         uint64 minutes = 0;
00663         uint64 seconds = 0;
00664 
00665         displayPrint();
00666         d.elapsed_time = d.current_time - d.start_time;
00667 
00668         if (calculatePercentComplete() != 0) {
00669                 return(1);
00670         }
00671 
00672         if (
00673                 calculateCountDisplay(
00674                         &total_count,
00675                         &total_count_units,
00676                         &short_count,
00677                         &short_count_units
00678                         )
00679                 != 0
00680                 )
00681         {
00682                 return(1);
00683         }
00684 
00685         if (
00686                 calculateThroughputDisplay(
00687                         &total_throughput,
00688                         &total_throughput_units,
00689                         &short_throughput,
00690                         &short_throughput_units
00691                         )
00692                 != 0
00693                 )
00694         {
00695                 return(1);
00696         }
00697 
00698         seconds = d.elapsed_time;
00699         if (calculateTimeDisplay(&seconds, &minutes, &hours) != 0) {
00700                 return(1);
00701         }
00702 
00703         fprintf(stderr, "\n");
00704         if (d.display_summary) {
00705                 fprintf(stderr, "Copied: %llu%s (%.1f%s)",
00706                         UINT64_CTYPE(total_count),
00707                         total_count_units,
00708                         short_count,
00709                         short_count_units
00710                         );
00711                 if (io.total_size_known && d.total_display_percent) {
00712                         fprintf(stderr, " (%d%% of expected input)", (int)d.percent_complete);
00713                 }
00714                 fprintf(stderr, "\n");
00715 
00716                 fprintf(stderr, "Time: ");
00717                 if (hours > 0) {
00718                         fprintf(stderr, "%3u:%2.2u:%2.2u", 
00719                                 (unsigned int)hours,
00720                                 (unsigned int)minutes,
00721                                 (unsigned int)seconds);
00722                 }
00723                 else if (minutes > 0) {
00724                         fprintf(stderr, "%2.2u:%2.2u",
00725                                 (unsigned int)minutes,
00726                                 (unsigned int)seconds);
00727                 }
00728                 else {
00729                         fprintf(stderr, "%2u seconds",
00730                                 (unsigned int)seconds);
00731                 }
00732                 fprintf(stderr, "\n");
00733 
00734                 if ((hours != 0) || (minutes != 0) || (seconds != 0)) {
00735                         fprintf(stderr, "Throughput: %llu%s (%.1f%s)\n\n",
00736                                 UINT64_CTYPE(total_throughput),
00737                                 total_throughput_units,
00738                                 short_throughput,
00739                                 short_throughput_units
00740                         );
00741                 }
00742                 else {
00743                         fprintf(stderr, "Throughput: (infinite)\n\n");
00744                 }
00745         }
00746 
00747         d.start_time = 0;
00748         
00749         return(0);
00750 }

Generated on Thu Jun 28 09:13:03 2007 for bar by  doxygen 1.5.1