Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ttyplot for openSUSE:Factory checked in at 2025-09-15 19:52:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ttyplot (Old) and /work/SRC/openSUSE:Factory/.ttyplot.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ttyplot" Mon Sep 15 19:52:53 2025 rev:3 rq:1304742 version:1.7.4 Changes: -------- --- /work/SRC/openSUSE:Factory/ttyplot/ttyplot.changes 2025-04-07 18:41:56.556865790 +0200 +++ /work/SRC/openSUSE:Factory/.ttyplot.new.1977/ttyplot.changes 2025-09-15 19:56:56.429265403 +0200 @@ -1,0 +2,6 @@ +Sat Sep 13 06:31:21 UTC 2025 - Martin Hauke <[email protected]> + +- Update to version 1.7.4 + * fix negative dual line issues + +------------------------------------------------------------------- Old: ---- ttyplot-1.7.1.tar.gz New: ---- ttyplot-1.7.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ttyplot.spec ++++++ --- /var/tmp/diff_new_pack.rxUR8V/_old 2025-09-15 19:56:56.937286735 +0200 +++ /var/tmp/diff_new_pack.rxUR8V/_new 2025-09-15 19:56:56.937286735 +0200 @@ -1,7 +1,7 @@ # # spec file for package ttyplot # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # Copyright (c) 2023-2025, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -18,7 +18,7 @@ Name: ttyplot -Version: 1.7.1 +Version: 1.7.4 Release: 0 Summary: Realtime plotting utility for terminals License: Apache-2.0 ++++++ ttyplot-1.7.1.tar.gz -> ttyplot-1.7.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/.github/workflows/clang_format.yml new/ttyplot-1.7.4/.github/workflows/clang_format.yml --- old/ttyplot-1.7.1/.github/workflows/clang_format.yml 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/.github/workflows/clang_format.yml 2025-08-18 04:21:27.000000000 +0200 @@ -21,7 +21,7 @@ env: CLANG_MAJOR_VERSION: 17 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Add Clang/LLVM repositories run: |- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/.github/workflows/codespell.yml new/ttyplot-1.7.4/.github/workflows/codespell.yml --- old/ttyplot-1.7.1/.github/workflows/codespell.yml 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/.github/workflows/codespell.yml 2025-08-18 04:21:27.000000000 +0200 @@ -19,7 +19,7 @@ name: Enforce codespell-clean spelling runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 # v2.1 with: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/.github/workflows/linux_and_macos.yml new/ttyplot-1.7.4/.github/workflows/linux_and_macos.yml --- old/ttyplot-1.7.1/.github/workflows/linux_and_macos.yml 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/.github/workflows/linux_and_macos.yml 2025-08-18 04:21:27.000000000 +0200 @@ -37,21 +37,21 @@ clang_repo_suffix: null make: bmake runs-on: ubuntu-22.04 - - cc: gcc-12 + - cc: gcc-13 clang_major_version: null clang_repo_suffix: null make: make - runs-on: macos-12 - - cc: gcc-13 + runs-on: macos-13 + - cc: gcc-14 clang_major_version: null clang_repo_suffix: null make: bmake - runs-on: macos-12 - - cc: clang-15 - clang_major_version: 15 + runs-on: macos-14 + - cc: clang-18 + clang_major_version: 18 clang_repo_suffix: null make: bsdmake - runs-on: macos-12 + runs-on: macos-15 steps: - name: Add Clang/LLVM repositories if: "${{ runner.os == 'Linux' && contains(matrix.cc, 'clang') }}" @@ -94,7 +94,7 @@ sudo ln -s "$(brew --prefix llvm@${{ matrix.clang_major_version }})"/bin/clang++ /usr/local/bin/clang++-${{ matrix.clang_major_version }} - name: Checkout Git branch - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Build musl Ncurses if: "${{ runner.os == 'Linux' && contains(matrix.cc, 'musl') }}" @@ -151,8 +151,8 @@ as_needed='-Wl,--as-needed' fi - # musl-gcc does not seem to support linking with sanitizers - if [[ ${{ matrix.cc }} =~ musl ]]; then + # musl-gcc and gcc/macOS do not seem to support linking with sanitizers + if [[ ${{ matrix.cc }} =~ musl || ${{ matrix.cc }} =~ gcc && ${{ matrix.runs-on }} =~ macos ]]; then sanitizer= else # ASan: https://clang.llvm.org/docs/AddressSanitizer.html @@ -205,8 +205,10 @@ ################################################################ EOF + eval `grep ^VERSION Makefile | tr -d ' '` + sed "s/@VERSION@/$VERSION/" recordings/template.txt > recordings/expected.txt diff -u recordings/{expected,actual}.txt - rm -f recordings/actual.txt + rm -f recordings/{expected,actual}.txt - name: 'Clean' env: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/Makefile new/ttyplot-1.7.4/Makefile --- old/ttyplot-1.7.1/Makefile 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/Makefile 2025-08-18 04:21:27.000000000 +0200 @@ -1,6 +1,8 @@ +VERSION = 1.7.3 DESTDIR ?= PREFIX ?= /usr/local MANPREFIX ?= $(PREFIX)/man +CPPFLAGS += -DVERSION_STR='"$(VERSION)"' CFLAGS += -Wall -Wextra CFLAGS += `pkg-config --cflags ncursesw` LDLIBS += `pkg-config --libs ncursesw` -lm @@ -22,6 +24,6 @@ .c: @pkg-config --version > /dev/null - $(CC) $(CFLAGS) $(LDFLAGS) $< $(LDLIBS) -o $@ + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $< $(LDLIBS) -o $@ .PHONY: all clean install uninstall diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/README.md new/ttyplot-1.7.4/README.md --- old/ttyplot-1.7.1/README.md 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/README.md 2025-08-18 04:21:27.000000000 +0200 @@ -67,6 +67,8 @@ ## examples +note: the examples provided are not meant to be exhaustive or even fully working in every case, just some ideas to expand on + ### cpu usage from vmstat using awk to pick the right column `fflush()` is needed to disable stdio buffering @@ -235,12 +237,19 @@ -M minimum value, if entered less than this, draws error symbol (see -E), lower-limit of the plot scale is fixed -t title of the plot -u unit displayed beside vertical bar - -C color[,axes,text,title] set colors (0-7) for elements: + -C color[,axes,text,title,max_err,min_err] set colors (0-7) for elements: First value: plot line color Second value: axes color (optional) Third value: text color (optional) Fourth value: title color (optional) - Example: -C 1,2,3,4 or -C 1,2 or -C 1 + Fifth value: max error indicator color (optional) + Sixth value: min error indicator color (optional) + Example: -C 1,2,3,4,5,6 or -C 1,2 or -C 1 + Predefined color schemes: + -C dark1 Blue-cyan-yellow scheme for dark terminals + -C dark2 Purple-yellow-green scheme for dark terminals + -C light1 Green-blue-red scheme for light terminals + -C light2 Blue-green-yellow scheme for light terminals Colors: 0=black, 1=red, 2=green, 3=yellow, 4=blue, 5=magenta, 6=cyan, 7=white -v print the current version and exit -h print this help message and exit @@ -258,6 +267,7 @@ ``` q quit r toggle rate mode + ^L full screen redraw ``` these commands do not work if the standard input is a terminal: in this case quit with <kbd>Ctrl</kbd>-<kbd>C</kbd>. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/recordings/expected.txt new/ttyplot-1.7.4/recordings/expected.txt --- old/ttyplot-1.7.1/recordings/expected.txt 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/recordings/expected.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,72 +0,0 @@ -[90x20] Frame 1: -+------------------------------------------------------------------------------------------+ -| .: ttyplot :. | -| ^ | -| │ | -| │ | -| │ | -| │ | -| │ | -| │ | -| │ | -| │ | -| │ waiting for data from stdin | -| │ | -| │ | -| │ | -| │ | -| │ | -| │ | -| └─────────────────────────────────────────────────────────────────────────────────────> | -| X Thu Jan 1 00:00:00 1970 | -| [0m[7m [0m https://github.com/tenox7/ttyplot 1.7.0 | -+------------------------------------------------------------------------------------------+ - -[90x20] Frame 2: -+------------------------------------------------------------------------------------------+ -| .: ttyplot :. | -| ^ 4.0 [0m[7m [0m | -| │ [0m[7m [0m | -| │ [0m[7m [0m | -| │ [0m[7m [0m | -| │ 3.0 [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ 2.0 [0m[7m [0m[0m[7mX[0m | -| │ [0m[7m [0m[0m[7mX[0m | -| │ [0m[7m [0m[0m[7mX[0m | -| │ [0m[7m [0m[0m[7mX[0m | -| │ 1.0 [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| └─────────────────────────────────────────────────────────────────────────────────────> | -| X last=3.0 min=1.0 max=3.0 avg=2.0 Thu Jan 1 00:00:00 1970 | -| [0m[7m [0m last=4.0 min=2.0 max=4.0 avg=3.0 https://github.com/tenox7/ttyplot 1.7.0 | -+------------------------------------------------------------------------------------------+ - -[90x20] Frame 3: -+------------------------------------------------------------------------------------------+ -| .: ttyplot :. | -| ^ 4.0 [0m[7m [0m | -| │ [0m[7m [0m | -| │ [0m[7m [0m | -| │ [0m[7m [0m | -| │ 3.0 [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ [0m[7mX[0m | -| │ 2.0 [0m[7m [0m[0m[7mX[0m | -| │ input stream closed [0m[7m [0m[0m[7mX[0m | -| │ [0m[7m [0m[0m[7mX[0m | -| │ [0m[7m [0m[0m[7mX[0m | -| │ 1.0 [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| │ [0m[7mX[0m[0m[7mX[0m | -| └─────────────────────────────────────────────────────────────────────────────────────> | -| X last=3.0 min=1.0 max=3.0 avg=2.0 Thu Jan 1 00:00:00 1970 | -| [0m[7m [0m last=4.0 min=2.0 max=4.0 avg=3.0 https://github.com/tenox7/ttyplot 1.7.0 | -+------------------------------------------------------------------------------------------+ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/recordings/get_back_in_sync.sh new/ttyplot-1.7.4/recordings/get_back_in_sync.sh --- old/ttyplot-1.7.1/recordings/get_back_in_sync.sh 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/recordings/get_back_in_sync.sh 2025-08-18 04:21:27.000000000 +0200 @@ -22,12 +22,13 @@ ./record.sh -cp actual.txt expected.txt +eval `grep ^VERSION ../Makefile | tr -d ' '` # get the version number +sed "s/$VERSION/@VERSION@/" actual.txt > template.txt -git add expected.txt +git add template.txt if git diff --cached --exit-code >/dev/null ; then echo 'Already in sync, good.' else - EDITOR=true git commit -m 'recordings: Sync expected.txt' + EDITOR=true git commit -m 'recordings: Sync template.txt' fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/recordings/template.txt new/ttyplot-1.7.4/recordings/template.txt --- old/ttyplot-1.7.1/recordings/template.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/ttyplot-1.7.4/recordings/template.txt 2025-08-18 04:21:27.000000000 +0200 @@ -0,0 +1,72 @@ +[90x20] Frame 1: ++------------------------------------------------------------------------------------------+ +| .: ttyplot :. | +| ^ | +| │ | +| │ | +| │ | +| │ | +| │ | +| │ | +| │ | +| │ | +| │ waiting for data from stdin | +| │ | +| │ | +| │ | +| │ | +| │ | +| │ | +| └─────────────────────────────────────────────────────────────────────────────────────> | +| X Thu Jan 1 00:00:00 1970 | +| [0m[7m [0m https://github.com/tenox7/ttyplot @VERSION@ | ++------------------------------------------------------------------------------------------+ + +[90x20] Frame 2: ++------------------------------------------------------------------------------------------+ +| .: ttyplot :. | +| ^ 4.0 [0m[7m [0m | +| │ [0m[7m [0m | +| │ [0m[7m [0m | +| │ [0m[7m [0m | +| │ 3.0 [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ 2.0 [0m[7m [0m[0m[7mX[0m | +| │ [0m[7m [0m[0m[7mX[0m | +| │ [0m[7m [0m[0m[7mX[0m | +| │ [0m[7m [0m[0m[7mX[0m | +| │ 1.0 [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| └─────────────────────────────────────────────────────────────────────────────────────> | +| X last=3.0 min=1.0 max=3.0 avg=2.0 Thu Jan 1 00:00:00 1970 | +| [0m[7m [0m last=4.0 min=2.0 max=4.0 avg=3.0 https://github.com/tenox7/ttyplot @VERSION@ | ++------------------------------------------------------------------------------------------+ + +[90x20] Frame 3: ++------------------------------------------------------------------------------------------+ +| .: ttyplot :. | +| ^ 4.0 [0m[7m [0m | +| │ [0m[7m [0m | +| │ [0m[7m [0m | +| │ [0m[7m [0m | +| │ 3.0 [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ [0m[7mX[0m | +| │ 2.0 [0m[7m [0m[0m[7mX[0m | +| │ input stream closed [0m[7m [0m[0m[7mX[0m | +| │ [0m[7m [0m[0m[7mX[0m | +| │ [0m[7m [0m[0m[7mX[0m | +| │ 1.0 [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| │ [0m[7mX[0m[0m[7mX[0m | +| └─────────────────────────────────────────────────────────────────────────────────────> | +| X last=3.0 min=1.0 max=3.0 avg=2.0 Thu Jan 1 00:00:00 1970 | +| [0m[7m [0m last=4.0 min=2.0 max=4.0 avg=3.0 https://github.com/tenox7/ttyplot @VERSION@ | ++------------------------------------------------------------------------------------------+ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ttyplot-1.7.1/ttyplot.c new/ttyplot-1.7.4/ttyplot.c --- old/ttyplot-1.7.1/ttyplot.c 2025-03-19 17:11:39.000000000 +0100 +++ new/ttyplot-1.7.4/ttyplot.c 2025-08-18 04:21:27.000000000 +0200 @@ -6,9 +6,9 @@ // Apache License 2.0 // -// This is needed on macOS to get the ncurses widechar API, and pkg-config fails to -// define it. -#ifdef __APPLE__ +// This is needed on FreeBSD and macOS to get the ncurses widechar API, +// and pkg-config fails to define it. +#if defined(__APPLE__) || defined(__FreeBSD__) #define _XOPEN_SOURCE_EXTENDED #else // This is needed for musl libc @@ -41,13 +41,6 @@ #include <err.h> #endif -#define STR_(x) #x -#define STR(x) STR_(x) -#define VERSION_MAJOR 1 -#define VERSION_MINOR 7 -#define VERSION_PATCH 1 -#define VERSION_STR STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_PATCH) - #define T_RARR '>' #define T_UARR '^' #ifdef NOACS @@ -60,6 +53,27 @@ #define T_LLCR ACS_LLCORNER #endif +// Define standard curses color constants for better readability +#define C_BLACK 0 +#define C_RED 1 +#define C_GREEN 2 +#define C_YELLOW 3 +#define C_BLUE 4 +#define C_MAGENTA 5 +#define C_CYAN 6 +#define C_WHITE 7 + +// Define color element indices +enum ColorElement { + LINE_COLOR = 0, + AXES_COLOR, + TEXT_COLOR, + TITLE_COLOR, + MAX_ERROR_COLOR, + MIN_ERROR_COLOR, + NUM_COLOR_ELEMENTS +}; + enum Event { // These are made to have no set bits overlap to ease flag set testing EVENT_TIMEOUT = 1 << 0, @@ -81,8 +95,8 @@ static bool fake_clock = false; static char *errstr = NULL; static bool redraw_needed = false; -// Color indices: 0=plot_line, 1=axes, 2=text, 3=title -static int colors[4] = {-1, -1, -1, -1}; // -1 means no color specified +// Array of colors for different elements, -1 means no color specified +static int colors[NUM_COLOR_ELEMENTS] = {-1, -1, -1, -1, -1, -1}; static const char *verstring = "https://github.com/tenox7/ttyplot " VERSION_STR; static void usage(void) { @@ -107,24 +121,69 @@ "lower-limit of the plot scale is fixed\n" " -t title of the plot\n" " -u unit displayed beside vertical bar\n" - " -C color[,axes,text,title] set colors (0-7) for elements:\n" + " -C color[,axes,text,title,max_err,min_err] set colors (0-7) for elements:\n" " First value: plot line color\n" " Second value: axes color (optional)\n" " Third value: text color (optional)\n" " Fourth value: title color (optional)\n" - " Example: -C 1,2,3,4 or -C 1,2 or -C 1\n" + " Fifth value: max error indicator color (optional)\n" + " Sixth value: min error indicator color (optional)\n" + " Example: -C 1,2,3,4,5,6 or -C 1,2 or -C 1\n" + " Predefined color schemes:\n" + " -C dark1 Blue-cyan-yellow scheme for dark terminals\n" + " -C dark2 Purple-yellow-green scheme for dark terminals\n" + " -C light1 Green-blue-red scheme for light terminals\n" + " -C light2 Blue-green-yellow scheme for light terminals\n" " -v print the current version and exit\n" " -h print this help message and exit\n" "\n" "Hotkeys:\n" " q quit\n" - " r toggle rate mode\n"); + " r toggle rate mode\n" + " ^L full screen refresh\n"); } static void version(void) { printf("ttyplot %s\n", VERSION_STR); } +// Set a predefined color scheme +static void set_color_scheme(const char *scheme_name) { + if (strcmp(scheme_name, "dark1") == 0) { + // Blue-cyan-yellow scheme for dark terminals + colors[LINE_COLOR] = C_BLUE; // Blue for plot line + colors[AXES_COLOR] = C_CYAN; // Cyan for axes + colors[TEXT_COLOR] = C_WHITE; // White for text + colors[TITLE_COLOR] = C_YELLOW; // Yellow for title + colors[MAX_ERROR_COLOR] = C_RED; // Red for max error + colors[MIN_ERROR_COLOR] = C_GREEN; // Green for min error + } else if (strcmp(scheme_name, "dark2") == 0) { + // Purple-yellow-green scheme for dark terminals + colors[LINE_COLOR] = C_MAGENTA; // Magenta for plot line + colors[AXES_COLOR] = C_YELLOW; // Yellow for axes + colors[TEXT_COLOR] = C_CYAN; // Cyan for text + colors[TITLE_COLOR] = C_GREEN; // Green for title + colors[MAX_ERROR_COLOR] = C_RED; // Red for max error + colors[MIN_ERROR_COLOR] = C_BLUE; // Blue for min error + } else if (strcmp(scheme_name, "light1") == 0) { + // Green-blue-red scheme for light terminals + colors[LINE_COLOR] = C_GREEN; // Green for plot line + colors[AXES_COLOR] = C_BLUE; // Blue for axes + colors[TEXT_COLOR] = C_BLACK; // Black for text + colors[TITLE_COLOR] = C_RED; // Red for title + colors[MAX_ERROR_COLOR] = C_RED; // Red for max error + colors[MIN_ERROR_COLOR] = C_MAGENTA; // Magenta for min error + } else if (strcmp(scheme_name, "light2") == 0) { + // Blue-green-yellow scheme for light terminals + colors[LINE_COLOR] = C_BLUE; // Blue for plot line + colors[AXES_COLOR] = C_GREEN; // Green for axes + colors[TEXT_COLOR] = C_BLACK; // Black for text + colors[TITLE_COLOR] = C_YELLOW; // Yellow for title + colors[MAX_ERROR_COLOR] = C_RED; // Red for max error + colors[MIN_ERROR_COLOR] = C_MAGENTA; // Magenta for min error + } +} + // Replace *v1 and *v2 (if non-NULL) by their time derivatives. // - v1, v2: addresses of input data and storage for results // - now: current time @@ -176,8 +235,8 @@ static void draw_axes(int h, int ph, int pw, double max, double min, char *unit) { // Apply axes color if specified - if (colors[1] != -1) - attron(COLOR_PAIR(2)); + if (colors[AXES_COLOR] != -1) + attron(COLOR_PAIR(AXES_COLOR + 1)); // Draw axes mvhline(h - 3, 2, T_HLINE, pw); @@ -186,56 +245,152 @@ mvaddch(1, 2, T_UARR); mvaddch(h - 3, 2, T_LLCR); - if (colors[1] != -1) - attroff(COLOR_PAIR(2)); + if (colors[AXES_COLOR] != -1) + attroff(COLOR_PAIR(AXES_COLOR + 1)); // Apply text color for scale labels if specified - if (colors[2] != -1) - attron(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attron(COLOR_PAIR(TEXT_COLOR + 1)); // Print scale labels if (max - min >= 0.1) { mvprintw(1, 4, "%.1f %s", max, unit); - mvprintw((ph / 4) + 1, 4, "%.1f %s", min / 4 + max * 3 / 4, unit); - mvprintw((ph / 2) + 1, 4, "%.1f %s", min / 2 + max / 2, unit); - mvprintw((ph * 3 / 4) + 1, 4, "%.1f %s", min * 3 / 4 + max / 4, unit); + + double label_val; + + label_val = min / 4 + max * 3 / 4; + if (fabs(label_val) < 0.01) + label_val = 0.0; // Prevent -0.0 + mvprintw((ph / 4) + 1, 4, "%.1f %s", label_val, unit); + + label_val = min / 2 + max / 2; + if (fabs(label_val) < 0.01) + label_val = 0.0; // Prevent -0.0 + mvprintw((ph / 2) + 1, 4, "%.1f %s", label_val, unit); + + label_val = min * 3 / 4 + max / 4; + if (fabs(label_val) < 0.01) + label_val = 0.0; // Prevent -0.0 + mvprintw((ph * 3 / 4) + 1, 4, "%.1f %s", label_val, unit); } - if (colors[2] != -1) - attroff(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attroff(COLOR_PAIR(TEXT_COLOR + 1)); } static void draw_line(int x, int ph, int l1, int l2, cchar_t *c1, cchar_t *c2, - cchar_t *hce, cchar_t *lce) { + cchar_t *hce, cchar_t *lce, int zero_pos, double v1, double v2, + int has_v2) { static cchar_t space = {.attr = A_REVERSE, .chars = {' ', '\0'}}; cchar_t c1r = *c1, c2r = *c2; c1r.attr |= A_REVERSE; c2r.attr |= A_REVERSE; - if (colors[0] != -1) { - c1->attr |= COLOR_PAIR(1); - c2->attr |= COLOR_PAIR(1); - c1r.attr |= COLOR_PAIR(1); - c2r.attr |= COLOR_PAIR(1); - space.attr |= COLOR_PAIR(1); - } + // Apply appropriate colors based on character type + if (c1 == hce && colors[MAX_ERROR_COLOR] != -1) { + // Max error indicator + c1->attr |= COLOR_PAIR(MAX_ERROR_COLOR + 1); + c1r.attr |= COLOR_PAIR(MAX_ERROR_COLOR + 1); + } else if (c1 == lce && colors[MIN_ERROR_COLOR] != -1) { + // Min error indicator + c1->attr |= COLOR_PAIR(MIN_ERROR_COLOR + 1); + c1r.attr |= COLOR_PAIR(MIN_ERROR_COLOR + 1); + } else if (colors[LINE_COLOR] != -1) { + // Normal plot line + c1->attr |= COLOR_PAIR(LINE_COLOR + 1); + c1r.attr |= COLOR_PAIR(LINE_COLOR + 1); + } + + if (c2 == hce && colors[MAX_ERROR_COLOR] != -1) { + // Max error indicator + c2->attr |= COLOR_PAIR(MAX_ERROR_COLOR + 1); + c2r.attr |= COLOR_PAIR(MAX_ERROR_COLOR + 1); + } else if (c2 == lce && colors[MIN_ERROR_COLOR] != -1) { + // Min error indicator + c2->attr |= COLOR_PAIR(MIN_ERROR_COLOR + 1); + c2r.attr |= COLOR_PAIR(MIN_ERROR_COLOR + 1); + } else if (colors[LINE_COLOR] != -1) { + // Normal plot line + c2->attr |= COLOR_PAIR(LINE_COLOR + 1); + c2r.attr |= COLOR_PAIR(LINE_COLOR + 1); + } + + // Space always uses plot line color + if (colors[LINE_COLOR] != -1) { + space.attr |= COLOR_PAIR(LINE_COLOR + 1); + } + + // Handle drawing based on whether values are positive or negative + if (zero_pos > 0) { // We have negative values + int y1_start, y1_end, y2_start, y2_end; + + // For value 1 + if (v1 >= 0) { + // Positive value: draw from zero line upward + y1_start = ph + 1 - l1; + y1_end = ph + 1 - zero_pos; + } else { + // Negative value: draw from zero line downward + y1_start = ph + 1 - zero_pos; + y1_end = ph + 1 - l1; + } + + // For value 2 + if (has_v2) { + if (v2 > 0) { + y2_start = ph + 1 - l2; + y2_end = ph + 1 - zero_pos; + } else if (v2 < 0) { + y2_start = ph + 1 - zero_pos; + y2_end = ph + 1 - l2; + } else { // v2 == 0 + y2_start = ph + 1 - zero_pos; + y2_end = ph + 1 - zero_pos; + } + } - if (l1 > l2) { - mvvline_set(ph + 1 - l1, x, c1, l1 - l2); - mvvline_set(ph + 1 - l2, x, &c2r, l2); - } else if (l1 < l2) { - mvvline_set(ph + 1 - l2, x, (c2 == hce || c2 == lce) ? &c2r : &space, l2 - l1); - mvvline_set(ph + 1 - l1, x, &c2r, l1); + // Draw the lines + if (y1_start < y1_end) { + mvvline_set(y1_start, x, c1, y1_end - y1_start); + } else if (y1_start > y1_end && l1 > 0) { + mvvline_set(y1_end, x, c1, y1_start - y1_end); + } + if (has_v2) { + if (y2_start < y2_end) { + mvvline_set(y2_start, x, &c2r, y2_end - y2_start); + } else if (y2_start > y2_end) { + mvvline_set(y2_end, x, &c2r, y2_start - y2_end); + } else { // y2_start == y2_end + mvvline_set(y2_start, x, &c2r, 1); + } + } } else { - mvvline_set(ph + 1 - l2, x, &c2r, l2); + // Original behavior for all positive values + if (l1 > l2) { + mvvline_set(ph + 1 - l1, x, c1, l1 - l2); + mvvline_set(ph + 1 - l2, x, &c2r, l2); + } else if (l1 < l2) { + mvvline_set(ph + 1 - l2, x, (c2 == hce || c2 == lce) ? &c2r : &space, + l2 - l1); + mvvline_set(ph + 1 - l1, x, &c2r, l1); + } else { + mvvline_set(ph + 1 - l2, x, &c2r, l2); + } } - if (colors[0] != -1) { - c1->attr &= ~COLOR_PAIR(1); - c2->attr &= ~COLOR_PAIR(1); - c1r.attr &= ~COLOR_PAIR(1); - c2r.attr &= ~COLOR_PAIR(1); - space.attr &= ~COLOR_PAIR(1); + // Reset all color attributes (COLOR_PAIR indexes are LINE_COLOR+1 through + // MIN_ERROR_COLOR+1) + const attr_t color_mask = COLOR_PAIR(LINE_COLOR + 1) | + COLOR_PAIR(MAX_ERROR_COLOR + 1) | + COLOR_PAIR(MIN_ERROR_COLOR + 1); + + c1->attr &= ~color_mask; + c2->attr &= ~color_mask; + c1r.attr &= ~color_mask; + c2r.attr &= ~color_mask; + + if (colors[LINE_COLOR] != -1) { + space.attr &= ~COLOR_PAIR(LINE_COLOR + 1); } } @@ -246,9 +401,17 @@ int i = (n + 1) % pw; int x; int l1, l2; + int zero_pos = 0; + + // Calculate zero position if we have negative values + if (min < 0 && max > 0) { + zero_pos = lrint((0 - min) / (max - min) * ph); + } else if (max <= 0) { + zero_pos = ph; // All values are negative, zero is at top + } - if (colors[0] != -1) - attron(COLOR_PAIR(1)); + if (colors[LINE_COLOR] != -1) + attron(COLOR_PAIR(LINE_COLOR + 1)); for (x = first_col; x < first_col + pw; x++, i = (i + 1) % pw) { /* suppress drawing uninitialized entries */ @@ -278,11 +441,12 @@ (v2 && v2[i] > hardmax) ? hce : (v2 && v2[i] < hardmin) ? lce : pc, - hce, lce); + hce, lce, zero_pos, v1[i], (v2 && !isnan(v2[i])) ? v2[i] : 0, + (v2 && !isnan(v2[i]))); } - if (colors[0] != -1) - attroff(COLOR_PAIR(1)); + if (colors[LINE_COLOR] != -1) + attroff(COLOR_PAIR(LINE_COLOR + 1)); } static void show_all_centered(const char *message) { @@ -291,13 +455,13 @@ const int y = height / 2; // Apply title color to error messages if specified - if (colors[3] != -1) - attron(COLOR_PAIR(4)); + if (colors[TITLE_COLOR] != -1) + attron(COLOR_PAIR(TITLE_COLOR + 1)); mvaddnstr(y, x, message, width); - if (colors[3] != -1) - attroff(COLOR_PAIR(4)); + if (colors[TITLE_COLOR] != -1) + attroff(COLOR_PAIR(TITLE_COLOR + 1)); } static int window_big_enough_to_draw(void) { @@ -337,8 +501,8 @@ min = hardmin; // Apply text color if specified - if (colors[2] != -1) - attron(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attron(COLOR_PAIR(TEXT_COLOR + 1)); mvaddstr(height - 1, width - strlen(verstring) - 1, verstring); @@ -352,12 +516,12 @@ } mvaddstr(height - 2, width - strlen(clock_display), clock_display); - if (colors[2] != -1) - attroff(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attroff(COLOR_PAIR(TEXT_COLOR + 1)); // Apply text color for stats - if (colors[2] != -1) - attron(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attron(COLOR_PAIR(TEXT_COLOR + 1)); mvvline_set(height - 2, 5, &plotchar, 1); if (v > 0) { @@ -374,8 +538,8 @@ } } - if (colors[2] != -1) - attroff(COLOR_PAIR(3)); + if (colors[TEXT_COLOR] != -1) + attroff(COLOR_PAIR(TEXT_COLOR + 1)); plot_values(plotheight, plotwidth, values1, two ? values2 : NULL, max, min, n, &plotchar, &max_errchar, &min_errchar, hardmax, hardmin); @@ -383,13 +547,13 @@ draw_axes(height, plotheight, plotwidth, max, min, unit); // Apply title color if specified - if (colors[3] != -1) - attron(COLOR_PAIR(4)); + if (colors[TITLE_COLOR] != -1) + attron(COLOR_PAIR(TITLE_COLOR + 1)); mvaddstr(0, (width / 2) - (strlen(title) / 2), title); - if (colors[3] != -1) - attroff(COLOR_PAIR(4)); + if (colors[TITLE_COLOR] != -1) + attroff(COLOR_PAIR(TITLE_COLOR + 1)); move(0, 0); } @@ -401,9 +565,11 @@ const unsigned char signal_number = (unsigned char)signum; // signum is either 2 (SIGINT) or 28 (SIGWINCH) ssize_t write_res; + int saved_errno = errno; do { write_res = write(signal_write_fd, &signal_number, 1); } while ((write_res == -1) && (errno == EINTR)); + errno = saved_errno; } static void redraw_screen(const char *errstr) { @@ -705,16 +871,23 @@ mbtowc(&min_errchar.chars[0], optarg, MB_CUR_MAX); break; case 'C': { - char *color_str = strdup(optarg); - char *token = strtok(color_str, ","); - int color_idx = 0; - - while (token != NULL && color_idx < 4) { - colors[color_idx++] = atoi(token); - token = strtok(NULL, ","); - } + // Check if it's a predefined color scheme + if (strcmp(optarg, "dark1") == 0 || strcmp(optarg, "dark2") == 0 || + strcmp(optarg, "light1") == 0 || strcmp(optarg, "light2") == 0) { + set_color_scheme(optarg); + } else { + // Process comma-separated color values + char *color_str = strdup(optarg); + char *token = strtok(color_str, ","); + int color_idx = 0; + + while (token != NULL && color_idx < NUM_COLOR_ELEMENTS) { + colors[color_idx++] = atoi(token); + token = strtok(NULL, ","); + } - free(color_str); + free(color_str); + } break; } case 's': @@ -745,7 +918,10 @@ if (hardmax <= hardmin) hardmax = FLT_MAX; - initscr(); /* uses filesystem, so before pledge */ + if (initscr() == NULL) { + fprintf(stderr, "Error: failed to initialize ncurses\n"); + exit(1); + } #ifdef __OpenBSD__ if (pledge("stdio tty", NULL) == -1) @@ -754,7 +930,7 @@ // Check if any colors are defined bool has_colors = false; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < NUM_COLOR_ELEMENTS; i++) { if (colors[i] != -1) { has_colors = true; break; @@ -766,14 +942,17 @@ use_default_colors(); // Initialize color pairs for different elements - // COLOR_PAIR(1): plot line (initialized in original code) - // COLOR_PAIR(2): axes - // COLOR_PAIR(3): text - // COLOR_PAIR(4): title + // COLOR_PAIR indexes match the enum + 1 because ncurses starts at 1 + // COLOR_PAIR(1): plot line (LINE_COLOR + 1) + // COLOR_PAIR(2): axes (AXES_COLOR + 1) + // COLOR_PAIR(3): text (TEXT_COLOR + 1) + // COLOR_PAIR(4): title (TITLE_COLOR + 1) + // COLOR_PAIR(5): max error indicator (MAX_ERROR_COLOR + 1) + // COLOR_PAIR(6): min error indicator (MIN_ERROR_COLOR + 1) - for (int i = 0; i < 4; i++) { + for (int i = 0; i < NUM_COLOR_ELEMENTS; i++) { if (colors[i] != -1) { - init_pair(i+1, colors[i], -1); // -1 for default background + init_pair(i + 1, colors[i], -1); // -1 for default background } } } @@ -847,6 +1026,10 @@ rate = ! rate; else if (key == 'q') // 'q' = quit break; + else if (key == '\f' || key == 12) { // Ctrl+L = full screen refresh + clear(); + redraw_needed = true; + } } else if (count == 0) { close(tty); tty = -1;
