Logo Search packages:      
Sourcecode: yencode version File versions

meter.c

/**************************************************************************************************
      $Header: /pub/cvsroot/yencode/src/ypost/meter.c,v 1.2 2002/03/21 04:58:31 bboy Exp $
      Routines used by `ypost' to output progress meters.

      Copyright (C) 2002  Don Moore <bboy@bboy.net>

      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at Your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with this program; if not, write to the Free Software
      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "ypost.h"

static int  screen_width = -1;                                                            /* Var for holding screen width */
struct timeval meter_start;                                                               /* Time meter started counting */
struct timeval meter_last;                                                                      /* Last time meter was displayed */
static char meter_text[METER_MAX + 1];                                              /* Current meter description */
static unsigned long meter_current = 0, meter_total = 0;          /* Meter current/total */
static int  meter_width = -1;                                                             /* Current meter width */
static void meter_redraw(void);


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      SET_SCREEN_WIDTH
      Handler for SIGWINCH - sets the screen width.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
set_screen_width(int signo)
{
      screen_width = get_screen_width();
      meter_redraw();
      return;
}
/*--- set_screen_width() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      METER
      Outputs a progress meter.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
meter(unsigned long current, unsigned long total, const char *fmt, ...)
{
      struct timeval now;
      va_list     ap;
      int         textmsg_len;
      char        meterbuf[METER_MAX + 1], dotbox[DOTBOX_MAX + 1];
      int         dotbox_width;
      int         pct = 0, fill = 0;
      char        speedbuf[30], etabuf[30];

      if (!isatty(STDOUT_FILENO) || !err_verbose || !screen_width)
            return;
      if (screen_width == -1 && !(screen_width = get_screen_width()))
            return;

      gettimeofday(&now, NULL);
      if (tvdiff(&meter_last, &now) < 0.2)
            return;
      meter_last.tv_sec = now.tv_sec;
      meter_last.tv_usec = now.tv_usec;

      if (meter_width)
            fwrite("\r", sizeof(char), 1, stdout);
      if (!meter_start.tv_sec)
            gettimeofday(&meter_start, NULL);

      va_start(ap, fmt);
      textmsg_len = vsnprintf(meter_text, sizeof(meter_text), fmt, ap);
      va_end(ap);

      /* Set width of dotbox and make sure it's a reasonable value */
      dotbox_width = (screen_width - 1) - textmsg_len - 10;
      if (dotbox_width < DOTBOX_MIN)
            return;
      if (dotbox_width > DOTBOX_MAX)
            dotbox_width = DOTBOX_MAX;

      *etabuf = '\0';
      *speedbuf = '\0';

      /* Get percentage complete */
      pct = (total) ? (int)(100.0 * current / total) : 0;

      /* If we have plenty of room, also output other helpful stats */
      if ((dotbox_width > DOTBOX_EXTRA_STATS) && total && (current > 1024))
      {
            float elapsed = timer_elapsed(&meter_start);
            float k_sec = (elapsed) ? (float)((float)current / elapsed) / 1024.0 : 0.0;
            int   eta_s = (elapsed) ? (int)((100.0 - pct) * (float)((float)elapsed / (float)pct)): 0;
            int   eta_h, eta_m;

            if (elapsed)
            {
                  if (k_sec > 1024.0)
                        dotbox_width -= snprintf(speedbuf, sizeof(speedbuf), " %6.1fM/s", (float)(k_sec / 1024.0));
                  else
                        dotbox_width -= snprintf(speedbuf, sizeof(speedbuf), " %6.1fk/s", k_sec);

                  eta_h = eta_s / 3600, eta_s %= 3600;
                  eta_m = eta_s / 60, eta_s %= 60;
                  if (eta_s >= 0 && eta_h > 0)
                        dotbox_width -= snprintf(etabuf, sizeof(etabuf), " ETA: %02d:%02d:%02d", eta_h, eta_m, eta_s);
                  else if (eta_s >= 0)
                        dotbox_width -= snprintf(etabuf, sizeof(etabuf), "    ETA: %02d:%02d", eta_m, eta_s);
            }
      }

      /* Construct dotbox */
      memset(dotbox, ' ', dotbox_width);
      dotbox[dotbox_width] = '\0';
      if (total)
      {
            fill = (int)((dotbox_width / 100.0) * pct);
            if (fill > dotbox_width)
                  fill = dotbox_width;
            memset(dotbox, '=', fill);
      }

      /* Save values */
      meter_current = current;
      meter_total = total;

      /* Output meter */
      meter_width = snprintf(meterbuf, sizeof(meterbuf),
                  "%s [%s] %3d%%%s%s ", meter_text, dotbox, pct, speedbuf, etabuf);

      fwrite(meterbuf, meter_width * sizeof(char), 1, stdout);
      fflush(stdout);
}
/*--- meter() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      METER_CLEAR
      Clears the progress meter if any is on screen.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
meter_clear(void)
{
      char buf[METER_MAX + 3];

      if (!isatty(STDOUT_FILENO) || !err_verbose || !screen_width || meter_width <= 0)
            return;

      memset(buf, ' ', meter_width);
      fwrite("\r", sizeof(char), 1, stdout);
      fwrite(buf, meter_width * sizeof(char), 1, stdout);
      fwrite("\r", sizeof(char), 1, stdout);
      fflush(stdout);

      meter_width = 0;
      meter_start.tv_sec = meter_start.tv_usec = 0;
      meter_last.tv_sec = meter_last.tv_usec = 0;
      meter_current = meter_total = 0;

      fflush(stdout);
}
/*--- meter_clear() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      METER_REDRAW
      Redraws the current meter (if the window size changed)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
meter_redraw(void)
{
      char buf[METER_MAX + 3];

      if (!isatty(STDOUT_FILENO) || meter_width <= 0)
            return;

      memset(buf, ' ', meter_width);
      fwrite("\r", sizeof(char), 1, stdout);
      fwrite(buf, meter_width * sizeof(char), 1, stdout);
      fwrite("\r", sizeof(char), 1, stdout);
      fflush(stdout);

      meter_width = 0;
      meter_last.tv_sec = meter_last.tv_usec = 0;

      meter(meter_current, meter_total, "%s", meter_text);
}
/*--- meter_redraw() ----------------------------------------------------------------------------*/

/* vi:set ts=3: */

Generated by  Doxygen 1.6.0   Back to index