chevron_left chevron_right
Login Register invert_colors photo_library
Thread Rating:
  • 0 Vote(s) - 0 Average


filter_list Tutorial Making multiple independent command line progress bars
Author
Message
Making multiple independent command line progress bars #1
So, I wrote a tutorial thread today about creating command line program progress bars, for another member on discord. During that conversation we talked about queueing them and making it so you could do simultaneous downloads and display those on screen, then implementing a basic (mutex style) queue. This is a little bit less of a tutorial and more of just a posting, but I went ahead and wrote a demo for it. Here's the code:

Code:
/* simple example of using ncurses to display a queue of progress bars
* save this file as ncprogress.c
* compile with gcc -o ncp ncprogress.c -pthread -lncurses
* change MAX_BARS to the size you want your queue to be
* run ./ncp to test it out */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <ncurses.h>
#define MAX_BARS 5
WINDOW *positions[MAX_BARS] = { NULL };
struct progressContext
{
        void (*callback)(unsigned, unsigned, struct progressContext *);
        WINDOW *win;
        char *name;
};
struct threadContext
{
        struct progressContext *progress;
        int position;
        unsigned seconds;
        pthread_t threadId;
};
void waitLoop(unsigned ms, unsigned interval, struct progressContext *context)
{
        unsigned i, j, s, count = ms/interval;
        for (i = 0, s = 0; i < ms; i += interval, ++s)
        {
                (*context->callback)(s % 4, (i * 100) / ms, context);
                usleep(interval * 1000);
        }
        (*context->callback)(0, 100, context);
        printf("\n");
}
void progressw(unsigned spin, unsigned step, struct progressContext *ctx)
{
        int i;
        const char *pgstep = "|\\-/";
        wclear(ctx->win);
        wprintw(ctx->win, "Your title here, this thread is %s seconds\n[", ctx->name); // print window title first
        for (i = 0; i < step; ++i) wprintw(ctx->win, "#"); // print bar
        for (; i < 100; ++i) wprintw(ctx->win, " "); // print blank space
        wprintw(ctx->win, "] %c                       ", step > 99 ? ' ' : pgstep[spin]);
        wrefresh(ctx->win);
}
void *threadWrapper(void *arg)
{
}
int selectPosition()
{
        int i;
        for (i = 0; i < MAX_BARS; ++i)
                if (positions[i] == NULL)
                        return i;
        return -1;
}
void *threadEntry(void *arg)
{
        struct threadContext *ctx;
        struct progressContext *pctx;
        ctx = arg;
        pctx = ctx->progress;
        waitLoop(ctx->seconds * 1000, 1000, pctx);
        werase(pctx->win);
        wrefresh(pctx->win);
        delwin(pctx->win);
        free(pctx->name);
        free(pctx);
        usleep(200 * 1000);
        positions[ctx->position] = NULL; // put the window back in the list
        free(ctx);
        return NULL;
}
void runThread(unsigned seconds, void (*callback)(unsigned, unsigned, struct progressContext *))
{
        int position;
        struct threadContext *ctx;
        do { position = selectPosition(); } while (position < 0); // wait until we get a window
        positions[position] = (void *)1; // reserve our spot before we create the window, we will change this later
        positions[position] = newwin(2, 120, position * 2, 0); // create an ncurses window for it
        wclear(positions[position]); wrefresh(positions[position]); // initialize the window
        ctx = malloc(sizeof(struct threadContext));
        ctx->threadId = 0;
        ctx->position = position;
        ctx->seconds = seconds;
        ctx->progress = malloc(sizeof(struct progressContext));
        ctx->progress->callback = callback;
        ctx->progress->win = positions[position];
        ctx->progress->name = malloc(8);
        sprintf(ctx->progress->name, "%d", seconds);
        ctx->threadId = pthread_create(&ctx->threadId, NULL, threadEntry, ctx);
}
int running()
{
        int i;
        for (i = 0; i < MAX_BARS; ++i)
                if (positions[i] != NULL)
                        return 1;
        return 0;
}
int main()
{
        int i;
        const int ndownloads = 18;
        initscr();
        refresh();
        noecho();
        srand(time(NULL));
        for (i = 0; i < ndownloads; ++i)
        {
                runThread(rand() % 10 + 5, &progressw); // run for random time between 5 and 10 seconds
                usleep(750 * 1000); //a time out
        }
        sleep(1); // wait for a thread to start
        while (running()); // loop while we wait
        refresh();
        endwin();
        return 0;
}

And, for those of you who want the syntax highlighting, click here
Or for the raw code download, click here

Reply






Users browsing this thread: 1 Guest(s)