⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 progressbar.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * progressbar.{cc,hh} -- element displays a progress bar on stderr * Eddie Kohler * * Copyright (c) 2001 International Computer Science Institute * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "progressbar.hh"#include <click/confparse.hh>#include <click/router.hh>#include <click/error.hh>#include <click/straccum.hh>#include <click/handlercall.hh>#ifdef HAVE_TERMIO_H# include <termio.h>#endif#include <termios.h>#include <unistd.h>#include <sys/ioctl.h>CLICK_DECLSProgressBar::ProgressBar()    : _status(ST_FIRST), _timer(this){}ProgressBar::~ProgressBar(){}intProgressBar::configure(Vector<String> &, ErrorHandler *){    return 0;}intProgressBar::initialize(ErrorHandler *errh){    Vector<String> conf;    configuration(conf);    _interval = 250;    _delay_ms = 0;    _active = true;    _size = -1;    String position_str, size_str;    bool check_stdout = false, have_size = false;    if (cp_va_parse(conf, this, errh,		    cpArgument, "position handler", &position_str,		    cpOptional,		    cpArgument, "size handler", &size_str,		    cpKeywords,		    "UPDATE", cpSecondsAsMilli, "update interval (s)", &_interval,		    "BANNER", cpString, "banner string", &_banner,		    "ACTIVE", cpBool, "start active?", &_active,		    "DELAY", cpSecondsAsMilli, "display delay (s)", &_delay_ms,		    "CHECK_STDOUT", cpBool, "check if stdout is terminal?", &check_stdout,		    cpConfirmKeywords,		    "FIXED_SIZE", cpDouble, "fixed size", &have_size, &_size,		    cpEnd) < 0)	return -1;    Vector<String> words;    cp_spacevec(size_str, words);    _first_pos_h = words.size();    cp_spacevec(position_str, words);    _es.assign(words.size(), 0);    _hs.assign(words.size(), 0);    for (int i = 0; i < words.size(); i++)	if (!cp_handler(words[i], HandlerCall::CHECK_READ, &_es[i], &_hs[i], this, errh))	    return -1;    if (!isatty(STDERR_FILENO) || (check_stdout && isatty(STDOUT_FILENO)))	_status = ST_DEAD;    else	_status = ST_FIRST;        _have_size = have_size;    _timer.initialize(this);    if (_active && _status != ST_DEAD)	_timer.schedule_now();    return 0;}voidProgressBar::cleanup(CleanupStage){    if (_status == ST_MIDDLE) {	_status = ST_DONE;	run_timer();    }}// Code based on the progress bar in the OpenSSH project's B<scp> program. Its// authors are listed as Timo Rinne, Tatu Ylonen, Theo de Raadt, and Aaron// Campbell. Under a BSD-like copyright.static boolforegroundproc(int fd){    static pid_t pgrp = -1;    int ctty_pgrp;    if (pgrp == -1)	pgrp = getpgrp();#ifdef HAVE_TCGETPGRP    return ((ctty_pgrp = tcgetpgrp(fd)) != -1 &&	    ctty_pgrp == pgrp);#else    return ((ioctl(fd, TIOCGPGRP, &ctty_pgrp) != -1 &&	     ctty_pgrp == pgrp));#endif}static intgetttywidth(){    // set TTY width (from openssh scp)    struct winsize winsize;    if (ioctl(STDERR_FILENO, TIOCGWINSZ, &winsize) != -1 && winsize.ws_col)	return (winsize.ws_col ? winsize.ws_col : 80);    else	return 80;}static const char bar[] = "************************************************************""************************************************************""************************************************************""************************************************************";static const char bad_bar[] ="------------------------------------------------------------""------------------------------------------------------------""------------------------------------------------------------""------------------------------------------------------------";static const int max_bar_length = 240;static const char prefixes[] = " KMGTP";#define STALLTIME	5boolProgressBar::get_value(int first, int last, double *value){    *value = 0;    bool all_known = true;    for (int i = first; i < last; i++) {	String s = cp_uncomment(_hs[i]->call_read(_es[i]));	double this_value;	bool ok = cp_double(s, &this_value);	if (ok)	    *value += this_value;	else	    all_known = false;    }    return (first == last ? false : all_known);}voidProgressBar::run_timer(){    // check _active    if (!_active || _status == ST_DEAD)	return;        // get size on first time through    if (_status == ST_FIRST || _status == ST_FIRSTDONE) {	if (!_have_size)	    _have_size = get_value(0, _first_pos_h, &_size);	_last_pos = 0;	_last_time = _start_time = Timestamp::now();	_stall_time = Timestamp();	_delay_time = _start_time + Timestamp::make_msec(_delay_ms);	if (_status == ST_FIRST)	    _status = ST_MIDDLE;    }    // exit if not in foreground    if (!foregroundproc(STDERR_FILENO)) {	_timer.reschedule_after_ms(_interval);	return;    }    // get current time    Timestamp now = Timestamp::now();    // exit if wait time not passed    if (now < _delay_time) {	_timer.reschedule_at(_delay_time);	return;    }        // get position    double pos;    bool have_pos = get_value(_first_pos_h, _es.size(), &pos);    // measure how far along we are    double thermpos;    if (!have_pos)	thermpos = -1;    else if (!_have_size) {	thermpos = ((int)(pos / 100000)) % 200;	if (thermpos > 100) thermpos = 200 - thermpos;    } else if (_size > 0) {	thermpos = (int)(100 * pos / _size);	if (thermpos < 0) thermpos = 0;	else if (thermpos > 100) thermpos = 100;    } else	thermpos = 100;    // start sa, print percentage    StringAccum sa;    sa << "\r";    if (_banner)	sa << _banner << ' ';    if (have_pos && _have_size)	sa.snprintf(6, "%3d%% ", (int)thermpos);    else if (_have_size)	sa << "  -% ";    // print the bar    int barlength = getttywidth() - (sa.length() + 25);    if (_have_size && _first_pos_h == 0)	barlength += 8;    barlength = (barlength <= max_bar_length ? barlength : max_bar_length);    if (barlength > 0) {	if (thermpos < 0 || (!_have_size && _status >= ST_DONE))	    sa.snprintf(barlength + 10, "|%.*s|", barlength, bad_bar);	else if (!_have_size && barlength > 3) {	    int barchar = (int)((barlength - 3) * thermpos / 100);	    sa.snprintf(barlength + 10, "|%*s***%*s|", barchar, "", barlength - barchar - 3, "");	} else if (!_have_size) {	    int barchar = (int)((barlength - 1) * thermpos / 100);	    sa.snprintf(barlength + 10, "|%*s*%*s|", barchar, "", barlength - barchar - 1, "");	} else {	    int barchar = (int)(barlength * thermpos / 100);	    sa.snprintf(barlength + 10, "|%.*s%*s|", barchar, bar, barlength - barchar, "");	}    }    // print position    if (_have_size && _first_pos_h == 0)	// don't print position, it's relevant only as a fraction of _size	sa << " ";    else if (have_pos) {	int which_pfx = 0;	double abbrevpos = pos;	while (abbrevpos >= 100000 && which_pfx < (int)(sizeof(prefixes))) {	    which_pfx++;	    abbrevpos /= 1024;	}	sa.snprintf(30, " %5lu%c%c ", (unsigned long)abbrevpos, prefixes[which_pfx], (prefixes[which_pfx] == ' ' ? ' ' : 'B'));    } else	sa << " -----   ";    // check wait time    Timestamp wait = now - _last_time;    if (pos > _last_pos) {	_last_time = now;	_last_pos = pos;	if (wait._sec >= STALLTIME)	    _stall_time += wait;	wait._sec = 0;    }    // check elapsed time    double elapsed = (now - _start_time - _stall_time).to_double();    // collect time    if (_status < ST_DONE	&& (!_have_size || elapsed <= 0.0 || pos > _size))	sa << "   --:-- ETA";    else if (wait._sec >= STALLTIME)	sa << " - stalled -";    else {	int time_remaining;	if (_status >= ST_DONE)	    time_remaining = (int)elapsed;	else	    time_remaining = (int)(_size / (pos / elapsed) - elapsed);		int hr = time_remaining / 3600;	if (hr)	    sa.snprintf(12, "%2d:", hr);	else	    sa << "   ";	int sec = time_remaining % 3600;	sa.snprintf(12, "%02d:%02d%s", sec / 60, sec % 60,		    (_status >= ST_DONE ? "    " : " ETA"));    }    // add \n if appropriate    if (_status >= ST_DONE)	sa << '\n';    // write data    int fd = STDERR_FILENO;    int buflen = sa.length();    int bufpos = 0;    const char *data = sa.data();    while (bufpos < buflen) {	ssize_t got = write(fd, data + bufpos, buflen - bufpos);	if (got > 0)	    bufpos += got;	else if (errno != EINTR && errno != EAGAIN#ifdef EWOULDBLOCK		 && errno != EWOULDBLOCK#endif		 )	    break;    }    if (_status < ST_DONE)	_timer.reschedule_after_ms(_interval);    else	_active = false;}voidProgressBar::complete(bool is_full){    if (_status < ST_DONE && _active) {	if (is_full) {	    _have_size = true;	    (void) get_value(_first_pos_h, _es.size(), &_size);	}	_status = (_status == ST_FIRST ? ST_FIRSTDONE : ST_DONE);	_timer.unschedule();	run_timer();    }}enum { H_MARK_STOPPED, H_MARK_DONE, H_BANNER, H_ACTIVE,       H_POSHANDLER, H_SIZEHANDLER, H_RESET, H_POS, H_SIZE };StringProgressBar::read_handler(Element *e, void *thunk){    ProgressBar *pb = static_cast<ProgressBar *>(e);    switch ((intptr_t)thunk) {      case H_BANNER:	return pb->_banner + "\n";      case H_ACTIVE:	return cp_unparse_bool(pb->_active) + "\n";      case H_POS:	return String(pb->_last_pos) + "\n";      case H_SIZE:	return String(pb->_size) + "\n";      case H_POSHANDLER:      case H_SIZEHANDLER: {	  bool is_pos = ((intptr_t)thunk == H_POSHANDLER);	  StringAccum sa;	  for (int i = (is_pos ? pb->_first_pos_h : 0); i < (is_pos ? pb->_es.size() : pb->_first_pos_h); i++) {	      if (sa.length()) sa << ' ';	      sa << pb->_hs[i]->unparse_name(pb->_es[i]);	  }	  sa << '\n';	  return sa.take_string();      }      default:	return "<error>";    }}intProgressBar::write_handler(const String &in_str, Element *e, void *thunk, ErrorHandler *errh){    ProgressBar *pb = static_cast<ProgressBar *>(e);    String str = cp_uncomment(in_str);    switch ((intptr_t)thunk) {      case H_MARK_STOPPED:	pb->complete(false);	return 0;      case H_MARK_DONE:	pb->complete(true);	return 0;      case H_BANNER:	pb->_banner = str;	return 0;      case H_SIZE:	if (cp_double(str, &pb->_size))	    return 0;	else	    return errh->error("`size' should be double (size value)");      case H_POSHANDLER:      case H_SIZEHANDLER: {	  Vector<String> words;	  cp_spacevec(str, words);	  bool is_pos = ((intptr_t)thunk == H_POSHANDLER);	  int total = (is_pos ? pb->_first_pos_h + words.size() : pb->_es.size() - pb->_first_pos_h + words.size());	  int offset = (is_pos ? pb->_first_pos_h : 0);	  	  Vector<Element*> es(total, 0);	  Vector<const Handler*> hs(total, 0);	  for (int i = 0; i < words.size(); i++)	      if (!cp_handler(words[i], HandlerCall::CHECK_READ, &es[i+offset], &hs[i+offset], pb, errh))		  return -1;	  offset = (is_pos ? 0 : words.size() - pb->_first_pos_h);	  for (int i = (is_pos ? 0 : pb->_first_pos_h); i < (is_pos ? pb->_first_pos_h : pb->_es.size()); i++)	      es[i + offset] = pb->_es[i], hs[i + offset] = pb->_hs[i];	  	  es.swap(pb->_es);	  hs.swap(pb->_hs);	  if (!is_pos) {	      pb->_have_size = false;	      pb->_first_pos_h = words.size();	  }	  return 0;      }      case H_ACTIVE:	if (cp_bool(str, &pb->_active)) {	    if (pb->_active && !pb->_timer.scheduled())		pb->_timer.schedule_now();	    return 0;	} else	    return errh->error("`active' should be bool (active setting)");      case H_RESET:	pb->_have_size = false;	pb->_status = ST_FIRST;	pb->_active = true;	pb->_timer.schedule_now();	return 0;      default:	return errh->error("internal");    }}voidProgressBar::add_handlers(){    add_write_handler("mark_stopped", write_handler, (void *)H_MARK_STOPPED);    add_write_handler("mark_done", write_handler, (void *)H_MARK_DONE);    add_read_handler("active", read_handler, (void *)H_ACTIVE);    add_write_handler("active", write_handler, (void *)H_ACTIVE);    add_read_handler("banner", read_handler, (void *)H_BANNER);    add_write_handler("banner", write_handler, (void *)H_BANNER);    add_read_handler("poshandler", read_handler, (void *)H_POSHANDLER);    add_write_handler("poshandler", write_handler, (void *)H_POSHANDLER);    add_read_handler("sizehandler", read_handler, (void *)H_SIZEHANDLER);    add_write_handler("sizehandler", write_handler, (void *)H_SIZEHANDLER);    add_read_handler("pos", read_handler, (void *)H_POS);    add_read_handler("size", read_handler, (void *)H_SIZE);    add_write_handler("size", write_handler, (void *)H_SIZE);    add_write_handler("reset", write_handler, (void *)H_RESET);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel)EXPORT_ELEMENT(ProgressBar)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -