/**************************************************************************************************
$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: */
syntax highlighted by Code2HTML, v. 0.9.1