diff options
author | Colin Walters <walters@verbum.org> | 2015-02-15 18:18:54 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2015-02-17 16:52:49 -0500 |
commit | 64936b67001410974f1bd92803a46cdb77f89db5 (patch) | |
tree | 53ca6072625baf195d4556c294d2278a83ef8fde | |
parent | 70b070b5eab16907fd6f53de100c31733a6fa7da (diff) | |
download | libglnx-64936b67001410974f1bd92803a46cdb77f89db5.tar.gz |
Import console from rpm-ostree
This contains some basic progress bar drawing code for now.
-rw-r--r-- | Makefile-libglnx.am | 2 | ||||
-rw-r--r-- | glnx-console.c | 268 | ||||
-rw-r--r-- | glnx-console.h | 47 | ||||
-rw-r--r-- | libglnx.h | 1 |
4 files changed, 318 insertions, 0 deletions
diff --git a/Makefile-libglnx.am b/Makefile-libglnx.am index a04f19e..7463395 100644 --- a/Makefile-libglnx.am +++ b/Makefile-libglnx.am @@ -24,6 +24,8 @@ libglnx_la_SOURCES = \ $(libglnx_srcpath)/glnx-local-alloc.c \ $(libglnx_srcpath)/glnx-errors.h \ $(libglnx_srcpath)/glnx-errors.c \ + $(libglnx_srcpath)/glnx-console.h \ + $(libglnx_srcpath)/glnx-console.c \ $(libglnx_srcpath)/glnx-dirfd.h \ $(libglnx_srcpath)/glnx-dirfd.c \ $(libglnx_srcpath)/glnx-xattrs.h \ diff --git a/glnx-console.c b/glnx-console.c new file mode 100644 index 0000000..5ae29b1 --- /dev/null +++ b/glnx-console.c @@ -0,0 +1,268 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters <walters@verbum.org> + * + * This program 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 2 of the licence 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-console.h" + +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <sys/ioctl.h> + +static char *current_text = NULL; +static gint current_percent = -1; +static gboolean locked; + +static gboolean +stdout_is_tty (void) +{ + static gsize initialized = 0; + static gboolean stdout_is_tty_v; + + if (g_once_init_enter (&initialized)) + { + stdout_is_tty_v = isatty (1); + g_once_init_leave (&initialized, 1); + } + + return stdout_is_tty_v; +} + +static volatile guint cached_columns = 0; +static volatile guint cached_lines = 0; + +static int +fd_columns (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_col <= 0) + return -EIO; + + return ws.ws_col; +} + +static guint +columns (void) +{ + if (G_UNLIKELY (cached_columns == 0)) + { + int c; + + c = fd_columns (STDOUT_FILENO); + + if (c <= 0) + c = 80; + + if (c > 256) + c = 256; + + cached_columns = c; + } + + return cached_columns; +} + +#if 0 +static int +fd_lines (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_row <= 0) + return -EIO; + + return ws.ws_row; +} + +static guint +lines (void) +{ + if (G_UNLIKELY (cached_lines == 0)) + { + int l; + + l = fd_lines (STDOUT_FILENO); + + if (l <= 0) + l = 24; + + cached_lines = l; + } + + return cached_lines; +} +#endif + +static void +on_sigwinch (int signum) +{ + cached_columns = 0; + cached_lines = 0; +} + +void +glnx_console_lock (GLnxConsoleRef *console) +{ + static gsize sigwinch_initialized = 0; + + if (!stdout_is_tty ()) + return; + + g_return_if_fail (!locked); + g_return_if_fail (!console->locked); + + locked = console->locked = TRUE; + + current_percent = 0; + + if (g_once_init_enter (&sigwinch_initialized)) + { + signal (SIGWINCH, on_sigwinch); + g_once_init_leave (&sigwinch_initialized, 1); + } + + { static const char initbuf[] = { '\n', 0x1B, 0x37 }; + (void) fwrite (initbuf, 1, sizeof (initbuf), stdout); + } +} + +static void +printpad (const char *padbuf, + guint padbuf_len, + guint n) +{ + const guint d = n / padbuf_len; + const guint r = n % padbuf_len; + guint i; + + for (i = 0; i < d; i++) + fwrite (padbuf, 1, padbuf_len, stdout); + fwrite (padbuf, 1, r, stdout); +} + +/** + * glnx_console_progress_text_percent: + * @text: Show this text before the progress bar + * @percentage: An integer in the range of 0 to 100 + * + * Print to the console @text followed by an ASCII art progress bar + * whose percentage is @percentage. + * + * You must have called glnx_console_lock() before invoking this + * function. + * + * Currently, if stdout is not a tty, this function does nothing. + */ +void +glnx_console_progress_text_percent (const char *text, + guint percentage) +{ + static const char equals[] = "===================="; + const guint n_equals = sizeof (equals) - 1; + static const char spaces[] = " "; + const guint n_spaces = sizeof (spaces) - 1; + const guint ncolumns = columns (); + const guint bar_min = 10; + const guint input_textlen = text ? strlen (text) : 0; + guint textlen; + guint barlen; + + if (!stdout_is_tty ()) + return; + + g_return_if_fail (percentage >= 0 && percentage <= 100); + + if (text && !*text) + text = NULL; + + if (percentage == current_percent + && g_strcmp0 (text, current_text) == 0) + return; + + if (ncolumns < bar_min) + return; /* TODO: spinner */ + + /* Restore cursor */ + { const char beginbuf[2] = { 0x1B, 0x38 }; + (void) fwrite (beginbuf, 1, sizeof (beginbuf), stdout); + } + + textlen = MIN (input_textlen, ncolumns - bar_min); + barlen = ncolumns - textlen; + + if (textlen > 0) + { + fwrite (text, 1, textlen - 1, stdout); + fputc (' ', stdout); + } + + { + const guint nbraces = 2; + const guint textpercent_len = 5; + const guint bar_internal_len = barlen - nbraces - textpercent_len; + const guint eqlen = bar_internal_len * (percentage / 100.0); + const guint spacelen = bar_internal_len - eqlen; + + fputc ('[', stdout); + printpad (equals, n_equals, eqlen); + printpad (spaces, n_spaces, spacelen); + fputc (']', stdout); + fprintf (stdout, " %3d%%", percentage); + } + + { const guint spacelen = ncolumns - textlen - barlen; + printpad (spaces, n_spaces, spacelen); + } + + fflush (stdout); +} + +/** + * glnx_console_unlock: + * + * Print a newline, and reset all cached console progress state. + * + * This function does nothing if stdout is not a tty. + */ +void +glnx_console_unlock (GLnxConsoleRef *console) +{ + if (!stdout_is_tty ()) + return; + + g_return_if_fail (locked); + g_return_if_fail (console->locked); + + current_percent = -1; + g_clear_pointer (¤t_text, g_free); + fputc ('\n', stdout); + + locked = FALSE; +} diff --git a/glnx-console.h b/glnx-console.h new file mode 100644 index 0000000..3dfdf1b --- /dev/null +++ b/glnx-console.h @@ -0,0 +1,47 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters <walters@verbum.org> + * + * This program 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 2 of the licence 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include <glnx-backport-autoptr.h> + +G_BEGIN_DECLS + +struct GLnxConsoleRef { + gboolean locked; +}; + +typedef struct GLnxConsoleRef GLnxConsoleRef; + +void glnx_console_lock (GLnxConsoleRef *ref); + +void glnx_console_progress_text_percent (const char *text, + guint percentage); + +void glnx_console_unlock (GLnxConsoleRef *ref); + +static inline void +glnx_console_ref_cleanup (GLnxConsoleRef *p) +{ + glnx_console_unlock (p); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxConsoleRef, glnx_console_ref_cleanup) + +G_END_DECLS @@ -31,5 +31,6 @@ G_BEGIN_DECLS #include <glnx-dirfd.h> #include <glnx-shutil.h> #include <glnx-xattrs.h> +#include <glnx-console.h> G_END_DECLS |