Skip to content

Commit

Permalink
Support plotting with mutibyte characters
Browse files Browse the repository at this point in the history
The options -c, -e and -E only support ASCII characters. Make them
support multibyte characters too, as box drawing and block elements can
make nice plotting glyphs.

This requires wide character support from the "ncursesw" version of the
ncurses library. Only characters supported by the user's locale can be
used, which includes the full Unicode repertoire on UTF-8 locales.

As the wide character API of ncurses does not support ACS characters,
the default plotting character on locales lacking mutibyte support is
now "|" (U+007C vertical line).
  • Loading branch information
edgar-bonet committed Nov 17, 2023
1 parent 8d24130 commit ba79765
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ DESTDIR ?=
PREFIX ?= /usr/local
MANPREFIX ?= $(PREFIX)/man
CFLAGS += -Wall -Wextra
LDLIBS += `pkg-config --libs ncurses 2>/dev/null || echo '-lcurses -ltinfo'`
LDLIBS += `pkg-config --libs ncursesw 2>/dev/null || echo '-lcursesw -ltinfo'`
torture: LDLIBS = -lm

all: ttyplot
Expand Down
47 changes: 30 additions & 17 deletions ttyplot.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
// Apache License 2.0
//

#define _XOPEN_SOURCE 500 // Get ncurses wchar_t support from SUSv2 (UNIX 98)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <float.h>
#include <time.h>
#include <locale.h>
#include <ncurses.h>
#include <signal.h>
#include <errno.h>
Expand Down Expand Up @@ -45,7 +47,7 @@
#endif

sigset_t sigmsk;
chtype plotchar, max_errchar, min_errchar;
cchar_t plotchar, max_errchar, min_errchar;
time_t t1,t2,td;
struct tm *lt;
double max=FLT_MIN;
Expand Down Expand Up @@ -121,19 +123,26 @@ void draw_axes(int h, int ph, int pw, double max, double min, char *unit) {
mvaddch(h-3, 2, T_LLCR);
}

void draw_line(int x, int ph, int l1, int l2, chtype c1, chtype c2, chtype hce, chtype lce) {
void draw_line(int x, int ph, int l1, int l2, cchar_t *c1, cchar_t *c2, cchar_t *hce, cchar_t *lce) {
static cchar_t space = {
.attr = A_REVERSE,
.chars = {' ', '\0'}
};
cchar_t c1r = *c1, c2r = *c2;
c1r.attr |= A_REVERSE;
c2r.attr |= A_REVERSE;
if(l1 > l2) {
mvvline(ph+1-l1, x, c1, l1-l2 );
mvvline(ph+1-l2, x, c2|A_REVERSE, l2 );
mvvline_set(ph+1-l1, x, c1, l1-l2 );
mvvline_set(ph+1-l2, x, &c2r, l2 );
} else if(l1 < l2) {
mvvline(ph+1-l2, x, (c2==hce || c2==lce) ? c2|A_REVERSE : ' '|A_REVERSE, l2-l1 );
mvvline(ph+1-l1, x, c1|A_REVERSE, l1 );
mvvline_set(ph+1-l2, x, (c2==hce || c2==lce) ? &c2r : &space, l2-l1 );
mvvline_set(ph+1-l1, x, &c2r, l1 );
} else {
mvvline(ph+1-l2, x, c2|A_REVERSE, l2 );
mvvline_set(ph+1-l2, x, &c2r, l2 );
}
}

void plot_values(int ph, int pw, double *v1, double *v2, double max, double min, int n, chtype pc, chtype hce, chtype lce, double hm) {
void plot_values(int ph, int pw, double *v1, double *v2, double max, double min, int n, cchar_t *pc, cchar_t *hce, cchar_t *lce, double hm) {
int i;
int x=3;
max-=min;
Expand Down Expand Up @@ -206,7 +215,7 @@ void paint_plot(void) {
asctime_r(lt, ls);
mvaddstr(height-2, width-strlen(ls), ls);

mvvline(height-2, 5, plotchar|A_NORMAL, 1);
mvvline_set(height-2, 5, &plotchar, 1);
mvprintw(height-2, 7, "last=%.1f min=%.1f max=%.1f avg=%.1f %s ", values1[n], min1, max1, avg1, unit);
if(rate)
printw(" interval=%llds", (long long int)td);
Expand All @@ -216,7 +225,7 @@ void paint_plot(void) {
mvprintw(height-1, 7, "last=%.1f min=%.1f max=%.1f avg=%.1f %s ", values2[n], min2, max2, avg2, unit);
}

plot_values(plotheight, plotwidth, values1, values2, max, hardmin, n, plotchar, max_errchar, min_errchar, hardmax);
plot_values(plotheight, plotwidth, values1, values2, max, hardmin, n, &plotchar, &max_errchar, &min_errchar, hardmax);

draw_axes(height, plotheight, plotwidth, max, hardmin, unit);

Expand Down Expand Up @@ -258,9 +267,13 @@ int main(int argc, char *argv[]) {
int show_ver;
int show_usage;

plotchar=T_VLINE;
max_errchar='e';
min_errchar='v';
setlocale(LC_ALL, "");
if (MB_CUR_MAX > 1) // if non-ASCII characters are supprted:
plotchar.chars[0]=0x2502; // U+2502 box drawings light vertical
else
plotchar.chars[0]='|'; // U+007C vertical line
max_errchar.chars[0]='e';
min_errchar.chars[0]='v';

cached_opterr = opterr;
opterr=0;
Expand Down Expand Up @@ -310,16 +323,16 @@ int main(int argc, char *argv[]) {
break;
case '2':
two=1;
plotchar='|';
plotchar.chars[0]='|';
break;
case 'c':
plotchar=optarg[0];
mbtowc(&plotchar.chars[0], optarg, MB_CUR_MAX);
break;
case 'e':
max_errchar=optarg[0];
mbtowc(&max_errchar.chars[0], optarg, MB_CUR_MAX);
break;
case 'E':
min_errchar=optarg[0];
mbtowc(&min_errchar.chars[0], optarg, MB_CUR_MAX);
break;
case 's':
softmax=atof(optarg);
Expand Down

0 comments on commit ba79765

Please sign in to comment.