commit eda41ce995fbd41f7b3f6ef5a9dc2efcf9a23b34
parent 9faf6eb459aa262bf7a0b4d3a53c6af4cf8874b7
Author: Christos Margiolis <christos@margiolis.net>
Date: Mon, 14 Dec 2020 00:15:04 +0200
more error checks, less functions, minor changes
Diffstat:
6 files changed, 162 insertions(+), 171 deletions(-)
diff --git a/LICENSE b/LICENSE
diff --git a/Makefile b/Makefile
@@ -8,8 +8,9 @@ BIN = graphcurses
DIST = ${BIN}-${VERSION}
MAN1 = ${BIN}.1
+EXT = c
SRC = graphcurses.c
-OBJ = graphcurses.o
+OBJ = ${SRC:.${EXT}=.o}
all: options ${BIN}
@@ -22,12 +23,12 @@ options:
${BIN}: ${OBJ}
${CC} ${LDFLAGS} ${OBJ} -o $@
-${OBJ}: ${SRC}
- ${CC} ${CFLAGS} -c ${SRC} -o $@
+.${EXT}.o:
+ ${CC} -c ${CFLAGS} $<
dist: clean
${MKDIR} ${DIST}
- ${CP} -R config.mk ${SRC} LICENSE Makefile README.md ${DIST}
+ ${CP} -R config.mk ${MAN1} ${SRC} LICENSE Makefile README.md ${DIST}
${TAR} ${DIST}.tar ${DIST}
${GZIP} ${DIST}.tar
${RM_DIR} ${DIST}
diff --git a/README.md b/README.md
@@ -2,7 +2,7 @@
A simple ncurses graph generator.
-![Screenshot_20200308_212613](https://user-images.githubusercontent.com/54286563/76169715-b3994d80-6183-11ea-97e0-4003239ecfe3.png)
+![preview](https://user-images.githubusercontent.com/54286563/102025554-66e14380-3da1-11eb-81e0-ea7cfc8c1161.png)
## Dependencies
@@ -22,10 +22,7 @@ The binary will be installed at `/usr/local/bin`
## To Do
-* ~~Improve key handling~~
* Add slope, curvature etc.
-* ~~Add an options window~~
-* Add coordinates using cursor pointing
-* ~~Add derivative calculator~~
+* Add curses coordinates
* Fix axes plotting bug
* Add point numbering on axes
diff --git a/config.mk b/config.mk
@@ -6,10 +6,6 @@ VERSION = 0
PREFIX = /usr/local
MAN_DIR = ${PREFIX}/man/man1
BIN_DIR = ${PREFIX}/bin
-# uncomment if you're making a library
-#MAN_DIR = ${PREFIX}/man/man3
-#INC_DIR = ${PREFIX}/include
-#LIB_DIR = ${PREFIX}/lib
# includes and libs
INCS = -Iinclude
@@ -17,12 +13,10 @@ LIBS = -Llib -lm -lmatheval -lncurses
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L \
- -DVERSION=\"${VERSION}\" -U__STRICT_ANSI__
+ -D_XOPEN_SOURCE=600 -DVERSION=\"${VERSION}\" -U__STRICT_ANSI__
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations \
-O3 ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}
-# uncomment if you're making a library
-#ARFLAGS = rs
# utils
CP = cp -f
@@ -36,5 +30,3 @@ GZIP = gzip
# compiler
CC = gcc
-# uncomment if you're making a library
-#AR = ar
diff --git a/graphcurses.1 b/graphcurses.1
diff --git a/graphcurses.c b/graphcurses.c
@@ -1,5 +1,4 @@
/* See LICENSE file for copyright and license details. */
-
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -13,17 +12,17 @@
#define XMIN_PLANE (-2.0f * M_PI)
#define XMAX_PLANE ( 2.0f * M_PI)
-#define YMIN_PLANE -M_PI
+#define YMIN_PLANE (-M_PI)
#define YMAX_PLANE M_PI
#define XSCALE_PLANE 1.0f
#define YSCALE_PLANE 1.0f
#define SHIFT_STEP 1.0f
#define ZOOM_IN_FACTOR (1.0f / 1.05f)
#define ZOOM_OUT_FACTOR 1.05f
-#define BUFFSIZE 256
+#define BUFSIZE 256
-#define YMAX() (getmaxy(stdscr))
-#define XMAX() (getmaxx(stdscr))
+#define YMAX (getmaxy(stdscr))
+#define XMAX (getmaxx(stdscr))
#define CENTER(x, y) ((x) / 2 - (y) / 2)
#define PLANE_SCALE(val, omin, omax, nmin, nmax) \
((((val) - (omin)) / ((omax) - (omin))) * ((nmax) - (nmin)) + (nmin))
@@ -44,160 +43,135 @@
#define OPT_ZOOM_OUT "- Zoom out"
#define MSG_QUIT_MENU "Press any key to quit the menu"
-struct Plane {
+typedef struct {
float (*f)(float);
void *df;
- float ymin, ymax;
- float xmin, xmax;
- float xscale, yscale;
- int ymaxs, xmaxs;
- int derivative_show;
-};
-
-static void *f = NULL;
-
-static void curses_init(void);
-static void func_get(struct Plane *, char *);
-static void expression_validate(struct Plane *);
-static float expression_evaluate(float);
-static void keys_handle(struct Plane *, int);
-static void plane_init(struct Plane *);
-static void plane_shift(struct Plane *, float, float);
-static void zoom_restore(struct Plane *);
-static void zoom_handle(struct Plane *, float);
-static void axes_draw(const struct Plane *);
-static void graph_draw(const struct Plane *);
-static void graph_plot(const struct Plane *, float, float);
-static void menu_options(void);
-static void menu_fill(struct _win_st *);
-
-void
-curses_init(void)
+ float ymin;
+ float ymax;
+ float xmin;
+ float xmax;
+ float xscale;
+ float yscale;
+ int ymaxs;
+ int xmaxs;
+ int derivshow;
+} Plane;
+
+static void cursesinit(void);
+static void funcget(Plane *, char *);
+static void exprvalidate(Plane *);
+static float expreval(float);
+static Plane *planeinit(void);
+static void planeshift(Plane *, float, float);
+static void zoomrestore(Plane *);
+static void zoomhandle(Plane *, float);
+static void axesdraw(const Plane *);
+static void graphdraw(const Plane *);
+static void graphplot(const Plane *, float, float);
+static void menuopts(void);
+
+static void *f = NULL;
+
+static void
+cursesinit(void)
{
- initscr();
+ if (!initscr()) {
+ fputs("graphcurses: initscr: cannot initialiaze ncurses", stderr);
+ exit(EXIT_FAILURE);
+ }
cbreak();
noecho();
curs_set(0);
keypad(stdscr, 1);
+
start_color();
init_pair(1, COLOR_WHITE, COLOR_BLACK);
- init_pair(2, COLOR_CYAN, COLOR_BLACK);
- init_pair(3, COLOR_RED, COLOR_BLACK);
+ init_pair(2, COLOR_CYAN, COLOR_BLACK);
+ init_pair(3, COLOR_RED, COLOR_BLACK);
}
-void
-func_get(struct Plane *p, char *buf)
+static void
+funcget(Plane *p, char *buf)
{
move(0, 0);
clrtoeol();
printw("f(x) = ");
echo();
refresh();
- getnstr(buf, BUFFSIZE);
- zoom_restore(p);
+ getnstr(buf, BUFSIZE);
+ zoomrestore(p);
refresh();
noecho();
}
-void
-expression_validate(struct Plane *p)
+static void
+exprvalidate(Plane *p)
{
char *buf;
- if ((buf = malloc(BUFFSIZE + sizeof(char))) == NULL) {
- fputs("Cannot allocate memory. Exiting. . .\n", stderr);
+ if ((buf = malloc(BUFSIZE)) == NULL) {
+ fputs("graphcurses: exprvalidate: cannot allocate memory", stderr);
exit(EXIT_FAILURE);
}
- func_get(p, buf);
+ funcget(p, buf);
while (!(f = evaluator_create(buf))) {
printw("Error in expression! Try again");
- func_get(p, buf);
+ funcget(p, buf);
refresh();
}
p->df = evaluator_derivative_x(f);
free(buf);
}
-float
-expression_evaluate(float x)
+static float
+expreval(float x)
{
return evaluator_evaluate_x(f, x);
}
-void
-keys_handle(struct Plane *p, int key)
+static Plane *
+planeinit(void)
{
- switch (key) {
- case 'k': case KEY_UP:
- plane_shift(p, 0.0f, SHIFT_STEP);
- break;
- case 'j': case KEY_DOWN:
- plane_shift(p, 0.0f, -SHIFT_STEP);
- break;
- case 'h': case KEY_LEFT:
- plane_shift(p, -SHIFT_STEP, 0.0f);
- break;
- case 'l': case KEY_RIGHT:
- plane_shift(p, SHIFT_STEP, 0.0f);
- break;
- case '+':
- zoom_handle(p, ZOOM_IN_FACTOR);
- break;
- case '-':
- zoom_handle(p, ZOOM_OUT_FACTOR);
- break;
- case 'd':
- p->derivative_show = !p->derivative_show;
- break;
- case 'r':
- zoom_restore(p);
- break;
- case 'f':
- expression_validate(p);
- break;
- case 'm':
- menu_options();
- break;
+ Plane *p;
+
+ if ((p = malloc(sizeof(Plane))) == NULL) {
+ fputs("graphcurses: planeinit: cannot allocate memory", stderr);
+ exit(EXIT_FAILURE);
}
-}
-void
-plane_init(struct Plane *p)
-{
- p->xmin = XMIN_PLANE;
- p->xmax = XMAX_PLANE;
- p->ymin = YMIN_PLANE;
- p->ymax = YMAX_PLANE;
- p->xscale = XSCALE_PLANE;
- p->yscale = YSCALE_PLANE;
- p->xmaxs = XMAX();
- p->ymaxs = YMAX();
+ p->xmaxs = XMAX;
+ p->ymaxs = YMAX;
+ p->derivshow = 0;
+ p->f = expreval;
+ zoomrestore(p);
+
+ return p;
}
-void
-plane_shift(struct Plane *p, float xshift, float yshift)
+static void
+planeshift(Plane *p, float xshift, float yshift)
{
- xshift *= (p->xmax - p->xmin) / 16.0f;
- yshift *= (p->ymax - p->ymin) / 16.0f;
+ xshift *= (p->xmax - p->xmin) / 16.0f;
+ yshift *= (p->ymax - p->ymin) / 16.0f;
p->xmin += xshift;
p->xmax += xshift;
p->ymin += yshift;
p->ymax += yshift;
}
-void
-zoom_restore(struct Plane *p)
+static void
+zoomrestore(Plane *p)
{
- p->xmin = XMIN_PLANE;
- p->xmax = XMAX_PLANE;
- p->ymin = YMIN_PLANE;
- p->ymax = YMAX_PLANE;
+ p->xmin = XMIN_PLANE;
+ p->xmax = XMAX_PLANE;
+ p->ymin = YMIN_PLANE;
+ p->ymax = YMAX_PLANE;
p->xscale = XSCALE_PLANE;
p->yscale = YSCALE_PLANE;
}
-void
-zoom_handle(struct Plane *p, float factor)
+static void
+zoomhandle(Plane *p, float factor)
{
float xctr = (p->xmin + p->ymax) / 2.0f;
float yctr = (p->ymin + p->ymax) / 2.0f;
@@ -208,8 +182,8 @@ zoom_handle(struct Plane *p, float factor)
p->ymax = PLANE_SCALE(factor, 1.0f, 0.0f, p->ymax, yctr);
}
-void
-axes_draw(const struct Plane *p)
+static void
+axesdraw(const Plane *p)
{
float x0, y0, xstep, ystep, plotx, ploty, i;
int tick;
@@ -218,6 +192,7 @@ axes_draw(const struct Plane *p)
y0 = PLANE_SCALE(0.0f, p->ymin, p->ymax, p->ymaxs, 0.0f);
PLANE_XSTEP(p, xstep);
PLANE_YSTEP(p, ystep);
+
for (i = 0.0f; i < p->xmaxs; i += xstep) {
plotx = p->xmin + xstep * i;
tick = fabs(fmod(plotx, p->xscale)) < xstep;
@@ -228,11 +203,12 @@ axes_draw(const struct Plane *p)
tick = fabs(fmod(ploty, p->yscale)) < ystep;
mvaddch(i, x0, tick ? ACS_PLUS : ACS_VLINE);
}
+
mvaddch(y0, x0, ACS_PLUS);
}
-void
-graph_draw(const struct Plane *p)
+static void
+graphdraw(const Plane *p)
{
float x, y, dy, xstep;
@@ -240,19 +216,18 @@ graph_draw(const struct Plane *p)
for (x = p->xmin; x <= p->xmax; x += xstep) {
y = p->f(x);
attron(COLOR_PAIR(2));
- graph_plot(p, x, y);
- if (p->derivative_show) {
+ graphplot(p, x, y);
+ if (p->derivshow) {
dy = evaluator_evaluate_x(p->df, x);
attron(COLOR_PAIR(3));
- graph_plot(p, x, dy);
+ graphplot(p, x, dy);
}
}
- attroff(COLOR_PAIR(3));
- attroff(COLOR_PAIR(2));
+ attroff(COLOR_PAIR(2) | COLOR_PAIR(3));
}
-void
-graph_plot(const struct Plane *p, float x, float y)
+static void
+graphplot(const Plane *p, float x, float y)
{
float xp = PLANE_SCALE(x, p->xmin, p->xmax, 0.0f, p->xmaxs);
float yp = PLANE_SCALE(y, p->ymin, p->ymax, p->ymaxs, 0.0f);
@@ -260,30 +235,21 @@ graph_plot(const struct Plane *p, float x, float y)
mvaddch(yp, xp, '.');
}
-void
-menu_options(void)
+static void
+menuopts(void)
{
- int w, h, wy, wx;
WINDOW *opts;
+ int w, h, wy, wx;
- w = 33;
+ w = 33;
h = 14;
- wy = CENTER(YMAX(), h);
- wx = CENTER(XMAX(), w);
+ wy = CENTER(YMAX, h);
+ wx = CENTER(XMAX, w);
opts = newwin(h, w, wy, wx);
werase(opts);
box(opts, 0, 0);
- menu_fill(opts);
- wrefresh(opts);
- wgetch(opts);
- werase(opts);
- wrefresh(opts);
- delwin(opts);
-}
-void
-menu_fill(WINDOW *opts)
-{
+ /* fill menu */
mvwprintw(opts, 1, 1, OPT_QUIT);
mvwprintw(opts, 2, 1, OPT_MOVE_UP);
mvwprintw(opts, 3, 1, OPT_MOVE_DOWN);
@@ -295,43 +261,78 @@ menu_fill(WINDOW *opts)
mvwprintw(opts, 9, 1, OPT_ZOOM_IN);
mvwprintw(opts, 10, 1, OPT_ZOOM_OUT);
mvwprintw(opts, 12, 1, MSG_QUIT_MENU);
+
+ wrefresh(opts);
+ wgetch(opts);
+ werase(opts);
+ wrefresh(opts);
+ delwin(opts);
}
int
main(int argc, char *argv[])
{
-#ifndef NCURSES_VERSION
- fputs("ncurses is needed in order to run this program.\n", stderr);
- return EXIT_FAILURE;
-#endif /* NCURSES_VERSION */
- struct Plane p;
+ /* TODO: implement `die` */
+ Plane *p;
int key = 0;
- curses_init();
- plane_init(&p);
- zoom_restore(&p);
- expression_validate(&p);
- p.derivative_show = 0;
- p.f = expression_evaluate;
+ cursesinit();
+ p = planeinit();
+ exprvalidate(p);
for (; key != 'q'; key = getch()) {
- keys_handle(&p, key);
+ switch (key) {
+ case 'k': /* FALLTHROUGH */
+ case KEY_UP:
+ planeshift(p, 0.0f, SHIFT_STEP);
+ break;
+ case 'j': /* FALLTHROUGH */
+ case KEY_DOWN:
+ planeshift(p, 0.0f, -SHIFT_STEP);
+ break;
+ case 'h': /* FALLTHROUGH */
+ case KEY_LEFT:
+ planeshift(p, -SHIFT_STEP, 0.0f);
+ break;
+ case 'l': /* FALLTHROUGH */
+ case KEY_RIGHT:
+ planeshift(p, SHIFT_STEP, 0.0f);
+ break;
+ case '+':
+ zoomhandle(p, ZOOM_IN_FACTOR);
+ break;
+ case '-':
+ zoomhandle(p, ZOOM_OUT_FACTOR);
+ break;
+ case 'd':
+ p->derivshow ^= 1;
+ break;
+ case 'r':
+ zoomrestore(p);
+ break;
+ case 'f':
+ exprvalidate(p);
+ break;
+ case 'm':
+ menuopts();
+ break;
+ }
+
erase();
- attron(COLOR_PAIR(1));
- attron(A_REVERSE);
- attron(A_BOLD);
+ attron(COLOR_PAIR(1) | A_REVERSE | A_BOLD);
mvprintw(0, 0, "f(x) = %s", evaluator_get_string(f));
- if (p.derivative_show)
- mvprintw(1, 0, "f'(x) = %s", evaluator_get_string(p.df));
- attroff(A_REVERSE);
- attroff(A_BOLD);
- axes_draw(&p);
- attroff(COLOR_PAIR(1));
- graph_draw(&p);
+ if (p->derivshow)
+ mvprintw(1, 0, "f'(x) = %s", evaluator_get_string(p->df));
+ attroff(COLOR_PAIR(1) | A_REVERSE | A_BOLD);
+
+ axesdraw(p);
+ graphdraw(p);
refresh();
}
endwin();
+ free(p);
evaluator_destroy(f);
+
return EXIT_SUCCESS;
}