Author: dteske
Date: Tue Nov  4 23:46:01 2014
New Revision: 274116
URL: https://svnweb.freebsd.org/changeset/base/274116

Log:
  Add new libraries/utilities for data throughput visualization.
  dpv(3): dialog progress view library
  dpv(1): stream data from stdin or multiple paths with dialog progress view
  figpar(3): configuration file parsing library
  
  Reviews:      D714
  Reviewed by:  jelischer, shurd
  Discussed at: MeetBSD California 2014 Vendor/Dev Summit
  Discussed on: -current
  MFC after:    21 days
  X-MFC-to:     stable/10 stable/9

Added:
  head/lib/libdpv/
  head/lib/libdpv/Makefile   (contents, props changed)
  head/lib/libdpv/dialog_util.c   (contents, props changed)
  head/lib/libdpv/dialog_util.h   (contents, props changed)
  head/lib/libdpv/dialogrc.c   (contents, props changed)
  head/lib/libdpv/dialogrc.h   (contents, props changed)
  head/lib/libdpv/dprompt.c   (contents, props changed)
  head/lib/libdpv/dprompt.h   (contents, props changed)
  head/lib/libdpv/dpv.3   (contents, props changed)
  head/lib/libdpv/dpv.c   (contents, props changed)
  head/lib/libdpv/dpv.h   (contents, props changed)
  head/lib/libdpv/dpv_private.h   (contents, props changed)
  head/lib/libdpv/status.c   (contents, props changed)
  head/lib/libdpv/status.h   (contents, props changed)
  head/lib/libdpv/util.c   (contents, props changed)
  head/lib/libdpv/util.h   (contents, props changed)
  head/lib/libfigpar/
  head/lib/libfigpar/Makefile   (contents, props changed)
  head/lib/libfigpar/figpar.3   (contents, props changed)
  head/lib/libfigpar/figpar.c   (contents, props changed)
  head/lib/libfigpar/figpar.h   (contents, props changed)
  head/lib/libfigpar/string_m.c   (contents, props changed)
  head/lib/libfigpar/string_m.h   (contents, props changed)
  head/usr.bin/dpv/
  head/usr.bin/dpv/Makefile   (contents, props changed)
  head/usr.bin/dpv/dpv.1   (contents, props changed)
  head/usr.bin/dpv/dpv.c   (contents, props changed)
  head/usr.bin/dpv/dpv_util.h   (contents, props changed)
Modified:
  head/lib/Makefile
  head/share/mk/bsd.libnames.mk
  head/sys/sys/param.h
  head/usr.bin/Makefile

Modified: head/lib/Makefile
==============================================================================
--- head/lib/Makefile   Tue Nov  4 23:34:46 2014        (r274115)
+++ head/lib/Makefile   Tue Nov  4 23:46:01 2014        (r274116)
@@ -42,12 +42,14 @@ SUBDIR=     ${SUBDIR_ORDERED} \
        libcrypt \
        libdevinfo \
        libdevstat \
+       libdpv \
        libdwarf \
        libedit \
        ${_libevent} \
        libexecinfo \
        libexpat \
        libfetch \
+       libfigpar \
        libgeom \
        ${_libgpib} \
        ${_libgssapi} \

Added: head/lib/libdpv/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libdpv/Makefile    Tue Nov  4 23:46:01 2014        (r274116)
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+LIB=           dpv
+SHLIB_MAJOR=   1
+INCS=          dpv.h
+MAN=           dpv.3
+MLINKS=                dpv.3 dpv_free.3
+
+CFLAGS+=       -I${.CURDIR}
+LDFLAGS+=      -ldialog -lfigpar -lncurses -lutil
+
+SRCS=          dialog_util.c dialogrc.c dprompt.c dpv.c status.c util.c
+
+WARNS?=                6
+
+.include <bsd.lib.mk>

