+#define STREQ(a,b) (strcmp((a),(b)) == 0)
+
+/* Compute the running mean and standard deviation from the
+ * series of estimated values.
+ *
+ * Method:
+ * http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
+ * Checked in a test program against answers given by Wolfram Alpha.
+ */
+struct rmsd {
+ double a; /* mean */
+ double i; /* number of samples */
+ double q;
+};
+
+static void
+rmsd_init (struct rmsd *r)
+{
+ r->a = 0;
+ r->i = 1;
+ r->q = 0;
+}
+
+static void
+rmsd_add_sample (struct rmsd *r, double x)
+{
+ double a_next, q_next;
+
+ a_next = r->a + (x - r->a) / r->i;
+ q_next = r->q + (x - r->a) * (x - a_next);
+ r->a = a_next;
+ r->q = q_next;
+ r->i += 1.0;
+}
+
+static double
+rmsd_get_mean (const struct rmsd *r)
+{
+ return r->a;
+}
+
+static double
+rmsd_get_standard_deviation (const struct rmsd *r)
+{
+ return sqrt (r->q / (r->i - 1.0));
+}
+
+struct progress_bar {
+ double start; /* start time of command */
+ int count; /* number of progress notifications per cmd */
+ struct rmsd rmsd; /* running mean and standard deviation */
+ int have_terminfo;
+ int utf8_mode;
+ int machine_readable;
+};
+
+struct progress_bar *
+progress_bar_init (unsigned flags)
+{
+ struct progress_bar *bar;
+ char *term;
+
+ bar = malloc (sizeof *bar);
+ if (bar == NULL)
+ return NULL;
+
+ if (flags & PROGRESS_BAR_MACHINE_READABLE) {
+ bar->machine_readable = 1;
+ bar->utf8_mode = 0;
+ bar->have_terminfo = 0;
+ } else {
+ bar->machine_readable = 0;
+
+ bar->utf8_mode = STREQ (nl_langinfo (CODESET), "UTF-8");
+
+ bar->have_terminfo = 0;
+
+ term = getenv ("TERM");
+ if (term) {
+ if (tgetent (NULL, term) == 1)
+ bar->have_terminfo = 1;
+ }
+ }
+
+ /* Call this to ensure the other fields are in a reasonable state.
+ * It is still the caller's responsibility to reset the progress bar
+ * before each command.
+ */
+ progress_bar_reset (bar);
+
+ return bar;
+}
+
+void
+progress_bar_free (struct progress_bar *bar)
+{
+ free (bar);
+}
+
+/* This function is called just before we issue any command. */
+void
+progress_bar_reset (struct progress_bar *bar)
+{
+ /* The time at which this command was issued. */
+ struct timeval start_t;
+ gettimeofday (&start_t, NULL);
+
+ bar->start = start_t.tv_sec + start_t.tv_usec / 1000000.;
+
+ bar->count = 0;
+
+ rmsd_init (&bar->rmsd);
+}
+