login

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define DEFAULT_WIDTH   32
#define LINE_MAX        (1 << 12)

static char spinchars[] = "|/-\\";
static unsigned spinindex = 0;
static char line[LINE_MAX];
static unsigned lastfill = UINT_MAX;
static unsigned lastpercent = 101;

void
print_progress(unsigned width, unsigned percent, int showbar, int showspinner, int showline)
{
    unsigned i, fill;
    fill = percent * width / 100;
    if (showspinner) {
        if (percent == 100)
            spinindex = 0;
        fprintf(stderr, " (%c)", spinchars[spinindex++]);
        spinindex %= sizeof(spinchars) - 1;
    }
    if (showbar) {
        if (fill != lastfill) {
            if (lastfill > width)
                lastfill = 0;
            fprintf(stderr, " [");
            if (lastfill)
                fprintf(stderr, "\x1B[%uC", lastfill);
            for (i = lastfill; i < fill; i++)
                fputc('#', stderr);
            if (!percent) {
                for (; i < width; i++)
                    fputc('-', stderr);
            } else {
                if (fill < width)
                    fprintf(stderr, "\x1B[%uC", width - fill);
            }
            lastfill = fill;
        } else {
            fprintf(stderr, "\x1B[%uC", width + 2);
        }
        if (percent != lastpercent) {
            fprintf(stderr, "] %3u%%", percent);
            lastpercent = percent;
        }
        fprintf(stderr, "\r");
        if (showline)
            fprintf(stderr, "\x1B[B%s\r\x1B[A", line);
    } else if (showline) {
        fprintf(stderr, " %s", line);
    }
    fprintf(stderr, "\r");
    fflush(stderr);
}

int
main(int argc, char *argv[])
{
    unsigned long count;
    unsigned percent;
    int i;
    char *arg;
    char *argtotal = NULL;
    int opt_showbar;
    int opt_showline = 0;
    int opt_showspinner = 0;
    int opt_output = 0;
    unsigned opt_width = DEFAULT_WIDTH;
    unsigned long total = 0;
    for (i = 1; i < argc; i++) {
        arg = argv[i];
        if (*arg == '-') {
            while (*(++arg)) {
                switch (*arg) {
                case 'v':
                    opt_showline = 1;
                    break;
                case 's':
                    opt_showspinner = 1;
                    break;
                case 'o':
                    opt_output = 1;
                    break;
                case 'w':
                    opt_width = (unsigned) strtol(arg+1, &arg, 10);
                    if (opt_width)
                        arg--;
                    else
                        opt_width = DEFAULT_WIDTH;
                    break;
                default:
                    fprintf(stderr, "%s: error: unknown option '-%c'\n", argv[0], *arg);
                    return 1;
                }
            }
        } else {
            argtotal = arg;
        }
    }
    if (argtotal != NULL)
        total = (unsigned) atol(argtotal);
    opt_showbar = total > 0;
    if (opt_showbar)
        fprintf(stderr, "\n\x1B[A");
    print_progress(opt_width, 0, opt_showbar, opt_showspinner, 0);
    count = 0;
    while (fgets(line, LINE_MAX, stdin) != NULL) {
        if (count < total)
            count++;
        if (opt_showbar)
            percent = count * 100 / total;
        print_progress(opt_width, percent, opt_showbar, opt_showspinner, opt_showline);
        if (opt_output)
            printf(line);
    }
    print_progress(opt_width, 100, opt_showbar, opt_showspinner, 0);
    fputs("\x1B[B\x1B[2K\x1B[A\n", stderr);
    return 0;
}