X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/44d94f487a2c0b514b77f169dcc1e6e756c2a375..refs/heads/mdw/cleanup:/multiprogress.h
diff --git a/multiprogress.h b/multiprogress.h
index f5147c4..4a0d114 100644
--- a/multiprogress.h
+++ b/multiprogress.h
@@ -1,16 +1,65 @@
+/* -*-c-*-
+ *
+ * Progress bars for terminal programs
+ *
+ * (c) 2022 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
#ifndef MULTIPROGRESS_H
#define MULTIPROGRESS_H
+/*----- Header files ------------------------------------------------------*/
+
#include
#include
+/*----- Compiler-specific magic -------------------------------------------*/
+
+#if (defined(__GNUC__) && (__GNUC__ > 2 || \
+ (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))) || \
+ (defined(__clang__) && (__clang_major__ > 3 || \
+ (__clang_major__ == 3 && __clang_minor__ >= 3)))
+# define MULTIPROGRESS__PRINTF_LIKE(farg, aarg) \
+ __attribute__((format(printf, farg, aarg)))
+#else
+# define MULTIPROGRESS__PRINTF_LIKE(farg, aarg)
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
struct progress_ttyinfo {
- FILE *fp; /* terminal stream */
+ /* Information about the terminal we're going to write to. This is
+ * maintained as part of the `progress_state' (see below) and
+ * published to renderers as part of the `progress_render_state'.
+ *
+ * The `fp' may be null, if no terminal could be opened, or it's just
+ * too deficient in terms of its capabilities. Capabilities are
+ * named following `termcap' conventions, even though we might well
+ * actually be using `terminfo' instead.
+ */
+
+ FILE *fp; /* terminal stream, or null */
char *termbuf, *capbuf; /* buffers for termcap */
struct { /* terminal capabilities */
unsigned f; /* various flags */
-#define TCF_BCE 1u /* erases to background colour */
- const char *cr, *nw, *up, *ce, *cd; /* cursor motion */
+#define TCF_BCE 1u /* erases to background colour */
+ const char *cr, *nw, *up, *ce, *cd; /* cursor motion and erasure */
const char *mr, *md, *me; /* reverse video, bold */
const char *af, *ab, *op; /* colour */
char pc; /* pad character (termcap) */
@@ -21,6 +70,11 @@ struct progress_ttyinfo {
{ 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 80, 25 }
struct progress_state {
+ /* The main state for progress reporting. Here we keep track of the
+ * items which need to be displayed, and current state of the
+ * display.
+ */
+
struct progress_ttyinfo tty; /* terminal state */
struct progress_item *items, *end_item; /* list of progress items */
unsigned nitems; /* number of items */
@@ -30,6 +84,17 @@ struct progress_state {
#define PROGRESS_STATE_INIT { PROGRESS_TTYINFO_INIT, 0, 0, 0, 0, { 0, 0 } }
struct progress_render_state {
+ /* Information passed to rendering functions.
+ *
+ * The `linebuf' accumulates the text to be shown by
+ * `progress_showbar' or similar, which consists of left and right
+ * portions aligned left and right on the terminal line, with a
+ * variable-size cap in between. These strings are stored at the
+ * beginning and end of the `linebuf', so that (hopefully) new
+ * material can be added in the gap between them without us having to
+ * reallocate the buffer.
+ */
+
const struct progress_ttyinfo *tty; /* terminal state */
unsigned width, height; /* terminal size, in characters */
char *linebuf; size_t linesz; /* output buffer */
@@ -40,6 +105,18 @@ struct progress_render_state {
};
struct progress_item {
+ /* An item in the progress display.
+ *
+ * The `render' function is passed a pointer to the `progress_item'
+ * structure. Usually, it will need additional state: handle this by
+ * making the `progress_item' be the first member of a larger
+ * structure which holds the necessary information.
+ *
+ * The `render' function should limit its activities to actually
+ * writing a line of information to the terminal. In particular, it
+ * shouldn't try to calculate anything time-dependent itself.
+ */
+
struct progress_state *parent; /* controlling progress state */
struct progress_item *next, *prev; /* forward and backward links */
void (*render)(struct progress_item */*item*/, /* render function */
@@ -47,37 +124,111 @@ struct progress_item {
};
#define PROGRESS_ITEM_INIT { 0, 0, 0, 0 }
+/*----- Functions provided ------------------------------------------------*/
+
extern int progress_init(struct progress_state */*progress*/);
+ /* Initialize PROGRESS.
+ *
+ * It is safe to call this function on uninitialized data. This
+ * involves opening a stream on the terminal, and determining the
+ * terminal's capabilities. Returns zero on success, or -1 on
+ * failure. The structure is usable in either case (though if no
+ * terminal could be opened, then no progress output will be
+ * produced).
+ */
+
extern void progress_free(struct progress_state */*progress*/);
+ /* Free any resources held by PROGRESS.
+ *
+ * It is safe to call this function on a structure that was
+ * initialized to `PROGRESS_STATE_INIT', or by calling
+ * `progress_init', whether that function succeeded or not. It's
+ * also harmless to call it repeatedly on the same structure.
+ */
extern int progress_additem(struct progress_state */*progress*/,
struct progress_item */*item*/);
+ /* If ITEM is already associated with a progress state, then do
+ * nothing and return -1. Otherwise, add ITEM to the end of the list
+ * of active items maintained by PROGRESS, and return 0. The
+ * progress display is not updated.
+ */
extern int progress_removeitem(struct progress_state */*progress*/,
struct progress_item */*item*/);
+ /* If ITEM is not associated with a progress state, then do nothing
+ * and return -1. Otherwise, remove ITEM from the list of active
+ * items maintained by PROGRESS, and return 0. The progress display
+ * is not updated.
+ */
extern int progress_clear(struct progress_state */*progress*/);
+ /* Clear any progress display currently shown on the terminal. Call
+ * this before doing your own output to the terminal, and call
+ * `progress_update' afterwards.
+ */
extern int progress_update(struct progress_state */*progress*/);
+ /* Update the progress display. This will call the `render'
+ * functions for all active progress items to redraw them.
+ */
extern int progress_vputleft(struct progress_render_state */*render*/,
const char */*fmt*/, va_list /*ap*/);
-
extern int progress_vputright(struct progress_render_state */*render*/,
const char */*fmt*/, va_list /*ap*/);
-
-__attribute__((format(printf, 2, 3)))
+MULTIPROGRESS__PRINTF_LIKE(2, 3)
extern int progress_putleft(struct progress_render_state */*render*/,
const char */*fmt*/, ...);
-
-__attribute__((format(printf, 2, 3)))
+MULTIPROGRESS__PRINTF_LIKE(2, 3)
extern int progress_putright(struct progress_render_state */*render*/,
const char */*fmt*/, ...);
+ /* Format the `printf'-style string FMT with the supplied arguments
+ * and add it to the left or right side of the current line being
+ * built up in RENDER. Later strings are added closer to the centre
+ * than earlier strings. If there isn't enough space left to show
+ * the new string on a terminal line, or if there isn't enough memory
+ * for the necessary buffers, then do nothing and return -1. If
+ * everything worked OK, then return 0.
+ */
+
+extern void progress_put_sequence(const struct progress_ttyinfo */*tty*/,
+ const char */*p*/, unsigned /*nlines*/);
+ /* Send a sequence P -- one of the capability strings from TTY -- to
+ * the terminal TTY, padding it as necessary based on the fact that
+ * NLINES of the display are affected. (See the `tputs' function for
+ * the details.)
+ */
+
+extern void progress_set_fgcolour(const struct progress_ttyinfo */*tty*/,
+ int /*colour*/);
+extern void progress_set_bgcolour(const struct progress_ttyinfo */*tty*/,
+ int /*colour*/);
+ /* Set COLOUR as the foreground (`set_fgcolour') or background
+ * (`set_bgcolour') colour for subsequent output to TTY.
+ */
extern int progress_showbar(struct progress_render_state */*render*/,
double /*frac*/);
+ /* Show a progress bar. The text of the progress bar will be as
+ * established by the `progress_putleft' and `progress_putright'
+ * functions called on RENDER so far, and the bar will be written to
+ * the terminal associated with RENDER. The length of the bar will
+ * be a FRAC fraction of the width of the terminal, so FRAC should be
+ * a real number between 0.0 and 1.0 inclusive.
+ */
extern int progress_shownotice(struct progress_render_state */*render*/,
int /*bg*/, int /*fg*/);
+ /* Show a notice, i.e., a temporary message which doesn't actually
+ * have any progress associated with it. The text of the notice will
+ * be as established by the `progress_putleft' and
+ * `progress_putright' functions called on RENDER so far, and the
+ * notice will be written to the terminal associated with RENDER.
+ * The notice's background and foreground colours will be BG and FG
+ * respectively.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
#endif