Added: head/lib/libdpv/dialog_util.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libdpv/dialog_util.c       Tue Nov  4 23:46:01 2014        
(r274116)
@@ -0,0 +1,633 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dte...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "dialog_util.h"
+#include "dpv.h"
+#include "dpv_private.h"
+
+extern char **environ;
+
+#define TTY_DEFAULT_ROWS       24
+#define TTY_DEFAULT_COLS       80
+
+/* [X]dialog(1) characteristics */
+uint8_t dialog_test    = 0;
+uint8_t use_dialog     = 0;
+uint8_t use_libdialog  = 1;
+uint8_t use_xdialog    = 0;
+uint8_t use_color      = 1;
+char dialog[PATH_MAX]  = DIALOG;
+
+/* [X]dialog(1) functionality */
+char *title    = NULL;
+char *backtitle        = NULL;
+int dheight    = 0;
+int dwidth     = 0;
+char *dargv[64]        = { NULL };
+
+/* TTY/Screen characteristics */
+static struct winsize *maxsize = NULL;
+
+/* Function prototypes */
+static void tty_maxsize_update(void);
+static void x11_maxsize_update(void);
+
+/*
+ * Update row/column fields of `maxsize' global (used by dialog_maxrows() and
+ * dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
+ * The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
+ * maximum height and width (respectively) for a dialog(1) widget based on the
+ * active TTY size.
+ *
+ * This function is called automatically by dialog_maxrows/cols() to reflect
+ * changes in terminal size in-between calls.
+ */
+static void
+tty_maxsize_update(void)
+{
+       int fd = STDIN_FILENO;
+       struct termios t;
+
+       if (maxsize == NULL) {
+               if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               memset((void *)maxsize, '\0', sizeof(struct winsize));
+       }
+
+       if (!isatty(fd))
+               fd = open("/dev/tty", O_RDONLY);
+       if ((tcgetattr(fd, &t) < 0) || (ioctl(fd, TIOCGWINSZ, maxsize) < 0)) {
+               maxsize->ws_row = TTY_DEFAULT_ROWS;
+               maxsize->ws_col = TTY_DEFAULT_COLS;
+       }
+}
+
+/*
+ * Update row/column fields of `maxsize' global (used by dialog_maxrows() and
+ * dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
+ * The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
+ * maximum height and width (respectively) for an Xdialog(1) widget based on
+ * the active video resolution of the X11 environment.
+ *
+ * This function is called automatically by dialog_maxrows/cols() to initialize
+ * `maxsize'. Since video resolution changes are less common and more obtrusive
+ * than changes to terminal size, the dialog_maxrows/cols() functions only call
+ * this function when `maxsize' is set to NULL.
+ */
+static void
+x11_maxsize_update(void)
+{
+       FILE *f = NULL;
+       char *cols;
+       char *cp;
+       char *rows;
+       char cmdbuf[LINE_MAX];
+       char rbuf[LINE_MAX];
+
+       if (maxsize == NULL) {
+               if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               memset((void *)maxsize, '\0', sizeof(struct winsize));
+       }
+
+       /* Assemble the command necessary to get X11 sizes */
+       snprintf(cmdbuf, LINE_MAX, "%s --print-maxsize 2>&1", dialog);
+
+       fflush(STDIN_FILENO); /* prevent popen(3) from seeking on stdin */
+
+       if ((f = popen(cmdbuf, "r")) == NULL) {
+               if (debug)
+                       warnx("WARNING! Command `%s' failed", cmdbuf);
+               return;
+       }
+
+       /* Read in the line returned from Xdialog(1) */
+       if ((fgets(rbuf, LINE_MAX, f) == NULL) || (pclose(f) < 0))
+               return;
+
+       /* Check for X11-related errors */
+       if (strncmp(rbuf, "Xdialog: Error", 14) == 0)
+               return;
+
+       /* Parse expected output: MaxSize: YY, XXX */
+       if ((rows = strchr(rbuf, ' ')) == NULL)
+               return;
+       if ((cols = strchr(rows, ',')) != NULL) {
+               /* strtonum(3) doesn't like trailing junk */
+               *(cols++) = '\0';
+               if ((cp = strchr(cols, '\n')) != NULL)
+                       *cp = '\0';
+       }
+
+       /* Convert to unsigned short */
+       maxsize->ws_row = (unsigned short)strtonum(
+           rows, 0, USHRT_MAX, (const char **)NULL);
+       maxsize->ws_col = (unsigned short)strtonum(
+           cols, 0, USHRT_MAX, (const char **)NULL);
+}
+
+/*
+ * Return the current maximum height (rows) for an [X]dialog(1) widget.
+ */
+int
+dialog_maxrows(void)
+{
+
+       if (use_xdialog && maxsize == NULL)
+               x11_maxsize_update(); /* initialize maxsize for GUI */
+       else if (!use_xdialog)
+               tty_maxsize_update(); /* update maxsize for TTY */
+       return (maxsize->ws_row);
+}
+
+/*
+ * Return the current maximum width (cols) for an [X]dialog(1) widget.
+ */
+int
+dialog_maxcols(void)
+{
+
+       if (use_xdialog && maxsize == NULL)
+               x11_maxsize_update(); /* initialize maxsize for GUI */
+       else if (!use_xdialog)
+               tty_maxsize_update(); /* update maxsize for TTY */
+
+       if (use_dialog || use_libdialog) {
+               if (use_shadow)
+                       return (maxsize->ws_col - 2);
+               else
+                       return (maxsize->ws_col);
+       } else
+               return (maxsize->ws_col);
+}
+
+/*
+ * Return the current maximum width (cols) for the terminal.
+ */
+int
+tty_maxcols(void)
+{
+
+       if (use_xdialog && maxsize == NULL)
+               x11_maxsize_update(); /* initialize maxsize for GUI */
+       else if (!use_xdialog)
+               tty_maxsize_update(); /* update maxsize for TTY */
+
+       return (maxsize->ws_col);
+}
+
+/*
+ * Spawn an [X]dialog(1) `--gauge' box with a `--prompt' value of init_prompt.
+ * Writes the resulting process ID to the pid_t pointed at by `pid'. Returns a
+ * file descriptor (int) suitable for writing data to the [X]dialog(1) instance
+ * (data written to the file descriptor is seen as standard-in by the spawned
+ * [X]dialog(1) process).
+ */
+int
+dialog_spawn_gauge(char *init_prompt, pid_t *pid)
+{
+       char dummy_init[2] = "";
+       char *cp;
+       int height;
+       int width;
+       int error;
+       posix_spawn_file_actions_t action;
+#if DIALOG_SPAWN_DEBUG
+       unsigned int i;
+#endif
+       unsigned int n = 0;
+       int stdin_pipe[2] = { -1, -1 };
+
+       /* Override `dialog' with a path from ENV_DIALOG if provided */
+       if ((cp = getenv(ENV_DIALOG)) != NULL)
+               snprintf(dialog, PATH_MAX, "%s", cp);
+
+       /* For Xdialog(1), set ENV_XDIALOG_HIGH_DIALOG_COMPAT */
+       setenv(ENV_XDIALOG_HIGH_DIALOG_COMPAT, "1", 1);
+
+       /* Constrain the height/width */
+       height = dialog_maxrows();
+       if (backtitle != NULL)
+               height -= use_shadow ? 5 : 4;
+       if (dheight < height)
+               height = dheight;
+       width = dialog_maxcols();
+       if (dwidth < width)
+               width = dwidth;
+
+       /* Populate argument array */
+       dargv[n++] = dialog;
+       if (title != NULL) {
+               if ((dargv[n] = malloc(8)) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               sprintf(dargv[n++], "--title");
+               dargv[n++] = title;
+       }
+       if (backtitle != NULL) {
+               if ((dargv[n] = malloc(12)) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               sprintf(dargv[n++], "--backtitle");
+               dargv[n++] = backtitle;
+       }
+       if (use_color) {
+               if ((dargv[n] = malloc(11)) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               sprintf(dargv[n++], "--colors");
+       }
+       if (use_xdialog) {
+               if ((dargv[n] = malloc(7)) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               sprintf(dargv[n++], "--left");
+
+               /*
+                * NOTE: Xdialog(1)'s `--wrap' appears to be broken for the
+                * `--gauge' widget prompt-updates. Add it anyway (in-case it
+                * gets fixed in some later release).
+                */
+               if ((dargv[n] = malloc(7)) == NULL)
+                       errx(EXIT_FAILURE, "Out of memory?!");
+               sprintf(dargv[n++], "--wrap");
+       }
+       if ((dargv[n] = malloc(8)) == NULL)
+               errx(EXIT_FAILURE, "Out of memory?!");
+       sprintf(dargv[n++], "--gauge");
+       dargv[n++] = use_xdialog ? dummy_init : init_prompt;
+       if ((dargv[n] = malloc(40)) == NULL)
+               errx(EXIT_FAILURE, "Out of memory?!");
+       snprintf(dargv[n++], 40, "%u", height);
+       if ((dargv[n] = malloc(40)) == NULL)
+               errx(EXIT_FAILURE, "Out of memory?!");
+       snprintf(dargv[n++], 40, "%u", width);
+       dargv[n] = NULL;
+
+       /* Open a pipe(2) to communicate with [X]dialog(1) */
+       if (pipe(stdin_pipe) < 0)
+               err(EXIT_FAILURE, "%s: pipe(2)", __func__);
+
+       /* Fork [X]dialog(1) process */
+#if DIALOG_SPAWN_DEBUG
+       fprintf(stderr, "%s: spawning `", __func__);
+       for (i = 0; i < n; i++) {
+               if (i == 0)
+                       fprintf(stderr, "%s", dargv[i]);
+               else if (*dargv[i] == '-' && *(dargv[i] + 1) == '-')
+                       fprintf(stderr, " %s", dargv[i]);
+               else
+                       fprintf(stderr, " \"%s\"", dargv[i]);
+       }
+       fprintf(stderr, "'\n");
+#endif
+       posix_spawn_file_actions_init(&action);
+       posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
+       posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
+       error = posix_spawnp(pid, dialog, &action,
+           (const posix_spawnattr_t *)NULL, dargv, environ);
+       if (error != 0)
+               err(EXIT_FAILURE, "%s: posix_spawnp(3)", __func__);
+
+       /* NB: Do not free(3) *dargv[], else SIGSEGV */
+
+       return (stdin_pipe[1]);
+}
+
+/*
+ * Returns the number of lines in buffer pointed to by `prompt'. Takes both
+ * newlines and escaped-newlines into account.
+ */
+unsigned int
+dialog_prompt_numlines(const char *prompt, uint8_t nlstate)
+{
+       uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+       const char *cp = prompt;
+       unsigned int nlines = 1;
+
+       if (prompt == NULL || *prompt == '\0')
+               return (0);
+
+       while (*cp != '\0') {
+               if (use_dialog) {
+                       if (strncmp(cp, "\\n", 2) == 0) {
+                               cp++;
+                               nlines++;
+                               nls = TRUE; /* See declaration comment */
+                       } else if (*cp == '\n') {
+                               if (!nls)
+                                       nlines++;
+                               nls = FALSE; /* See declaration comment */
+                       }
+               } else if (use_libdialog) {
+                       if (*cp == '\n')
+                               nlines++;
+               } else if (strncmp(cp, "\\n", 2) == 0) {
+                       cp++;
+                       nlines++;
+               }
+               cp++;
+       }
+
+       return (nlines);
+}
+
+/*
+ * Returns the length in bytes of the longest line in buffer pointed to by
+ * `prompt'. Takes newlines and escaped newlines into account. Also discounts
+ * dialog(1) color escape codes if enabled (via `use_color' global).
+ */
+unsigned int
+dialog_prompt_longestline(const char *prompt, uint8_t nlstate)
+{
+       uint8_t backslash = 0;
+       uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+       const char *p = prompt;
+       int longest = 0;
+       int n = 0;
+
+       /* `prompt' parameter is required */
+       if (prompt == NULL)
+               return (0);
+       if (*prompt == '\0')
+               return (0); /* shortcut */
+
+       /* Loop until the end of the string */
+       while (*p != '\0') {
+               /* dialog(1) and dialog(3) will render literal newlines */
+               if (use_dialog || use_libdialog) {
+                       if (*p == '\n') {
+                               if (!use_libdialog && nls)
+                                       n++;
+                               else {
+                                       if (n > longest)
+                                               longest = n;
+                                       n = 0;
+                               }
+                               nls = FALSE; /* See declaration comment */
+                               p++;
+                               continue;
+                       }
+               }
+
+               /* Check for backslash character */
+               if (*p == '\\') {
+                       /* If second backslash, count as a single-char */
+                       if ((backslash ^= 1) == 0)
+                               n++;
+               } else if (backslash) {
+                       if (*p == 'n' && !use_libdialog) { /* new line */
+                               /* NB: dialog(3) ignores escaped newlines */
+                               nls = TRUE; /* See declaration comment */
+                               if (n > longest)
+                                       longest = n;
+                               n = 0;
+                       } else if (use_color && *p == 'Z') {
+                               if (*++p != '\0')
+                                       p++;
+                               backslash = 0;
+                               continue;
+                       } else /* [X]dialog(1)/dialog(3) only expand those */
+                               n += 2;
+
+                       backslash = 0;
+               } else
+                       n++;
+               p++;
+       }
+       if (n > longest)
+               longest = n;
+
+       return (longest);
+}
+
+/*
+ * Returns a pointer to the last line in buffer pointed to by `prompt'. Takes
+ * both newlines (if using dialog(1) versus Xdialog(1)) and escaped newlines
+ * into account. If no newlines (escaped or otherwise) appear in the buffer,
+ * `prompt' is returned. If passed a NULL pointer, returns NULL.
+ */
+char *
+dialog_prompt_lastline(char *prompt, uint8_t nlstate)
+{
+       uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+       char *lastline;
+       char *p;
+
+       if (prompt == NULL)
+               return (NULL);
+       if (*prompt == '\0')
+               return (prompt); /* shortcut */
+
+       lastline = p = prompt;
+       while (*p != '\0') {
+               /* dialog(1) and dialog(3) will render literal newlines */
+               if (use_dialog || use_libdialog) {
+                       if (*p == '\n') {
+                               if (use_libdialog || !nls)
+                                       lastline = p + 1;
+                               nls = FALSE; /* See declaration comment */
+                       }
+               }
+               /* dialog(3) does not expand escaped newlines */
+               if (use_libdialog) {
+                       p++;
+                       continue;
+               }
+               if (*p == '\\' && *(p + 1) != '\0' && *(++p) == 'n') {
+                       nls = TRUE; /* See declaration comment */
+                       lastline = p + 1;
+               }
+               p++;
+       }
+
+       return (lastline);
+}
+
+/*
+ * Returns the number of extra lines generated by wrapping the text in buffer
+ * pointed to by `prompt' within `ncols' columns (for prompts, this should be
+ * dwidth - 4). Also discounts dialog(1) color escape codes if enabled (via
+ * `use_color' global).
+ */
+int
+dialog_prompt_wrappedlines(char *prompt, int ncols, uint8_t nlstate)
+{
+       uint8_t backslash = 0;
+       uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+       char *cp;
+       char *p = prompt;
+       int n = 0;
+       int wlines = 0;
+
+       /* `prompt' parameter is required */
+       if (p == NULL)
+               return (0);
+       if (*p == '\0')
+               return (0); /* shortcut */
+
+       /* Loop until the end of the string */
+       while (*p != '\0') {
+               /* dialog(1) and dialog(3) will render literal newlines */
+               if (use_dialog || use_libdialog) {
+                       if (*p == '\n') {
+                               if (use_dialog || !nls)
+                                       n = 0;
+                               nls = FALSE; /* See declaration comment */
+                       }
+               }
+
+               /* Check for backslash character */
+               if (*p == '\\') {
+                       /* If second backslash, count as a single-char */
+                       if ((backslash ^= 1) == 0)
+                               n++;
+               } else if (backslash) {
+                       if (*p == 'n' && !use_libdialog) { /* new line */
+                               /* NB: dialog(3) ignores escaped newlines */
+                               nls = TRUE; /* See declaration comment */
+                               n = 0;
+                       } else if (use_color && *p == 'Z') {
+                               if (*++p != '\0')
+                                       p++;
+                               backslash = 0;
+                               continue;
+                       } else /* [X]dialog(1)/dialog(3) only expand those */
+                               n += 2;
+
+                       backslash = 0;
+               } else
+                       n++;
+
+               /* Did we pass the width barrier? */
+               if (n > ncols) {
+                       /*
+                        * Work backward to find the first whitespace on-which
+                        * dialog(1) will wrap the line (but don't go before
+                        * the start of this line).
+                        */
+                       cp = p;
+                       while (n > 1 && !isspace(*cp)) {
+                               cp--;
+                               n--;
+                       }
+                       if (n > 0 && isspace(*cp))
+                               p = cp;
+                       wlines++;
+                       n = 1;
+               }
+
+               p++;
+       }
+
+       return (wlines);
+}
+
+/*
+ * Returns zero if the buffer pointed to by `prompt' contains an escaped
+ * newline but only if appearing after any/all literal newlines. This is
+ * specific to dialog(1) and does not apply to Xdialog(1).
+ *
+ * As an attempt to make shell scripts easier to read, dialog(1) will "eat"
+ * the first literal newline after an escaped newline. This however has a bug
+ * in its implementation in that rather than allowing `\\n\n' to be treated
+ * similar to `\\n' or `\n', dialog(1) expands the `\\n' and then translates
+ * the following literal newline (with or without characters between [!]) into
+ * a single space.
+ *
+ * If you want to be compatible with Xdialog(1), it is suggested that you not
+ * use literal newlines (they aren't supported); but if you have to use them,
+ * go right ahead. But be forewarned... if you set $DIALOG in your environment
+ * to something other than `cdialog' (our current dialog(1)), then it should
+ * do the same thing w/respect to how to handle a literal newline after an
+ * escaped newline (you could do no wrong by translating every literal newline
+ * into a space but only when you've previously encountered an escaped one;
+ * this is what dialog(1) is doing).
+ *
+ * The ``newline state'' (or nlstate for short; as I'm calling it) is helpful
+ * if you plan to combine multiple strings into a single prompt text. In lead-
+ * up to this procedure, a common task is to calculate and utilize the widths
+ * and heights of each piece of prompt text to later be combined. However, if
+ * (for example) the first string ends in a positive newline state (has an
+ * escaped newline without trailing literal), the first literal newline in the
+ * second string will be mangled.
+ *
+ * The return value of this function should be used as the `nlstate' argument
+ * to dialog_*() functions that require it to allow accurate calculations in
+ * the event such information is needed.
+ */
+uint8_t
+dialog_prompt_nlstate(const char *prompt)
+{
+       const char *cp;
+
+       if (prompt == NULL)
+               return 0;
+
+       /*
+        * Work our way backward from the end of the string for efficiency.
+        */
+       cp = prompt + strlen(prompt);
+       while (--cp >= prompt) {
+               /*
+                * If we get to a literal newline first, this prompt ends in a
+                * clean state for rendering with dialog(1). Otherwise, if we
+                * get to an escaped newline first, this prompt ends in an un-
+                * clean state (following literal will be mangled; see above).
+                */
+               if (*cp == '\n')
+                       return (0);
+               else if (*cp == 'n' && --cp > prompt && *cp == '\\')
+                       return (1);
+       }
+
+       return (0); /* no newlines (escaped or otherwise) */
+}
+
+/*
+ * Free allocated items initialized by tty_maxsize_update() and
+ * x11_maxsize_update()
+ */
+void
+dialog_maxsize_free(void)
+{
+       if (maxsize != NULL) {
+               free(maxsize);
+               maxsize = NULL;
+       }
+}

Added: head/lib/libdpv/dialog_util.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libdpv/dialog_util.h       Tue Nov  4 23:46:01 2014        
(r274116)
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dte...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DIALOG_UTIL_H_
+#define _DIALOG_UTIL_H_
+
+#include <sys/types.h>
+
+#include "dialogrc.h"
+
+#define DIALOG_SPAWN_DEBUG     0       /* Debug spawning of [X]dialog(1) */
+
+/* dialog(3) and [X]dialog(1) characteristics */
+#define DIALOG         "dialog"
+#define XDIALOG                "Xdialog"
+#define PROMPT_MAX     16384
+#define ENV_DIALOG     "DIALOG"
+#define ENV_USE_COLOR  "USE_COLOR"
+#define ENV_XDIALOG_HIGH_DIALOG_COMPAT "XDIALOG_HIGH_DIALOG_COMPAT"
+extern uint8_t dialog_test;
+extern uint8_t use_libdialog;
+extern uint8_t use_dialog;
+extern uint8_t use_xdialog;
+extern uint8_t use_color;
+extern char dialog[];
+
+/* dialog(3) and [X]dialog(1) functionality */
+extern char *title, *backtitle;
+extern int dheight, dwidth;
+
+__BEGIN_DECLS
+uint8_t                 dialog_prompt_nlstate(const char *_prompt);
+void            dialog_gauge_free(void);
+void            dialog_maxsize_free(void);
+char           *dialog_prompt_lastline(char *_prompt, uint8_t _nlstate);
+int             dialog_maxcols(void);
+int             dialog_maxrows(void);
+int             dialog_prompt_wrappedlines(char *_prompt, int _ncols,
+                   uint8_t _nlstate);
+int             dialog_spawn_gauge(char *_init_prompt, pid_t *_pid);
+int             tty_maxcols(void);
+#define                 tty_maxrows() dialog_maxrows()
+unsigned int    dialog_prompt_longestline(const char *_prompt,
+                   uint8_t _nlstate);
+unsigned int    dialog_prompt_numlines(const char *_prompt, uint8_t _nlstate);
+__END_DECLS
+
+#endif /* !_DIALOG_UTIL_H_ */

Added: head/lib/libdpv/dialogrc.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libdpv/dialogrc.c  Tue Nov  4 23:46:01 2014        (r274116)
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dte...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <figpar.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_m.h>
+
+#include "dialogrc.h"
+
+#define STR_BUFSIZE 255
+
+/* dialog(1) `.dialogrc' characteristics */
+uint8_t use_colors = 1;
+uint8_t use_shadow = 1;
+char gauge_color[STR_BUFSIZE]  = "47b"; /* (BLUE,WHITE,ON) */
+char separator[STR_BUFSIZE]    = "";
+
+/* Function prototypes */
+static int setattr(struct config *, uint32_t, char *, char *);
+static int setbool(struct config *, uint32_t, char *, char *);
+static int setnum(struct config *, uint32_t, char *, char *);
+static int setstr(struct config *, uint32_t, char *, char *);
+
+/*
+ * Anatomy of DIALOGRC (~/.dialogrc by default)
+ * NOTE: Must appear after private function prototypes (above)
+ * NB: Brace-initialization of union requires cast to *first* member of union
+ */
+static struct config dialogrc_config[] = {
+    /* TYPE     Directive                      DEFAULT         HANDLER */
+    {TYPE_INT, "aspect",                       {(void *)0},    &setnum},
+    {TYPE_STR, "separate_widget",              {separator},    &setstr},
+    {TYPE_INT, "tab_len",                      {(void *)0},    &setnum},
+    {TYPE_BOOL,        "visit_items",                  {(void *)0},    
&setbool},
+    {TYPE_BOOL, "use_shadow",                  {(void *)1},    &setbool},
+    {TYPE_BOOL, "use_colors",                  {(void *)1},    &setbool},
+    {TYPE_STR, "screen_color",                 {NULL},         &setattr},
+    {TYPE_STR, "shadow_color",                 {NULL},         &setattr},
+    {TYPE_STR, "dialog_color",                 {NULL},         &setattr},
+    {TYPE_STR, "title_color",                  {NULL},         &setattr},
+    {TYPE_STR, "border_color",                 {NULL},         &setattr},
+    {TYPE_STR, "button_active_color",          {NULL},         &setattr},
+    {TYPE_STR, "button_inactive_color",        {NULL},         &setattr},
+    {TYPE_STR, "button_key_active_color",      {NULL},         &setattr},
+    {TYPE_STR, "button_key_inactive_color",    {NULL},         &setattr},
+    {TYPE_STR, "button_label_active_color",    {NULL},         &setattr},
+    {TYPE_STR, "button_label_inactive_color",  {NULL},         &setattr},
+    {TYPE_STR, "inputbox_color",               {NULL},         &setattr},
+    {TYPE_STR, "inputbox_border_color",        {NULL},         &setattr},
+    {TYPE_STR, "searchbox_color",              {NULL},         &setattr},
+    {TYPE_STR, "searchbox_title_color",        {NULL},         &setattr},
+    {TYPE_STR, "searchbox_border_color",       {NULL},         &setattr},
+    {TYPE_STR, "position_indicator_color",     {NULL},         &setattr},
+    {TYPE_STR, "menubox_color",                {NULL},         &setattr},
+    {TYPE_STR, "menubox_border_color",         {NULL},         &setattr},
+    {TYPE_STR, "item_color",                   {NULL},         &setattr},
+    {TYPE_STR, "item_selected_color",          {NULL},         &setattr},
+    {TYPE_STR, "tag_color",                    {NULL},         &setattr},
+    {TYPE_STR, "tag_selected_color",           {NULL},         &setattr},
+    {TYPE_STR, "tag_key_color",                {NULL},         &setattr},
+    {TYPE_STR, "tag_key_selected_color",       {NULL},         &setattr},
+    {TYPE_STR, "check_color",                  {NULL},         &setattr},
+    {TYPE_STR, "check_selected_color",         {NULL},         &setattr},
+    {TYPE_STR, "uarrow_color",                 {NULL},         &setattr},
+    {TYPE_STR, "darrow_color",                 {NULL},         &setattr},
+    {TYPE_STR, "itemhelp_color",               {NULL},         &setattr},
+    {TYPE_STR, "form_active_text_color",       {NULL},         &setattr},
+    {TYPE_STR, "form_text_color",              {NULL},         &setattr},
+    {TYPE_STR, "form_item_readonly_color",     {NULL},         &setattr},
+    {TYPE_STR, "gauge_color",                  {gauge_color},  &setattr},
+    {0, NULL, {0}, NULL}
+};
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Attribute'
+ */
+static int
+setattr(struct config *option, uint32_t line __unused,
+    char *directive __unused, char *value)
+{
+       char *cp = value;
+       char *val;
+       size_t len;
+       char attrbuf[4];
+
+       if (option == NULL) {
+               warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+                   __LINE__, __func__);
+               return (-1); /* Abort processing */
+       }
+
+       /* Allocate memory for the data if not already done */
+       if (option->value.str == NULL) {
+               if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
+                       return (-1);
+       }
+
+       /*
+        * If the first character is left-parenthesis, the format is
+        * `(background,foreground,highlight)' otherwise, we should take it
+        * as a reference to another color.
+        */
+       if (*cp != '(') {
+               /* Copy the [current] value from the referenced color */
+               val = dialogrc_config_option(cp)->value.str;
+               if (val != NULL)
+                       snprintf(option->value.str, STR_BUFSIZE, "%s", val);
+
+               return (0);
+       } else
+               cp++;
+
+       strtolower(cp);
+
+       /* Initialize the attrbuf (fg,bg,hi,NUL) */
+       attrbuf[0] = '0';
+       attrbuf[1] = '0';
+       attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */
+       attrbuf[3] = '\0';
+
+       /* Interpret the foreground color */
+       if      (strncmp(cp, "red,",     4) == 0) attrbuf[0] = '1';
+       else if (strncmp(cp, "green,",   6) == 0) attrbuf[0] = '2';
+       else if (strncmp(cp, "yellow,",  7) == 0) attrbuf[0] = '3';
+       else if (strncmp(cp, "blue,",    5) == 0) attrbuf[0] = '4';
+       else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5';
+       else if (strncmp(cp, "cyan,",    5) == 0) attrbuf[0] = '6';
+       else if (strncmp(cp, "white,",   6) == 0) attrbuf[0] = '7';
+       else if (strncmp(cp, "black,",   6) == 0) attrbuf[0] = '8';
+
+       /* Advance to the background color */
+       cp = strchr(cp, ',');
+       if (cp == NULL)
+               goto write_attrbuf;
+       else
+               cp++;
+
+       /* Interpret the background color */
+       if      (strncmp(cp, "red,",     4) == 0) attrbuf[1] = '1';
+       else if (strncmp(cp, "green,",   6) == 0) attrbuf[1] = '2';
+       else if (strncmp(cp, "yellow,",  7) == 0) attrbuf[1] = '3';
+       else if (strncmp(cp, "blue,",    5) == 0) attrbuf[1] = '4';
+       else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5';
+       else if (strncmp(cp, "cyan,",    5) == 0) attrbuf[1] = '6';
+       else if (strncmp(cp, "white,",   6) == 0) attrbuf[1] = '7';
+       else if (strncmp(cp, "black,",   6) == 0) attrbuf[1] = '8';
+
+       /* Advance to the highlight */
+       cp = strchr(cp, ',');
+       if (cp == NULL)
+               goto write_attrbuf;
+       else
+               cp++;
+
+       /* Trim trailing parenthesis */
+       len = strlen(cp);
+       if (cp[len - 1] == ')')
+               cp[len - 1] = '\0';
+
+       /* Interpret the highlight (initialized to off above) */
+       if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0)
+               attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */
+
+write_attrbuf:
+       sprintf(option->value.str, "%s", attrbuf);
+
+       return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Boolean'
+ */
+static int
+setbool(struct config *option, uint32_t line __unused,
+    char *directive __unused, char *value)
+{
+
+       if (option == NULL) {
+               warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+                   __LINE__, __func__);
+               return (-1); /* Abort processing */
+       }
+
+       /* Assume ON, check for OFF (case-insensitive) */
+       option->value.boolean = 1;
+       strtolower(value);
+       if (strcmp(value, "off") == 0)
+               option->value.boolean = 0;
+
+       return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Number'
+ */
+static int
+setnum(struct config *option, uint32_t line __unused, char *directive __unused,
+    char *value)
+{
+
+       if (option == NULL) {
+               warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+                   __LINE__, __func__);
+               return (-1); /* Abort processing */
+       }
+
+       /* Convert the string to a 32-bit signed integer */
+       option->value.num = (int32_t)strtol(value, (char **)NULL, 10);
+
+       return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `String'
+ */
+static int

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to