free(tty->capbuf); tty->capbuf = 0;
}
-#if defined(USE_TERMINFO)
-static const struct progress_ttyinfo *curtty = 0;
-static int putty(int ch) { return (putc(ch, curtty->fp)); }
-static void put_sequence(const struct progress_ttyinfo *tty,
- const char *p, unsigned nlines)
- { if (p) { curtty = tty; tputs(p, nlines, putty); } }
-static void set_fgcolour(const struct progress_ttyinfo *tty, int colour)
- { put_sequence(tty, tgoto(tty->cap.af, -1, colour), 1); }
-static void set_bgcolour(const struct progress_ttyinfo *tty, int colour)
- { put_sequence(tty, tgoto(tty->cap.ab, -1, colour), 1); }
-#elif defined(USE_TERMCAP)
-static const struct progress_ttyinfo *curtty = 0;
-static int putty(int ch) { return (putc(ch, curtty->fp)); }
-static void put_sequence(const struct progress_ttyinfo *tty,
- const char *p, unsigned nlines)
- { if (p) { curtty = tty; tputs(p, nlines, putty); } }
-static void set_fgcolour(const struct progress_ttyinfo *tty, int colour)
- { put_sequence(tty, tgoto(tty->cap.af, -1, colour), 1); }
-static void set_bgcolour(const struct progress_ttyinfo *tty, int colour)
- { put_sequence(tty, tgoto(tty->cap.ab, -1, colour), 1); }
-#else
-static void put_sequence(const struct progress_ttyinfo *tty,
- const char *p, unsigned nlines) { ; }
-static void set_fgcolour(const struct progress_ttyinfo *tty, int colour)
- { ; }
-static void set_bgcolour(const struct progress_ttyinfo *tty, int colour)
- { ; }
-#endif
-
-#define CLRF_ALL 1u
-static int clear_progress(struct progress_state *progress,
- struct progress_render_state *render, unsigned f)
-{
- const struct progress_ttyinfo *tty = &progress->tty;
- unsigned ndel, nleave;
- unsigned i;
-
- if (!tty->fp) return (-1);
-
- put_sequence(tty, tty->cap.cr, 1);
- if (progress->last_lines) {
- if (f&CLRF_ALL)
- { ndel = progress->last_lines; nleave = 0; }
- else {
- if (progress->nitems >= progress->last_lines) ndel = 0;
- else ndel = progress->last_lines - progress->nitems;
- nleave = progress->last_lines - ndel;
- }
- if (!ndel)
- for (i = 0; i < nleave - 1; i++) put_sequence(tty, tty->cap.up, 1);
- else {
- for (i = 0; i < ndel - 1; i++) put_sequence(tty, tty->cap.up, 1);
- put_sequence(tty, tty->cap.cd, ndel);
- for (i = 0; i < nleave; i++) put_sequence(tty, tty->cap.up, 1);
- }
- }
- progress->last_lines = 0;
- if (ferror(tty->fp)) return (-1);
- return (0);
-}
-
-static int grow_linebuf(struct progress_render_state *render, size_t want)
+int progress_additem(struct progress_state *progress,
+ struct progress_item *item)
{
- char *newbuf; size_t newsz;
+ if (item->parent) return (-1);
+ item->prev = progress->end_item; item->next = 0;
+ if (progress->end_item) progress->end_item->next = item;
+ else progress->items = item;
+ progress->end_item = item; item->parent = progress;
+ progress->nitems++;
- if (want <= render->linesz) return (0);
- if (!render->linesz) newsz = 4*render->width + 1;
- else newsz = render->linesz;
- while (newsz < want) newsz *= 2;
- newbuf = malloc(newsz + 1); if (!newbuf) return (-1);
- newbuf[newsz] = 0;
- if (render->leftsz)
- memcpy(newbuf, render->linebuf, render->leftsz);
- if (render->rightsz)
- memcpy(newbuf + newsz - render->rightsz,
- render->linebuf + render->linesz - render->rightsz,
- render->rightsz);
- free(render->linebuf); render->linebuf = newbuf; render->linesz = newsz;
return (0);
}
-static int grow_tempbuf(struct progress_render_state *render, size_t want)
+int progress_removeitem(struct progress_state *progress,
+ struct progress_item *item)
{
- char *newbuf; size_t newsz;
+ if (!item->parent) return (-1);
+ if (item->next) item->next->prev = item->prev;
+ else (progress->end_item) = item->prev;
+ if (item->prev) item->prev->next = item->next;
+ else (progress->items) = item->next;
+ progress->nitems--; item->parent = 0;
- if (want <= render->tempsz) return (0);
- if (!render->tempsz) newsz = 4*render->width + 1;
- else newsz = render->tempsz;
- while (newsz < want) newsz *= 2;
- newbuf = malloc(newsz + 1); if (!newbuf) return (-1);
- newbuf[newsz] = 0;
- if (render->tempsz) memcpy(newbuf, render->tempbuf, render->tempsz);
- free(render->tempbuf); render->tempbuf = newbuf; render->tempsz = newsz;
return (0);
}
-static int setup_render_state(struct progress_state *progress,
- struct progress_render_state *render)
+static void setup_render_state(struct progress_state *progress,
+ struct progress_render_state *render)
{
const struct progress_ttyinfo *tty = &progress->tty;
struct winsize wsz;
- int rc = 0;
render->tty = tty;
render->linebuf = 0; render->linesz = 0;
if (!ioctl(fileno(tty->fp), TIOCGWINSZ, &wsz))
{ render->width = wsz.ws_col; render->height = wsz.ws_row; }
else
- { render->width = tty->defwd; render->height = tty->defht; rc = -1; }
+ { render->width = tty->defwd; render->height = tty->defht; }
if (render->width && !tty->cap.op && !tty->cap.mr) render->width--;
-
- return (rc);
}
static void free_render_state(struct progress_render_state *render)
unsigned *wd_out, unsigned maxwd)
{
struct measure m;
- size_t lasti; unsigned lastwd;
+ size_t i; unsigned wd;
int more;
init_measure(&m, p, sz);
for (;;) {
- lasti = m.i; lastwd = m.wd;
+ if (!advance_measure(&m)) { *wd_out = m.wd; return (sz); }
+ if (m.wd >= maxwd) break;
+ }
+ wd = m.wd; i = m.i;
+ for (;;) {
more = advance_measure(&m);
- if (m.wd > maxwd) { *wd_out = lastwd; return (lasti); }
- else if (!more) { *wd_out = m.wd; return (sz); }
+ if (m.wd > wd) break;
+ i = m.i;
+ if (!more) break;
}
+ *wd_out = wd; return (i);
+}
+
+static int grow_linebuf(struct progress_render_state *render, size_t want)
+{
+ char *newbuf; size_t newsz;
+
+ if (want <= render->linesz) return (0);
+ if (!render->linesz) newsz = 4*render->width + 1;
+ else newsz = render->linesz;
+ while (newsz < want) newsz *= 2;
+ newbuf = malloc(newsz + 1); if (!newbuf) return (-1);
+ newbuf[newsz] = 0;
+ if (render->leftsz)
+ memcpy(newbuf, render->linebuf, render->leftsz);
+ if (render->rightsz)
+ memcpy(newbuf + newsz - render->rightsz,
+ render->linebuf + render->linesz - render->rightsz,
+ render->rightsz);
+ free(render->linebuf); render->linebuf = newbuf; render->linesz = newsz;
+ return (0);
+}
+
+static int grow_tempbuf(struct progress_render_state *render, size_t want)
+{
+ char *newbuf; size_t newsz;
+
+ if (want <= render->tempsz) return (0);
+ if (!render->tempsz) newsz = 4*render->width + 1;
+ else newsz = render->tempsz;
+ while (newsz < want) newsz *= 2;
+ newbuf = malloc(newsz + 1); if (!newbuf) return (-1);
+ newbuf[newsz] = 0;
+ free(render->tempbuf); render->tempbuf = newbuf; render->tempsz = newsz;
+ return (0);
}
enum { LEFT, RIGHT };
return (rc);
}
+#if defined(USE_TERMINFO)
+static const struct progress_ttyinfo *curtty = 0;
+static int putty(int ch) { return (putc(ch, curtty->fp)); }
+void progress_put_sequence(const struct progress_ttyinfo *tty,
+ const char *p, unsigned nlines)
+ { if (p) { curtty = tty; tputs(p, nlines, putty); } }
+void progress_set_fgcolour(const struct progress_ttyinfo *tty, int colour)
+ { progress_put_sequence(tty, tgoto(tty->cap.af, -1, colour), 1); }
+void progress_set_bgcolour(const struct progress_ttyinfo *tty, int colour)
+ { progress_put_sequence(tty, tgoto(tty->cap.ab, -1, colour), 1); }
+#elif defined(USE_TERMCAP)
+static const struct progress_ttyinfo *curtty = 0;
+static int putty(int ch) { return (putc(ch, curtty->fp)); }
+void progress_put_sequence(const struct progress_ttyinfo *tty,
+ const char *p, unsigned nlines)
+ { if (p) { curtty = tty; tputs(p, nlines, putty); } }
+void progress_set_fgcolour(const struct progress_ttyinfo *tty, int colour)
+ { progress_put_sequence(tty, tgoto(tty->cap.af, -1, colour), 1); }
+void progress_set_bgcolour(const struct progress_ttyinfo *tty, int colour)
+ { progress_put_sequence(tty, tgoto(tty->cap.ab, -1, colour), 1); }
+#else
+void progress_put_sequence(const struct progress_ttyinfo *tty,
+ const char *p, unsigned nlines) { ; }
+void progress_set_fgcolour(const struct progress_ttyinfo *tty, int colour)
+ { ; }
+void progress_set_bgcolour(const struct progress_ttyinfo *tty, int colour)
+ { ; }
+#endif
+
+#define CLRF_ALL 1u
+static int clear_progress(struct progress_state *progress,
+ struct progress_render_state *render, unsigned f)
+{
+ const struct progress_ttyinfo *tty = &progress->tty;
+ unsigned ndel, nleave;
+ unsigned i;
+
+ progress_put_sequence(tty, tty->cap.cr, 1);
+ if (progress->last_lines) {
+ if (f&CLRF_ALL)
+ { ndel = progress->last_lines; nleave = 0; }
+ else {
+ if (progress->nitems >= progress->last_lines) ndel = 0;
+ else ndel = progress->last_lines - progress->nitems;
+ nleave = progress->last_lines - ndel;
+ }
+ if (!ndel)
+ for (i = 1; i < nleave; i++)
+ progress_put_sequence(tty, tty->cap.up, 1);
+ else {
+ for (i = 1; i < ndel; i++)
+ progress_put_sequence(tty, tty->cap.up, 1);
+ progress_put_sequence(tty, tty->cap.cd, ndel);
+ for (i = 0; i < nleave; i++)
+ progress_put_sequence(tty, tty->cap.up, 1);
+ }
+ }
+ progress->last_lines = 0;
+ if (ferror(tty->fp)) return (-1);
+ return (0);
+}
+
+int progress_clear(struct progress_state *progress)
+{
+ struct progress_render_state render;
+
+ if (!progress->tty.fp) return (-1);
+ setup_render_state(progress, &render);
+ clear_progress(progress, &render, CLRF_ALL);
+ free_render_state(&render);
+ return (0);
+}
+
+int progress_update(struct progress_state *progress)
+{
+ struct progress_render_state render;
+ const struct progress_ttyinfo *tty = &progress->tty;
+ struct progress_item *item;
+ unsigned f = 0;
+#define f_any 1u
+
+ if (!progress->tty.fp) return (-1);
+ setup_render_state(progress, &render);
+ clear_progress(progress, &render, 0);
+
+ for (item = progress->items; item; item = item->next) {
+ if (f&f_any) progress_put_sequence(tty, tty->cap.nw, 1);
+ render.leftsz = render.rightsz = 0;
+ render.leftwd = render.rightwd = 0;
+ item->render(item, &render); progress->last_lines++; f |= f_any;
+ if (progress->last_lines > render.height) break;
+ }
+ if (f&f_any) progress_put_sequence(tty, tty->cap.cr, 1);
+ free_render_state(&render);
+ return (0);
+}
+
enum {
LEFT_COLOUR,
LEFT_MONO,
const struct progress_ttyinfo *tty = render->tty;
size_t here = bar->nextpos;
- while (bar->nextpos == here) {
+ while (bar->nextpos <= here) {
switch (bar->state) {
- case LEFT_COLOUR: set_bgcolour(tty, 3); goto right;
- case LEFT_MONO: put_sequence(tty, tty->cap.me, 1); goto right;
+ case LEFT_COLOUR: progress_set_bgcolour(tty, 3); goto right;
+ case LEFT_MONO: progress_put_sequence(tty, tty->cap.me, 1); goto right;
case LEFT_SIMPLE: putc('|', tty->fp); goto right;
right: bar->state = RIGHT_ANY; bar->nextpos = render->width; break;
case RIGHT_ANY: bar->state = STOP; bar->nextpos = UINT_MAX; break;
bar.render = render; bar.pos = 0; bar.nextpos = frac*render->width + 0.5;
if (tty->cap.op) {
- set_fgcolour(tty, 0); bar.state = LEFT_COLOUR;
- if (bar.nextpos) set_bgcolour(tty, 2);
+ progress_set_fgcolour(tty, 0); bar.state = LEFT_COLOUR;
+ if (bar.nextpos) progress_set_bgcolour(tty, 2);
else advance_bar_state(&bar);
} else if (tty->cap.mr) {
if (bar.nextpos)
- { bar.state = LEFT_MONO; put_sequence(tty, tty->cap.mr, 1); }
+ { bar.state = LEFT_MONO; progress_put_sequence(tty, tty->cap.mr, 1); }
else
{ bar.state = RIGHT; bar.nextpos = render->width; }
} else
render->linebuf + render->linesz - render->rightsz,
render->rightsz);
- put_sequence(tty, tty->cap.me, 1);
- put_sequence(tty, tty->cap.op, 1);
+ progress_put_sequence(tty, tty->cap.me, 1);
+ progress_put_sequence(tty, tty->cap.op, 1);
return (0);
}
if (!tty->fp) return (-1);
- if (tty->cap.op) { set_fgcolour(tty, fg); set_bgcolour(tty, bg); }
- else if (tty->cap.mr) put_sequence(tty, tty->cap.mr, 1);
- if (tty->cap.md) put_sequence(tty, tty->cap.md, 1);
+ if (tty->cap.op)
+ { progress_set_fgcolour(tty, fg); progress_set_bgcolour(tty, bg); }
+ else if (tty->cap.mr)
+ progress_put_sequence(tty, tty->cap.mr, 1);
+ if (tty->cap.md)
+ progress_put_sequence(tty, tty->cap.md, 1);
put_str(tty->fp, render->linebuf, render->leftsz);
if (!render->rightsz && (tty->cap.f&TCF_BCE) && tty->cap.ce)
- put_sequence(tty, tty->cap.ce, 1);
+ progress_put_sequence(tty, tty->cap.ce, 1);
else {
put_spc(tty->fp, render->width - render->leftwd - render->rightwd);
put_str(tty->fp,
render->rightsz);
}
- put_sequence(tty, tty->cap.me, 1);
- put_sequence(tty, tty->cap.op, 1);
-
- return (0);
-}
-
-int progress_additem(struct progress_state *progress,
- struct progress_item *item)
-{
- if (item->parent) return (-1);
- item->prev = progress->end_item; item->next = 0;
- if (progress->end_item) progress->end_item->next = item;
- else progress->items = item;
- progress->end_item = item; item->parent = progress;
- progress->nitems++;
-
- return (0);
-}
-
-int progress_clear(struct progress_state *progress)
-{
- struct progress_render_state render;
-
- if (!progress->tty.fp) return (-1);
- if (setup_render_state(progress, &render)) return (-1);
- clear_progress(progress, &render, CLRF_ALL);
- free_render_state(&render);
- return (0);
-}
-
-int progress_update(struct progress_state *progress)
-{
- struct progress_render_state render;
- const struct progress_ttyinfo *tty = &progress->tty;
- struct progress_item *item;
- unsigned f = 0;
-#define f_any 1u
-
- if (!progress->tty.fp) return (-1);
- if (setup_render_state(progress, &render)) return (-1);
- clear_progress(progress, &render, 0);
-
- for (item = progress->items; item; item = item->next) {
- if (f&f_any) put_sequence(tty, tty->cap.nw, 1);
- render.leftsz = render.rightsz = 0;
- render.leftwd = render.rightwd = 0;
- item->render(item, &render); progress->last_lines++; f |= f_any;
- if (progress->last_lines > render.height) break;
- }
- if (f&f_any) put_sequence(tty, tty->cap.cr, 1);
- free_render_state(&render);
- return (0);
-}
-
-int progress_removeitem(struct progress_state *progress,
- struct progress_item *item)
-{
- if (!item->parent) return (-1);
- if (item->next) item->next->prev = item->prev;
- else (progress->end_item) = item->prev;
- if (item->prev) item->prev->next = item->next;
- else (progress->items) = item->next;
- progress->nitems--; item->parent = 0;
+ progress_put_sequence(tty, tty->cap.me, 1);
+ progress_put_sequence(tty, tty->cap.op, 1);
return (0);
}