multiprogress.c (clear_progress): Don't check `tty->fp': the caller did it.
[dvdrip] / multiprogress.c
index efad38d..3318415 100644 (file)
@@ -69,6 +69,7 @@ int progress_init(struct progress_state *progress)
   if (setupterm(0, fileno(tty->fp), &err) != OK || err < 1) return (-1);
 
   tty->cap.cr = tigetstr("cr");
+  tty->cap.nw = tigetstr("nel");
   tty->cap.up = tigetstr("cuu1");
   tty->cap.ce = tigetstr("el");
   tty->cap.cd = tigetstr("ed");
@@ -90,14 +91,15 @@ int progress_init(struct progress_state *progress)
 
 #elif defined(USE_TERMCAP)
 
-  term = getenv("TERM"); if (!term) return (-1);
-  if (tgetent(tty->termbuf, term) < 1) return (-1);
-
   tty->termbuf = malloc(4096); if (!tty->termbuf) return (-1);
   tty->capbuf = malloc(4096); if (!tty->capbuf) return (-1);
 
+  term = getenv("TERM"); if (!term) return (-1);
+  if (tgetent(tty->termbuf, term) < 1) return (-1);
+
   capcur = tty->capbuf;
   tty->cap.cr = tgetstr("cr", &capcur);
+  tty->cap.nw = tgetstr("nw", &capcur);
   tty->cap.up = tgetstr("up", &capcur);
   tty->cap.ce = tgetstr("ce", &capcur);
   tty->cap.cd = tgetstr("cd", &capcur);
@@ -114,7 +116,7 @@ int progress_init(struct progress_state *progress)
 
   if (tgetflag("ut") > 0) tty->cap.f |= TCF_BCE;
 
-  t = tgetstr("pc", &capcur); PC = t ? *t : 0;
+  t = tgetstr("pc", &capcur); tty->cap.pc = t ? *t : 0;
 
   SETDIM(defwd, "COLUMNS", tgetnum("co"), 80);
   SETDIM(defht, "LINES", tgetnum("li"), 25);
@@ -128,7 +130,9 @@ int progress_init(struct progress_state *progress)
 
 #undef SETDIM
 
-  if (!tty->cap.cr || !tty->cap.up || !tty->cap.ce || !tty->cap.cd)
+  if (!tty->cap.cr) tty->cap.cr = "\r";
+  if (!tty->cap.nw) tty->cap.nw = "\r\n";
+  if (!tty->cap.up || !tty->cap.ce || !tty->cap.cd)
     { fclose(tty->fp); tty->fp = 0; return (-1); }
   if (!tty->cap.af || !tty->cap.ab || !tty->cap.op) tty->cap.op = 0;
   if (!tty->cap.me) tty->cap.mr = tty->cap.md = 0;
@@ -140,111 +144,41 @@ void progress_free(struct progress_state *progress)
   struct progress_ttyinfo *tty = &progress->tty;
 
   if (tty->fp) { fclose(tty->fp); tty->fp = 0; }
-  free(tty->termbuf); free(tty->capbuf); tty->termbuf = tty->capbuf = 0;
+  free(tty->termbuf); tty->termbuf = 0;
+  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)
+int progress_additem(struct progress_state *progress,
+                    struct progress_item *item)
 {
-  const struct progress_ttyinfo *tty = &progress->tty;
-  unsigned ndel, nleave;
-  unsigned i;
-
-  if (!tty->fp) return (-1);
+  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++;
 
-  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)
-{
-  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)
+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;
@@ -253,16 +187,15 @@ static int setup_render_state(struct progress_state *progress,
 #ifdef USE_TERMCAP
   render->old_bc = BC; BC = 0;
   render->old_up = UP; UP = 0;
+  render->old_pc = PC; PC = tty->cap.pc;
 #endif
 
   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)
@@ -273,6 +206,7 @@ static void free_render_state(struct progress_render_state *render)
 #ifdef USE_TERMCAP
   UP = render->old_up;
   BC = render->old_bc;
+  PC = render->old_pc;
 #endif
 }
 
@@ -320,16 +254,56 @@ static size_t split_string(const char *p, size_t sz,
                           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 };
@@ -404,6 +378,103 @@ int progress_putright(struct progress_render_state *render,
   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,
@@ -423,10 +494,10 @@ static void advance_bar_state(struct bar_state *bar)
   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;
@@ -478,12 +549,12 @@ int progress_showbar(struct progress_render_state *render, double frac)
   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
@@ -495,8 +566,8 @@ int progress_showbar(struct progress_render_state *render, double frac)
             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);
 }
@@ -507,13 +578,16 @@ int progress_shownotice(struct progress_render_state *render, int bg, int fg)
 
   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,
@@ -521,67 +595,8 @@ int progress_shownotice(struct progress_render_state *render, int bg, int fg)
            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;
-  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) fputs("\r\n", progress->tty.fp);
-    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;
-  }
-  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);
 }