Compare commits
No commits in common. "main" and "shfx" have entirely different histories.
30 changed files with 463 additions and 1056 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
|||
bin/
|
||||
build/
|
||||
logs/
|
||||
sandbox/
|
||||
|
||||
# clangd
|
||||
|
|
|
|||
17
Makefile
17
Makefile
|
|
@ -8,7 +8,6 @@ BUILD := build
|
|||
|
||||
LIB := lib
|
||||
CLI := cli
|
||||
CT := cursetree
|
||||
|
||||
# === MACRO DEFINITIONS ===
|
||||
define objpath
|
||||
|
|
@ -19,13 +18,13 @@ endef
|
|||
define mkobj
|
||||
$(foreach DEP, $?,
|
||||
mkdir -p $(dir $(call objpath, $(DEP)))
|
||||
$(CC) $(CFLAGS) $1 -o $(call objpath, $(DEP)) -c $(DEP))
|
||||
$(CC) $(CFLAGS) -o $(call objpath, $(DEP)) -c $(DEP))
|
||||
|
||||
$(LD) -r $(LDFLAGS) -o $@ $(call objpath, $?)
|
||||
endef
|
||||
|
||||
# === BUILD TARGETS ===
|
||||
all: $(BUILD) $(BIN) $(addprefix $(BIN)/,pw-test dorne)
|
||||
all: $(BUILD) $(BIN) $(addprefix $(BIN)/,pw-test shfx dorne)
|
||||
$(BIN)/pw-test: $(addprefix $(LIB)/, main.c)
|
||||
$(CC) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^
|
||||
$(CLD) $(CLDFLAGS) -lpipewire-0.3 -o $@ $(BUILD)/pw-test.o
|
||||
|
|
@ -37,11 +36,11 @@ $(BUILD) $(BIN):
|
|||
mkdir -p $@
|
||||
|
||||
$(BUILD)/dorne.o: $(addprefix $(CLI)/, main.c)
|
||||
$(call mkobj,-Icursetree)
|
||||
$(BUILD)/cursetree.o: $(addprefix $(CT)/, cursetree.c tree.c node.c surface.c dims.c ncrswrap.c)
|
||||
$(call mkobj,)
|
||||
$(BUILD)/epty.o: $(addprefix $(CT)/, pty/child.c pty/epty.c pty/_pty.c)
|
||||
$(call mkobj,)
|
||||
$(mkobj)
|
||||
$(BUILD)/cursetree.o: $(addprefix $(CLI)/, tree.c curse.c)
|
||||
$(mkobj)
|
||||
$(BUILD)/epty.o: $(addprefix $(CLI)/, child.c epty.c _pty.c)
|
||||
$(mkobj)
|
||||
|
||||
# === DEVELOPMENT TARGETS ===
|
||||
.PHONY: debug run test
|
||||
|
|
@ -56,4 +55,4 @@ test: clean run
|
|||
# === UTILITY TARGETS ===
|
||||
.PHONY: clean
|
||||
clean:
|
||||
- rm -rf $(BUILD) $(BIN) vgcore.* &>/dev/null logs/
|
||||
- rm -rf $(BUILD) $(BIN) vgcore.* &>/dev/null
|
||||
|
|
|
|||
|
|
@ -4,11 +4,6 @@
|
|||
A personal functional music programming framework written in Haskell & C and packaged with Nix.
|
||||
|
||||
### Setup
|
||||
Ensure that your system's version of ncurses has the following extensions:
|
||||
- wide character support
|
||||
- term resizing (see `man 3x resizeterm`)
|
||||
> TODO: actually list which extensions are used and how to compile with them
|
||||
|
||||
```bash
|
||||
nix build && nix develop -i
|
||||
```
|
||||
|
|
|
|||
8
TODO.md
8
TODO.md
|
|
@ -9,12 +9,4 @@ then fork and exec shfx as child (+ close ptmx), then close pts as parent.
|
|||
- [ ] Should I compile ncurses with --with-pthread? (see `man 3x ncurses`)
|
||||
What about --enable-widec? (are these just ligatures?)
|
||||
|
||||
- [ ] cursetree shits itself if width/height are 0 on bifurcation
|
||||
|
||||
- [ ] ensure NDEBUG is set for preprocessor to avoid <assert.h> statements if not debugging
|
||||
|
||||
|
||||
- [ ] resize_node() is quite wasteful and results could definitely be cached for the next resize_node() call
|
||||
|
||||
- I think this should help!
|
||||
https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/windows.html#OTHERBORDERFUNCS
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef CURSETREE_PTY_H
|
||||
#define CURSETREE_PTY_H
|
||||
#ifndef DORNE_MKPTY_H
|
||||
#define DORNE_MKPTY_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
|
@ -27,4 +27,4 @@ int setptsxy(const unsigned short rows, const unsigned short cols,
|
|||
const int fds);
|
||||
int getptsxy(unsigned short *rows, unsigned short *cols, const int fds);
|
||||
|
||||
#endif /* CURSETREE_PTY_H */
|
||||
#endif /* DORNE_MKPTY_H */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef CURSETREE_CHILD_H
|
||||
#define CURSETREE_CHILD_H
|
||||
#ifndef DORNE_CHILD_H
|
||||
#define DORNE_CHILD_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
|
@ -11,4 +11,4 @@ struct d_child {
|
|||
|
||||
int spawnchild(struct d_child *child);
|
||||
|
||||
#endif /* CURSETREE_CHILD_H */
|
||||
#endif /* DORNE_CHILD_H */
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_ncurses.h"
|
||||
|
||||
#include "ncrswrap.h"
|
||||
#include "curse.h"
|
||||
|
||||
#define BASE_DELAY 1000000
|
||||
#define CRS_LOCALE "en_US.UTF-8"
|
||||
|
||||
/* Set ncurses terminal mode (buffering, character processing,
|
||||
|
|
@ -26,18 +25,6 @@ int termmode(const enum crs_termmode mode) {
|
|||
}
|
||||
}
|
||||
|
||||
void termsize(int *const width, int *const height) {
|
||||
*width = COLS;
|
||||
*height = LINES;
|
||||
}
|
||||
|
||||
struct ct_dims *termdims(void) {
|
||||
struct ct_dims *dims = new_dims(0, 0, 0, 0);
|
||||
termsize(&dims->width, &dims->height);
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
/* Apply a default IO configuration for an ncurses WINDOW.
|
||||
*/
|
||||
static inline void __conf_window(WINDOW *const win) {
|
||||
|
|
@ -54,9 +41,8 @@ void init_ncurses(void) {
|
|||
// ncurses expects a locale for consistent behaviour
|
||||
setlocale(LC_ALL, CRS_LOCALE);
|
||||
|
||||
/* NCurses Initialisation */
|
||||
/* NCurses Init */
|
||||
initscr();
|
||||
/* WARNING: no you shouldn't delwin(stdscr) it breaks everything... */
|
||||
__conf_window(stdscr);
|
||||
start_color();
|
||||
|
||||
|
|
@ -67,10 +53,6 @@ void init_ncurses(void) {
|
|||
curs_set(0); // hide cursor
|
||||
}
|
||||
|
||||
void end_ncurses(void) {
|
||||
endwin();
|
||||
}
|
||||
|
||||
/* Initialise (with default IO configuration) a new ncurses WINDOW.
|
||||
*/
|
||||
WINDOW *new_window(const int x, const int y, const int width,
|
||||
|
|
@ -81,34 +63,52 @@ WINDOW *new_window(const int x, const int y, const int width,
|
|||
return win;
|
||||
}
|
||||
|
||||
/* Initialise (with default IO configuration) a fullscreen ncurses WINDOW.
|
||||
/* Initialise (with default IO configuration) the root ncurses WINDOW.
|
||||
* NOTE: This is typically done via initscr(3x) and called "stdscr".
|
||||
*/
|
||||
WINDOW *new_window_fs(void) {
|
||||
WINDOW *root_window(void) {
|
||||
WINDOW *rootwin = new_window(0, 0, COLS, LINES);
|
||||
__conf_window(rootwin);
|
||||
return rootwin;
|
||||
}
|
||||
|
||||
// void destroy_window(WINDOW *) __attribute__((alias("delwin")));
|
||||
|
||||
// int winposx(WINDOW *) __attribute__((alias("getbegy")));
|
||||
// int winposy(WINDOW *) __attribute__((alias("getbegy")));
|
||||
// int winwidth(WINDOW *) __attribute__((alias("getmaxx")));
|
||||
// int winheight(WINDOW *) __attribute__((alias("getmaxy")));
|
||||
|
||||
// struct ct_dims *windims(WINDOW *win) {
|
||||
// int x, y, width, height;
|
||||
// winpos(win, x, y);
|
||||
// winsize(win, width, height);
|
||||
// return new_dims(x, y, width, height);
|
||||
// }
|
||||
|
||||
/* Resize and move (if resized successfully) an ncurses WINDOW.
|
||||
* Returns ERR (1) on fail, and OK (0) on success.
|
||||
* NOTE: Failure occurs if width or height <= 0,
|
||||
* NOTE: or if the x,y coordinate is outside the screen bounds.
|
||||
*/
|
||||
int resizemv_window(WINDOW *const win, const int x, const int y,
|
||||
const int width, const int height) {
|
||||
int resizemv_window(const int x, const int y, const int width, const int height,
|
||||
WINDOW *const win) {
|
||||
return wresize(win, height, width) || mvwin(win, y, x);
|
||||
}
|
||||
|
||||
/*
|
||||
int main(const int argc, const char *const argv[]) {
|
||||
init_ncurses();
|
||||
WINDOW *stdscr = new_window(0, 0, 0, 0);
|
||||
|
||||
// Set background
|
||||
wbkgd(stdscr, COLOR_PAIR(1));
|
||||
|
||||
attron(COLOR_PAIR(1));
|
||||
attron(A_BOLD);
|
||||
int counter = 0;
|
||||
while (1) {
|
||||
mvprintw(0, 0, "COUNTER %d", counter++);
|
||||
refresh();
|
||||
|
||||
switch (getch()) {
|
||||
case 'q':
|
||||
goto end;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(BASE_DELAY);
|
||||
}
|
||||
|
||||
end:
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
27
cli/curse.h
Normal file
27
cli/curse.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef DORNE_CURSE_H
|
||||
#define DORNE_CURSE_H
|
||||
|
||||
/* libncurses with wide-character support. */
|
||||
#include <ncursesw/ncurses.h>
|
||||
|
||||
enum crs_termmode {
|
||||
/* tty cbreak mode */
|
||||
TMODE_CBREAK,
|
||||
/* tty raw mode */
|
||||
TMODE_RAW,
|
||||
/* tty cooked mode (ISIG & IXON not modified)*/
|
||||
TMODE_NOCBREAK,
|
||||
/* tty cooked mode (ISIG & IXON set) */
|
||||
TMODE_NORAW,
|
||||
};
|
||||
|
||||
int termmode(const enum crs_termmode mode);
|
||||
|
||||
void init_ncurses(void);
|
||||
WINDOW *new_window(const int x, const int y, const int width, const int height);
|
||||
WINDOW *root_window(void);
|
||||
|
||||
int resizemv_window(const int x, const int y, const int width, const int height,
|
||||
WINDOW *const win);
|
||||
|
||||
#endif /* DORNE_CURSE_H */
|
||||
8
cli/epty.h
Normal file
8
cli/epty.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef DORNE_EPTY_H
|
||||
#define DORNE_EPTY_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
pid_t forkepty(int *fdmx, int *fderr);
|
||||
|
||||
#endif /* DORNE_EPTY_H */
|
||||
109
cli/main.c
109
cli/main.c
|
|
@ -4,66 +4,79 @@
|
|||
|
||||
#include <ncursesw/ncurses.h>
|
||||
|
||||
#include "cursetree.h"
|
||||
#include "surface.h"
|
||||
// #include "child.h"
|
||||
#include "curse.h"
|
||||
#include "tree.h"
|
||||
|
||||
#define nprintsfdims(nout, i, label, nin) \
|
||||
(mvwprintw((nout)->surface->win, (i), 0, "%s@(%d,%d) %dx%d", (label), \
|
||||
(nin)->surface->dims->x, (nin)->surface->dims->y, \
|
||||
(nin)->surface->dims->width, (nin)->surface->dims->height))
|
||||
// struct d_window {
|
||||
// int ptmx; // fd
|
||||
// };
|
||||
|
||||
// struct d_window new_window() {
|
||||
// struct d_window w = {
|
||||
// .ptmx = posix_openpt(O_RDWR | O_NOCTTY),
|
||||
// };
|
||||
// }
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct ct_tree *tree;
|
||||
ct_init(&tree);
|
||||
// struct d_child child;
|
||||
// spawnchild(&child);
|
||||
|
||||
init_pair(1, COLOR_BLACK, COLOR_CYAN);
|
||||
init_pair(2, COLOR_BLACK, COLOR_RED);
|
||||
init_pair(3, COLOR_BLACK, COLOR_GREEN);
|
||||
init_pair(4, COLOR_BLACK, COLOR_MAGENTA);
|
||||
init_pair(5, COLOR_BLACK, COLOR_YELLOW);
|
||||
struct crs_tree *tree;
|
||||
init_tree(&tree);
|
||||
|
||||
struct ct_node *const child1 = new_node(bounds_none(), tree->root);
|
||||
// struct ct_node *const child2 = new_node(bounds_none(), tree->root);
|
||||
// struct ct_node *const child3 = new_node(bounds_none(), tree->root);
|
||||
// struct ct_node *const child4 = new_node(bounds_none(), tree->root);
|
||||
// struct ct_node *const child5 = new_node(bounds_none(), tree->root);
|
||||
append_child_node(tree->root, child1);
|
||||
// append_child_node(tree->root, child2);
|
||||
// append_child_node(tree->root, child3);
|
||||
// append_child_node(tree->root, child4);
|
||||
// append_child_node(tree->root, child5);
|
||||
init_pair(1, COLOR_CYAN, COLOR_CYAN);
|
||||
init_pair(2, COLOR_RED, COLOR_RED);
|
||||
init_pair(3, COLOR_MAGENTA, COLOR_MAGENTA);
|
||||
init_pair(4, COLOR_YELLOW, COLOR_YELLOW);
|
||||
init_pair(5, COLOR_GREEN, COLOR_GREEN);
|
||||
|
||||
wbkgd(child1->surface->win, COLOR_PAIR(1));
|
||||
// wbkgd(child2->surface->win, COLOR_PAIR(2));
|
||||
// wbkgd(child3->surface->win, COLOR_PAIR(3));
|
||||
// wbkgd(child4->surface->win, COLOR_PAIR(4));
|
||||
// wbkgd(child5->surface->win, COLOR_PAIR(5));
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
/* BUG TODO : PROGRAM SHITS ITSELF IF RATIO MAKES WIDTH/HEIGHT 0, MAYBE CLAMP? : TODO BUG*/
|
||||
bifurcate_window_node(&tree->root, AXIS_X, FALSE, 0.5);
|
||||
bifurcate_window_node(&tree->root->child[0], AXIS_X, FALSE, 0.05);
|
||||
bifurcate_window_node(&tree->root->child[1], AXIS_Y, FALSE, 0.7);
|
||||
bifurcate_window_node(&tree->root->child[1]->child[1], AXIS_X, FALSE, 0.9);
|
||||
|
||||
// child3->axis = AXIS_Y;
|
||||
// struct ct_node *const child3_1 = new_node(bounds_none(), child3);
|
||||
// struct ct_node *const child3_2 = new_node(bounds_none(), child3);
|
||||
// append_child_node(child3, child3_1);
|
||||
// append_child_node(child3, child3_2);
|
||||
// wbkgd(child3_1->surface->win, COLOR_PAIR(1));
|
||||
// wbkgd(child3_2->surface->win, COLOR_PAIR(5));
|
||||
wbkgd(tree->root->child[0]->child[0]->win, COLOR_PAIR(5));
|
||||
wbkgd(tree->root->child[0]->child[1]->win, COLOR_PAIR(3));
|
||||
wbkgd(tree->root->child[1]->child[0]->win, COLOR_PAIR(2));
|
||||
wbkgd(tree->root->child[1]->child[1]->child[0]->win, COLOR_PAIR(1));
|
||||
wbkgd(tree->root->child[1]->child[1]->child[1]->win, COLOR_PAIR(4));
|
||||
wrefresh(tree->root->child[0]->child[0]->win);
|
||||
wrefresh(tree->root->child[0]->child[1]->win);
|
||||
wrefresh(tree->root->child[1]->child[0]->win);
|
||||
wrefresh(tree->root->child[1]->child[1]->child[0]->win);
|
||||
wrefresh(tree->root->child[1]->child[1]->child[1]->win);
|
||||
|
||||
/* NOTE : THIS IS VALID : NOTE */
|
||||
// refresh();
|
||||
// WINDOW *my_win = newwin(0, 0, 0, 0);
|
||||
// wbkgd(my_win, COLOR_PAIR(1));
|
||||
// wrefresh(my_win);
|
||||
|
||||
/* NOTE : THIS IS VALID : NOTE */
|
||||
// wbkgd(tree->root->win, COLOR_PAIR(2));
|
||||
// wrefresh(tree->root->win);
|
||||
|
||||
while (1) {
|
||||
ct_update(tree);
|
||||
|
||||
// nprintsfdims(child2, 0, "R", tree->root);
|
||||
// nprintsfdims(child2, 1, "1", child1);
|
||||
// nprintsfdims(child2, 2, "2", child2);
|
||||
// nprintsfdims(child2, 3, "3", child3);
|
||||
// nprintsfdims(child2, 4, "4", child4);
|
||||
// nprintsfdims(child2, 5, "5", child5);
|
||||
|
||||
// nprintsfdims(child2, 7, "3_1", child3_1);
|
||||
// nprintsfdims(child2, 8, "3_2", child3_2);
|
||||
|
||||
ct_process(tree);
|
||||
// refresh();
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
destroy_tree(tree);
|
||||
// endwin();
|
||||
// free(tree);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
245
cli/tree.c
Normal file
245
cli/tree.c
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "curse.h"
|
||||
#include "tree.h"
|
||||
|
||||
/* Internal allocator method for crs_node structures.
|
||||
*/
|
||||
static inline struct crs_node *__alloc_node(const enum crs_nodetype type) {
|
||||
struct crs_node *node = (struct crs_node *)malloc(sizeof(struct crs_node));
|
||||
node->type = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Construct a new window node (crs_node of type NODE_WIN).
|
||||
*/
|
||||
static struct crs_node *init_window_node(WINDOW *const win) {
|
||||
struct crs_node *node = __alloc_node(NODE_WINDOW);
|
||||
node->win = win;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct crs_node *auto_window_node(const struct crs_nodedims *dims) {
|
||||
WINDOW *win = newwin(dims->height, dims->width, dims->y, dims->x);
|
||||
return init_window_node(win);
|
||||
}
|
||||
|
||||
static struct crs_node *init_abstract_node(struct crs_node *node0,
|
||||
struct crs_node *node1,
|
||||
const enum crs_axis axis,
|
||||
const float ratio,
|
||||
struct crs_nodedims *dims) {
|
||||
struct crs_node *node = __alloc_node(NODE_ABSTRACT);
|
||||
node->axis = axis;
|
||||
node->ratio = ratio;
|
||||
node->dims = dims;
|
||||
|
||||
node->child[0] = node0;
|
||||
node->child[1] = node1;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void destroy_node(struct crs_node *node) {
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
delwin(node->win);
|
||||
goto end;
|
||||
}
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
destroy_node(node->child[0]);
|
||||
destroy_node(node->child[1]);
|
||||
free(node->dims);
|
||||
|
||||
end:
|
||||
free(node);
|
||||
}
|
||||
|
||||
static inline struct crs_nodedims *__dup_dims(const struct crs_nodedims *dims) {
|
||||
struct crs_nodedims *dup;
|
||||
dup = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims));
|
||||
memcpy(dup, dims, sizeof(struct crs_nodedims));
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static struct crs_nodedims *get_dims(const struct crs_node *node) {
|
||||
struct crs_nodedims *dims;
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims));
|
||||
// GET_WNODEDIMS();
|
||||
getbegyx(node->win, dims->y, dims->x);
|
||||
getmaxyx(node->win, dims->height, dims->width);
|
||||
printf("getx: %d\n", dims->x);
|
||||
printf("gety: %d\n", dims->y);
|
||||
printf("getwidth: %d\n", dims->width);
|
||||
printf("getheight: %d\n", dims->height);
|
||||
} else {
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
dims = __dup_dims(node->dims);
|
||||
}
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
struct crs_nodedims term_dims(void) {
|
||||
struct crs_nodedims dims;
|
||||
getbegyx(stdscr, dims.y, dims.x);
|
||||
getmaxyx(stdscr, dims.height, dims.width);
|
||||
return dims;
|
||||
}
|
||||
|
||||
/* Calculate the dimensions for nodes resulting from a bifurcation.
|
||||
* Returns 0 on success, and 1 on failure if any width/height are 0 characters.
|
||||
* WARNING: This function does not guarantee the x,y positions returned
|
||||
* WARNING: are valid screen coordinates.
|
||||
*/
|
||||
static int bifurcate_dims(const struct crs_node *parent,
|
||||
const enum crs_axis axis, const float ratio,
|
||||
struct crs_nodedims **dims0,
|
||||
struct crs_nodedims **dims1) {
|
||||
assert(0 < ratio && ratio < 1);
|
||||
struct crs_nodedims *_dims0, *_dims1;
|
||||
|
||||
_dims0 = get_dims(parent);
|
||||
_dims1 = __dup_dims(_dims0);
|
||||
|
||||
printf("widthP: %d\n", _dims0->width);
|
||||
printf("heightP: %d\n", _dims0->height);
|
||||
|
||||
if (axis == AXIS_X) {
|
||||
_dims0->width *= ratio;
|
||||
_dims1->width -= _dims0->width;
|
||||
_dims1->x += _dims0->width;
|
||||
} else {
|
||||
_dims0->height *= ratio;
|
||||
_dims1->height -= _dims0->height;
|
||||
_dims1->y += _dims0->height;
|
||||
}
|
||||
|
||||
if (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height) {
|
||||
printf("width0: %d\n", _dims0->width);
|
||||
printf("height0: %d\n", _dims0->height);
|
||||
printf("width1: %d\n", _dims1->width);
|
||||
printf("height1: %d\n", _dims1->height);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// propagate bifurcated dimensions
|
||||
*dims0 = _dims0;
|
||||
*dims1 = _dims1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void resize_node(struct crs_node *node, struct crs_nodedims *new_dims) {
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
resizemv_window(new_dims->x, new_dims->y, new_dims->width, new_dims->height,
|
||||
node->win);
|
||||
free(new_dims);
|
||||
} else {
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
struct crs_nodedims *dims0, *dims1;
|
||||
|
||||
free(node->dims);
|
||||
node->dims = new_dims;
|
||||
bifurcate_dims(node, node->axis, node->ratio, &dims0, &dims1);
|
||||
|
||||
resize_node(node->child[0], dims0);
|
||||
resize_node(node->child[1], dims1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Subdivide a window node's allocated region into two window nodes
|
||||
* replacing the original node with an abstract node.
|
||||
* Parameters:
|
||||
* axis - controls which direction the subdivision occurs
|
||||
* invert_axis - invert index of the original node in the new abstract node
|
||||
*/
|
||||
void bifurcate_window_node(struct crs_node **node, const enum crs_axis axis,
|
||||
const int invert_axis, const float ratio) {
|
||||
assert((*node)->type == NODE_WINDOW);
|
||||
struct crs_nodedims *dims0, *dims1;
|
||||
struct crs_node *node0, *node1;
|
||||
|
||||
if (bifurcate_dims(*node, axis, ratio, &dims0, &dims1)) {
|
||||
printf("FAILED TERRIBLY THE FUCK\n");
|
||||
exit(1);
|
||||
return;
|
||||
}
|
||||
if (invert_axis) {
|
||||
/* Inverted Bifurcation */
|
||||
node0 = auto_window_node(dims0);
|
||||
node1 = *node;
|
||||
resize_node(node1, dims1);
|
||||
} else {
|
||||
/* Non-Inverted Bifurcation */
|
||||
node0 = *node;
|
||||
node1 = auto_window_node(dims1);
|
||||
resize_node(node0, dims0);
|
||||
}
|
||||
|
||||
*node = init_abstract_node(node0, node1, axis, ratio, (*node)->dims);
|
||||
}
|
||||
|
||||
/* Collapse an abstract node, killing one child node and resizing
|
||||
* the other to take its place.
|
||||
*/
|
||||
static void collapse_abstract_node(struct crs_node **node,
|
||||
const int collapse_i) {
|
||||
assert((*node)->type == NODE_ABSTRACT);
|
||||
assert(0 <= collapse_i && collapse_i < NODE_CHILD_N);
|
||||
|
||||
// WARNING: only works for NODE_CHILD_N=2 (binary trees)
|
||||
destroy_node((*node)->child[!collapse_i]);
|
||||
|
||||
struct crs_node *collapse_target = (*node)->child[collapse_i];
|
||||
free(*node);
|
||||
*node = collapse_target;
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
static struct crs_node *init_root_node(void) {
|
||||
struct crs_nodedims rootdims;
|
||||
WINDOW *rootwin;
|
||||
|
||||
// rootdims = term_dims();
|
||||
// rootwin = new_window(rootdims.x, rootdims.y,
|
||||
// rootdims.height, rootdims.height);
|
||||
// rootwin = new_window(0, 0, 0, 0);
|
||||
rootwin = root_window();
|
||||
return init_window_node(rootwin);
|
||||
}
|
||||
|
||||
int init_tree(struct crs_tree **const tree) {
|
||||
*tree = (struct crs_tree *)malloc(sizeof(struct crs_tree));
|
||||
|
||||
/* Initialise NCurses Library & Standard Screen */
|
||||
init_ncurses();
|
||||
|
||||
(*tree)->root = init_root_node();
|
||||
|
||||
// (*tree)->root = __alloc_node(NODE_WINDOW);
|
||||
// crs_init(&(*tree)->root->win);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_tree(struct crs_tree *const tree) {
|
||||
/* WARNING: is it ok to delwin(stdscr) ?? */
|
||||
destroy_node(tree->root);
|
||||
|
||||
endwin();
|
||||
free(tree);
|
||||
}
|
||||
|
||||
void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims) {
|
||||
resize_node(tree->root, dims);
|
||||
}
|
||||
61
cli/tree.h
Normal file
61
cli/tree.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef DORNE_TREE_H
|
||||
#define DORNE_TREE_H
|
||||
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
#define NODE_CHILD_N 2
|
||||
|
||||
/* MACRO:
|
||||
* Get widnow node start x,y coordinates, width, & height.
|
||||
* void NODEDIMS(struct crs_node *node, struct crs_nodedims dims);
|
||||
*/
|
||||
#define GET_WNODEDIMS(dims, node) \
|
||||
(getbegyx((node)->win, dims.y, dims.x)); \
|
||||
getmaxyx((node)->win, dims.y, dims.x)
|
||||
|
||||
enum crs_nodetype {
|
||||
NODE_WINDOW,
|
||||
NODE_ABSTRACT,
|
||||
};
|
||||
|
||||
/* Stores a node's starting x,y coordinates, width, & height.
|
||||
* NOTE: Intended for interfunction communication.
|
||||
*/
|
||||
struct crs_nodedims {
|
||||
int x, y, width, height;
|
||||
};
|
||||
|
||||
enum crs_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
};
|
||||
|
||||
struct crs_node {
|
||||
enum crs_nodetype type;
|
||||
// union value depends on crs_node.type
|
||||
union {
|
||||
WINDOW *win;
|
||||
struct {
|
||||
enum crs_axis axis;
|
||||
float ratio;
|
||||
struct crs_nodedims *dims;
|
||||
struct crs_node *child[NODE_CHILD_N];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct crs_tree {
|
||||
struct crs_node *root;
|
||||
};
|
||||
|
||||
/* === External Interface === */
|
||||
int init_tree(struct crs_tree **const tree);
|
||||
void destroy_tree(struct crs_tree *const tree);
|
||||
void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims);
|
||||
|
||||
void bifurcate_window_node(struct crs_node **node, const enum crs_axis axis,
|
||||
const int invert_axis, const float ratio);
|
||||
|
||||
#endif /* DORNE_TREE_H */
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
/* This file exists to isolate the ncurses instance being used
|
||||
* ie ncurses, ncursesw, ncursest, ncursestw
|
||||
*/
|
||||
|
||||
/* libncurses with wide-character support. */
|
||||
#include <ncursesw/ncurses.h>
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_ncurses.h"
|
||||
#include "ncrswrap.h"
|
||||
#include "ncurses.h"
|
||||
#include "node.h"
|
||||
#include "tree.h"
|
||||
|
||||
volatile sig_atomic_t got_winch = 0;
|
||||
|
||||
void handle_SIGWINCH(int sig) {
|
||||
// endwin();
|
||||
// Needs to be called after an endwin() so ncurses will initialize
|
||||
// itself with the new terminal dimensions.
|
||||
got_winch = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If ncurses is configured to supply its own SIGWINCH handler,
|
||||
* - on receipt of a SIGWINCH, the handler sets a flag
|
||||
* - which is tested in wgetch(3X), doupdate(3X) and restartterm(3X),
|
||||
* - in turn, calling the resizeterm function,
|
||||
* - which ungetch's a KEY_RESIZE which will be read on the next call to
|
||||
* wgetch. REF: `man resizeterm(3x)`
|
||||
*/
|
||||
static void bind_SIGWINCH(void) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = handle_SIGWINCH;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART; /* Restart functions if
|
||||
interrupted by handler */
|
||||
if (sigaction(SIGWINCH, &sa, NULL) == -1) {
|
||||
perror("bind_SIGWINCH");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int ct_init(struct ct_tree **const tree) {
|
||||
// bind_SIGWINCH();
|
||||
/* Initialise NCurses Library & Root Node */
|
||||
init_ncurses();
|
||||
init_tree(tree);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void ct_redraw(void) {
|
||||
/* TODO: hide doupdate() behind some other method */
|
||||
/* flush ncurses virtual screen -> physical screen */
|
||||
doupdate();
|
||||
}
|
||||
|
||||
/* Recursively search the tree for update requests.
|
||||
* Returns:
|
||||
* 0 - success (no action required)
|
||||
* 1 - success (request: redraw the screen)
|
||||
*/
|
||||
static int __update_rec(struct ct_node *const node) {
|
||||
int result = 0;
|
||||
struct ct_dims *dims;
|
||||
|
||||
if (node->flags & NFLAG_RESIZE) {
|
||||
/* TODO: the child has requested a resizing, but resize_node()
|
||||
* TODO: wastes CPU time resizing itself!
|
||||
*/
|
||||
dims = IS_ROOT_NODE(node) ? termdims() : dup_dims(node->surface->dims);
|
||||
resize_node(node, dims);
|
||||
node->flags &= ~NFLAG_RESIZE;
|
||||
result = 1;
|
||||
}
|
||||
if (node->surface->updatereq) {
|
||||
// TODO: is this necessary or does mvresize_win do this for us?
|
||||
wnoutrefresh(node->surface->win);
|
||||
node->surface->updatereq = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->cindex; i++) {
|
||||
result |= __update_rec(node->child[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ct_update(struct ct_tree *const tree) {
|
||||
// WARNING: update_rec does not flush the screen, wgetch will do that for us
|
||||
if (__update_rec(tree->root)) {
|
||||
doupdate();
|
||||
// redrawwin(curscr);
|
||||
// wrefresh(curscr);
|
||||
}
|
||||
}
|
||||
|
||||
void ct_process(struct ct_tree *const tree) {
|
||||
const int key = wgetch(curscr);
|
||||
// int key = -1;
|
||||
|
||||
/* ncurses binds a SIGWINCH handler if SIGWINCH has SIG_DFL disposition
|
||||
* when initscr(3x) is called. This handler emits KEY_RESIZE (decimal 410) to
|
||||
* stdin. REF: manpages -> resizeterm(3x) initscr(3x) wgetch(3x)
|
||||
*/
|
||||
switch (key) {
|
||||
case -1:
|
||||
// wclear(tree->root->surface->win);
|
||||
// mvwprintw(tree->root->surface->win, 0, 0, " \r-1\n");
|
||||
// wrefresh(tree->root->surface->win);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
// got_winch = 1;
|
||||
tree->root->flags |= NFLAG_RESIZE;
|
||||
break;
|
||||
default:
|
||||
// wclear(tree->root->surface->win);
|
||||
// mvwprintw(tree->root->surface->win, 0, 0, " \r%d\n", key);
|
||||
// wrefresh(tree->root->surface->win);
|
||||
break;
|
||||
}
|
||||
|
||||
// if (got_winch == 1) {
|
||||
// tree->root->flags |= NFLAG_RESIZE;
|
||||
// got_winch = 0;
|
||||
// }
|
||||
|
||||
// if (__update_rec(tree->root)) {
|
||||
// ct_redraw();
|
||||
// }
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef CURSETREE_CURSETREE_H
|
||||
#define CURSETREE_CURSETREE_H
|
||||
|
||||
#include "tree.h"
|
||||
|
||||
/* === External Interface === */
|
||||
int ct_init(struct ct_tree **const tree);
|
||||
void ct_update(struct ct_tree *const tree);
|
||||
void ct_process(struct ct_tree *const tree);
|
||||
|
||||
#endif /* CURSETREE_CURSETREE_H */
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dims.h"
|
||||
#include "node.h"
|
||||
#include "util.h"
|
||||
|
||||
struct ct_dims *new_dims(const int x, const int y, const int width, const int height) {
|
||||
struct ct_dims *dims;
|
||||
|
||||
dims = (struct ct_dims *)malloc(sizeof(struct ct_dims));
|
||||
*dims = (struct ct_dims){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
return dims;
|
||||
}
|
||||
|
||||
struct ct_dims *dup_dims(const struct ct_dims *const dims) {
|
||||
struct ct_dims *dup;
|
||||
dup = (struct ct_dims *)malloc(sizeof(struct ct_dims));
|
||||
memcpy(dup, dims, sizeof(struct ct_dims));
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
static struct ct_bounds *__bounds(const enum ct_boundtype type, const int wmin,
|
||||
const int wmax, const int hmin,
|
||||
const int hmax) {
|
||||
struct ct_bounds *bounds;
|
||||
|
||||
bounds = (struct ct_bounds *)malloc(sizeof(struct ct_bounds));
|
||||
*bounds = (struct ct_bounds){
|
||||
.type = type,
|
||||
.wmin = wmin,
|
||||
.wmax = wmax,
|
||||
.hmin = hmin,
|
||||
.hmax = hmax,
|
||||
};
|
||||
return bounds;
|
||||
}
|
||||
|
||||
static inline void __clamp(int *const val, const int min, const int max,
|
||||
const int do_ceiling) {
|
||||
if (*val == __BOUND_UNLIMITED)
|
||||
*val = do_ceiling ? max : min;
|
||||
else
|
||||
*val = clampi(*val, min, max);
|
||||
}
|
||||
#define CLAMP_ABS(val, is_max) \
|
||||
(__clamp(&val, __BOUND_ABS_MIN, __BOUND_ABS_MAX, is_max))
|
||||
#define CLAMP_REL(val, is_max) \
|
||||
(__clamp(&val, __BOUND_REL_MIN, __BOUND_REL_MAX, is_max))
|
||||
|
||||
struct ct_bounds *bounds_none(void) {
|
||||
return __bounds(BOUND_NONE, __BOUND_ABS_MIN, __BOUND_ABS_MAX, __BOUND_ABS_MIN,
|
||||
__BOUND_ABS_MAX);
|
||||
}
|
||||
|
||||
struct ct_bounds *bounds_absolute(int wmin, int wmax,
|
||||
int hmin, int hmax) {
|
||||
CLAMP_ABS(wmin, false);
|
||||
CLAMP_ABS(wmax, true);
|
||||
CLAMP_ABS(hmin, false);
|
||||
CLAMP_ABS(hmax, true);
|
||||
return __bounds(BOUND_ABSOLUTE, wmin, wmax, hmin, hmax);
|
||||
}
|
||||
|
||||
struct ct_bounds *bounds_relative(int wmin, int wmax,
|
||||
int hmin, int hmax) {
|
||||
CLAMP_REL(wmin, false);
|
||||
CLAMP_REL(wmax, true);
|
||||
CLAMP_REL(hmin, false);
|
||||
CLAMP_REL(hmax, true);
|
||||
return __bounds(BOUND_RELATIVE, wmin, wmax, hmin, hmax);
|
||||
}
|
||||
|
||||
struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds) {
|
||||
struct ct_bounds *dup;
|
||||
dup = (struct ct_bounds *)malloc(sizeof(struct ct_bounds));
|
||||
memcpy(dup, bounds, sizeof(struct ct_bounds));
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef CURSETREE_DIMS_H
|
||||
#define CURSETREE_DIMS_H
|
||||
|
||||
#define __BOUND_UNLIMITED (-1)
|
||||
#define __BOUND_ABS_MIN (1)
|
||||
#define __BOUND_ABS_MAX (INT_MAX / CINDEX_MAX - 1)
|
||||
#define __BOUND_REL_MIN ((float)0)
|
||||
#define __BOUND_REL_MAX ((float)1)
|
||||
|
||||
enum ct_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
};
|
||||
|
||||
enum ct_boundtype {
|
||||
BOUND_NONE,
|
||||
BOUND_ABSOLUTE,
|
||||
BOUND_RELATIVE,
|
||||
};
|
||||
|
||||
/* Stores a node's starting x,y coordinates, width, & height.
|
||||
* NOTE: Intended for interfunction communication.
|
||||
*/
|
||||
struct ct_dims {
|
||||
int x, y, width, height;
|
||||
};
|
||||
|
||||
struct ct_bounds {
|
||||
enum ct_boundtype type;
|
||||
int wmin, wmax, hmin, hmax;
|
||||
};
|
||||
|
||||
struct ct_dims *new_dims(const int x, const int y, const int width, const int height);
|
||||
struct ct_dims *dup_dims(const struct ct_dims *const dims);
|
||||
|
||||
struct ct_bounds *bounds_none(void);
|
||||
struct ct_bounds *bounds_absolute(int wmin, int wmax, int hmin, int hmax);
|
||||
struct ct_bounds *bounds_relative(int wmin, int wmax, int hmin, int hmax);
|
||||
struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds);
|
||||
|
||||
#endif /* CURSETREE_DIMS_H */
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#ifndef CURSETREE_NCRSWRAP_H
|
||||
#define CURSETREE_NCRSWRAP_H
|
||||
|
||||
#include "dims.h"
|
||||
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
enum crs_termmode {
|
||||
/* tty cbreak mode */
|
||||
TMODE_CBREAK,
|
||||
/* tty raw mode */
|
||||
TMODE_RAW,
|
||||
/* tty cooked mode (ISIG & IXON not modified)*/
|
||||
TMODE_NOCBREAK,
|
||||
/* tty cooked mode (ISIG & IXON set) */
|
||||
TMODE_NORAW,
|
||||
};
|
||||
|
||||
int termmode(const enum crs_termmode mode);
|
||||
void termsize(int *const width, int *const height);
|
||||
struct ct_dims *termdims(void);
|
||||
|
||||
void init_ncurses(void);
|
||||
void end_ncurses(void);
|
||||
|
||||
WINDOW *new_window(const int x, const int y, const int width, const int height);
|
||||
WINDOW *new_window_fs(void);
|
||||
void destroy_window(WINDOW *);
|
||||
|
||||
int resizemv_window(WINDOW *const win, const int x, const int y,
|
||||
const int width, const int height);
|
||||
|
||||
#endif /* CURSETREE_NCRSWRAP_H */
|
||||
359
cursetree/node.c
359
cursetree/node.c
|
|
@ -1,359 +0,0 @@
|
|||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dims.h"
|
||||
#include "node.h"
|
||||
#include "surface.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Internal allocator method for ct_node structures.
|
||||
*/
|
||||
static inline struct ct_node *__alloc_node(void) {
|
||||
struct ct_node *node = (struct ct_node *)malloc(sizeof(struct ct_node));
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Returns NULL if memory allocation failed.
|
||||
* TODO: should dims be given as a parameter, or lazily computed in ct_update?
|
||||
*/
|
||||
struct ct_node *__node(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent) {
|
||||
struct ct_node *node = __alloc_node();
|
||||
if (node != NULL) {
|
||||
*node = (struct ct_node){
|
||||
.surface = new_surface(dims, bounds),
|
||||
.flags = NFLAG_EMPTY,
|
||||
|
||||
.parent = parent,
|
||||
.child = (struct ct_node **)malloc(NODE_INIT_CHILDREN *
|
||||
sizeof(struct ct_node *)),
|
||||
.csize = NODE_INIT_CHILDREN,
|
||||
.cindex = 0,
|
||||
.axis = AXIS_X,
|
||||
};
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct ct_node *new_node(struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent) {
|
||||
/* copy the parent's dimensions for now and request
|
||||
* cursetree resize this node appropriately afterwards
|
||||
* WARNING: new_node doesn't set the NFLAG_RESIZE request flag
|
||||
* WARNING: that should be done by a function calling new_node
|
||||
*/
|
||||
return __node(dup_dims(parent->surface->dims), bounds, parent);
|
||||
}
|
||||
|
||||
/* WARNING: Do NOT use __destroy_node() to destroy a node's children!
|
||||
* WARNING: Use the destroy_child_node() function instead.
|
||||
*/
|
||||
void __destroy_node(struct ct_node *const node) {
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
// destroy children first
|
||||
for (int j = 0; j < node->cindex; j++) {
|
||||
__destroy_node(node->child[j]);
|
||||
}
|
||||
|
||||
destroy_surface(node->surface);
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Surface Partition Dimensions */
|
||||
/* TODO: can I use unsigned short instead of int? */
|
||||
struct ct_spdims {
|
||||
// Main Axis & Orthogonal Axis Sizes
|
||||
int axm_size;
|
||||
bool fixed;
|
||||
int min, max;
|
||||
};
|
||||
|
||||
/*
|
||||
*/
|
||||
int resize_node(struct ct_node *const node, struct ct_dims *dims) {
|
||||
resize_surface(node->surface, dims);
|
||||
dims = node->surface->dims;
|
||||
|
||||
if (node->surface->bounds->wmin > dims->width ||
|
||||
node->surface->bounds->hmin > dims->height) {
|
||||
node->flags |= NFLAG_SMALL;
|
||||
return 1;
|
||||
} else if (node->surface->bounds->wmax < dims->width ||
|
||||
node->surface->bounds->hmax < dims->height) {
|
||||
node->flags |= NFLAG_LARGE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!IS_PARENT_NODE(node))
|
||||
return 0;
|
||||
|
||||
if (node->cbounds.wmin_abs + node->cbounds.wmin_rel * dims->width >
|
||||
dims->width ||
|
||||
node->cbounds.hmin_abs + node->cbounds.hmin_rel * dims->height >
|
||||
dims->height) {
|
||||
node->flags |= NFLAG_SMALLCHILD;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int axm_size, axm_free;
|
||||
size_t bounds_axm_min_offset, bounds_axm_max_offset;
|
||||
size_t dims_axm_pos_offset, dims_axm_size_offset;
|
||||
|
||||
if (node->axis == AXIS_X) {
|
||||
axm_free = dims->width;
|
||||
axm_size = dims->width;
|
||||
|
||||
dims_axm_pos_offset = offsetof(struct ct_dims, x);
|
||||
dims_axm_size_offset = offsetof(struct ct_dims, width);
|
||||
bounds_axm_min_offset = offsetof(struct ct_bounds, wmin);
|
||||
bounds_axm_max_offset = offsetof(struct ct_bounds, wmax);
|
||||
} else {
|
||||
assert(node->axis == AXIS_Y);
|
||||
axm_free = dims->height;
|
||||
axm_size = dims->height;
|
||||
|
||||
dims_axm_pos_offset = offsetof(struct ct_dims, y);
|
||||
dims_axm_size_offset = offsetof(struct ct_dims, height);
|
||||
bounds_axm_min_offset = offsetof(struct ct_bounds, hmin);
|
||||
bounds_axm_max_offset = offsetof(struct ct_bounds, hmax);
|
||||
}
|
||||
|
||||
struct ct_spdims cspdims[node->cindex];
|
||||
cindex parts_n = node->cindex;
|
||||
memset(cspdims, 0, sizeof(struct ct_spdims) * node->cindex);
|
||||
for (int i = 0; i < node->cindex; i++) {
|
||||
cspdims[i].min = *(int *)((char *)node->child[i]->surface->bounds +
|
||||
bounds_axm_min_offset);
|
||||
cspdims[i].max = *(int *)((char *)node->child[i]->surface->bounds +
|
||||
bounds_axm_max_offset);
|
||||
|
||||
if (node->child[i]->surface->bounds->type == BOUND_RELATIVE) {
|
||||
cspdims[i].min *= axm_size;
|
||||
cspdims[i].max *= axm_size;
|
||||
}
|
||||
|
||||
cspdims[i].axm_size = 0;
|
||||
}
|
||||
|
||||
int split, new_size;
|
||||
while (axm_free && parts_n) {
|
||||
split = (axm_free > parts_n) ? (axm_free / parts_n) : 1;
|
||||
for (int i = 0; i < node->cindex; i++) {
|
||||
if (cspdims[i].fixed)
|
||||
continue;
|
||||
|
||||
new_size =
|
||||
clampi(cspdims[i].axm_size + split, cspdims[i].min, cspdims[i].max);
|
||||
|
||||
if (new_size == cspdims[i].axm_size) {
|
||||
cspdims[i].fixed = true;
|
||||
parts_n--;
|
||||
continue;
|
||||
}
|
||||
|
||||
axm_free -= (new_size - cspdims[i].axm_size);
|
||||
cspdims[i].axm_size = new_size;
|
||||
|
||||
if (axm_free == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ct_dims *cdims = dup_dims(dims);
|
||||
/* NOTE: the statements below are done implicitly by dup_dims */
|
||||
// *(int*)(cdims + dims_axm_pos_offset) = *(int*)(dims +
|
||||
// dims_axm_pos_offset);
|
||||
// *(int*)(cdims + dims_axo_pos_offset) = *(int*)(dims +
|
||||
// dims_axo_pos_offset);
|
||||
// *(int*)(cdims + dims_axo_size_offset) = axo_size;
|
||||
for (int i = 0; i < node->cindex; i++) {
|
||||
*(int *)((char *)cdims + dims_axm_size_offset) = cspdims[i].axm_size;
|
||||
resize_node(node->child[i], dup_dims(cdims));
|
||||
*(int *)((char *)cdims + dims_axm_pos_offset) += cspdims[i].axm_size;
|
||||
}
|
||||
free(cdims);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __set_cbounds(struct ct_node *const parent,
|
||||
const struct ct_node *const child,
|
||||
const bool additive) {
|
||||
/* child and parent w/h min aliases */
|
||||
int c_wmin, c_hmin;
|
||||
int p_wmin_rel, p_hmin_rel;
|
||||
|
||||
c_wmin = child->surface->bounds->wmin;
|
||||
c_hmin = child->surface->bounds->hmin;
|
||||
|
||||
if (!additive) {
|
||||
c_wmin *= -1;
|
||||
c_hmin *= -1;
|
||||
}
|
||||
|
||||
if (child->surface->bounds->type == BOUND_RELATIVE) {
|
||||
parent->cbounds.wmin_abs++;
|
||||
parent->cbounds.hmin_abs++;
|
||||
|
||||
p_wmin_rel = parent->cbounds.wmin_rel + c_wmin;
|
||||
p_hmin_rel = parent->cbounds.hmin_rel + c_wmin;
|
||||
if (p_wmin_rel > __BOUND_REL_MAX || p_hmin_rel >= __BOUND_REL_MAX)
|
||||
return 1;
|
||||
|
||||
parent->cbounds.wmin_rel = p_wmin_rel;
|
||||
parent->cbounds.hmin_rel = p_hmin_rel;
|
||||
assert(parent->cbounds.wmin_rel >= __BOUND_REL_MIN);
|
||||
assert(parent->cbounds.hmin_rel >= __BOUND_REL_MIN);
|
||||
} else {
|
||||
parent->cbounds.wmin_abs += c_wmin;
|
||||
parent->cbounds.hmin_abs += c_hmin;
|
||||
assert(parent->cbounds.wmin_abs >= __BOUND_ABS_MIN);
|
||||
assert(parent->cbounds.hmin_abs >= __BOUND_ABS_MIN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (max child limit reached)
|
||||
* 2 -> failed (cumulative relative bounds surpasses 100%)
|
||||
*/
|
||||
int insert_child_node(struct ct_node *const parent, struct ct_node *const child,
|
||||
const cindex i) {
|
||||
if (parent->cindex == CINDEX_MAX)
|
||||
return 1;
|
||||
else if (__set_cbounds(parent, child, true))
|
||||
return 2;
|
||||
else if (parent->cindex == parent->csize) {
|
||||
// grow child array size and clamp maximum
|
||||
cindex new_csize = parent->csize * NODE_CHILDREN_GROWTH;
|
||||
// check overflow
|
||||
parent->csize = (parent->csize <= new_csize) ? new_csize : CINDEX_MAX;
|
||||
|
||||
parent->child =
|
||||
reallocarray(parent->child, parent->csize, sizeof(struct ct_node *));
|
||||
}
|
||||
|
||||
// shift all children up for insertion
|
||||
for (int j = parent->cindex; j > i; j--) {
|
||||
parent->child[j] = parent->child[j - 1];
|
||||
}
|
||||
// do insertion
|
||||
parent->child[i] = child;
|
||||
parent->cindex++;
|
||||
// request cursetree recompute dimensions recursively from parent
|
||||
parent->flags |= NFLAG_RESIZE;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (max child limit reached)
|
||||
* 2 -> failed (cumulative relative bounds surpasses 100%)
|
||||
*/
|
||||
int append_child_node(struct ct_node *const parent,
|
||||
struct ct_node *const child) {
|
||||
return insert_child_node(parent, child, parent->cindex);
|
||||
}
|
||||
|
||||
/* Remove a child node from a parent node by index.
|
||||
* Returns NULL if an invalid index was provided, otherwise returns
|
||||
* a pointer to the child node removed.
|
||||
* NOTE: This does NOT destroy the child node and should be
|
||||
* NOTE: used when moving the child somewhere else.
|
||||
* NOTE: Otherwise use destroy_child_node() instead.
|
||||
*/
|
||||
struct ct_node *remove_child_node(struct ct_node *const parent,
|
||||
const cindex i) {
|
||||
struct ct_node *child;
|
||||
|
||||
if (i >= parent->cindex)
|
||||
return NULL;
|
||||
else if (parent->cindex <= parent->csize / NODE_CHILDREN_GROWTH) {
|
||||
// shrink child array to avoid memory bloat
|
||||
parent->csize /= NODE_CHILDREN_GROWTH;
|
||||
parent->child =
|
||||
reallocarray(parent->child, parent->csize, sizeof(struct ct_node *));
|
||||
}
|
||||
|
||||
child = &parent[i];
|
||||
// shift all children down to fill removal
|
||||
for (int j = i; j < parent->cindex; j++) {
|
||||
parent->child[j] = parent->child[j + 1];
|
||||
}
|
||||
parent->cindex--;
|
||||
__set_cbounds(parent, child, false);
|
||||
// request cursetree recompute dimensions recursively from parent
|
||||
parent->flags |= NFLAG_RESIZE;
|
||||
return child;
|
||||
}
|
||||
|
||||
/* Remove and destroy a child node by index.
|
||||
* Returns 1 on failure (invalid index provided), and 0 on success.
|
||||
* NOTE: Use remove_child_node() instead if the child should live.
|
||||
*/
|
||||
int destroy_child_node(struct ct_node *const parent, const cindex i) {
|
||||
struct ct_node *child = remove_child_node(parent, i);
|
||||
__destroy_node(child);
|
||||
return (child == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (node has no parent)
|
||||
* 2 -> failed (parent has no reference to node, CRITICAL)
|
||||
*/
|
||||
static int __index_as_child(const struct ct_node *const node,
|
||||
int *const index) {
|
||||
if (node->parent == NULL)
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < node->parent->cindex; i++) {
|
||||
if (node->parent->child[i] == node) {
|
||||
*index = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* If preserve_bounds is set then upon collapse the new node maintains the
|
||||
* original node's bounds struct. Otherwise the bounds of the child collapsed
|
||||
* onto are used.
|
||||
*/
|
||||
void collapse_node(struct ct_node **const node, const int i,
|
||||
const bool preserve_bounds) {
|
||||
assert(0 <= i && i < (*node)->cindex);
|
||||
int parent_index;
|
||||
struct ct_node *const parent = (*node)->parent;
|
||||
struct ct_node *collapse_target = remove_child_node(*node, i);
|
||||
struct ct_dims *dims = dup_dims((*node)->surface->dims);
|
||||
struct ct_bounds *bounds;
|
||||
|
||||
if (preserve_bounds) {
|
||||
bounds = dup_bounds((*node)->surface->bounds);
|
||||
rebind_surface(collapse_target->surface, bounds);
|
||||
}
|
||||
|
||||
/* Destroy original node and point to the collapse_target */
|
||||
if (__index_as_child(*node, &parent_index)) {
|
||||
/* __index_as_child fails (typically) because
|
||||
* the *node is cursetree's root node. */
|
||||
__destroy_node(*node);
|
||||
*node = collapse_target;
|
||||
} else {
|
||||
destroy_child_node(parent, parent_index);
|
||||
insert_child_node(parent, collapse_target, parent_index);
|
||||
}
|
||||
|
||||
resize_node(collapse_target, dims);
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
#ifndef CURSETREE_NODE_H
|
||||
#define CURSETREE_NODE_H
|
||||
|
||||
#include "dims.h"
|
||||
#include "limits.h"
|
||||
#include "surface.h"
|
||||
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
#define NODE_INIT_CHILDREN 4
|
||||
#define NODE_CHILDREN_GROWTH 1.5
|
||||
#define CINDEX_MAX (UCHAR_MAX)
|
||||
|
||||
#define NFLAG_EMPTY (0)
|
||||
#define NFLAG_RESIZE (1 << 0)
|
||||
#define NFLAG_SMALL (1 << 1)
|
||||
#define NFLAG_SMALLCHILD (1 << 2)
|
||||
#define NFLAG_LARGE (1 << 3)
|
||||
|
||||
/* Child Index */
|
||||
typedef unsigned char cindex;
|
||||
|
||||
struct ct_node {
|
||||
struct ct_surface *surface;
|
||||
unsigned char flags;
|
||||
|
||||
struct ct_node *parent;
|
||||
enum ct_axis axis;
|
||||
struct ct_node **child;
|
||||
cindex csize, cindex;
|
||||
/* child imposed minimum bounds */
|
||||
struct {
|
||||
int wmin_abs;
|
||||
int hmin_abs;
|
||||
int wmin_rel;
|
||||
int hmin_rel;
|
||||
} cbounds;
|
||||
};
|
||||
|
||||
/* === External Interface === */
|
||||
#define IS_ROOT_NODE(node) (node->parent == NULL)
|
||||
#define IS_PARENT_NODE(node) (node->cindex != 0)
|
||||
|
||||
struct ct_node *__node(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent);
|
||||
struct ct_node *new_node(struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent);
|
||||
void __destroy_node(struct ct_node *const node);
|
||||
|
||||
int resize_node(struct ct_node *const node, struct ct_dims *dims);
|
||||
|
||||
int insert_child_node(struct ct_node *const parent, struct ct_node *const child,
|
||||
const cindex i);
|
||||
int append_child_node(struct ct_node *const parent,
|
||||
struct ct_node *const child);
|
||||
struct ct_node *remove_child_node(struct ct_node *const parent,
|
||||
const cindex i);
|
||||
int destroy_child_node(struct ct_node *const parent, const cindex i);
|
||||
|
||||
void collapse_node(struct ct_node **const node, const int i,
|
||||
const bool preserve_bounds);
|
||||
|
||||
#endif /* CURSETREE_NODE_H */
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#ifndef CURSETREE_EPTY_H
|
||||
#define CURSETREE_EPTY_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
pid_t forkepty(int *fdmx, int *fderr);
|
||||
|
||||
#endif /* CURSETREE_EPTY_H */
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "ncrswrap.h"
|
||||
#include "surface.h"
|
||||
#include "_ncurses.h"
|
||||
#include "ncurses.h"
|
||||
|
||||
static inline struct ct_surface *__surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
WINDOW *const win) {
|
||||
struct ct_surface *surface;
|
||||
|
||||
surface = (struct ct_surface *)malloc(sizeof(struct ct_surface));
|
||||
*surface = (struct ct_surface){
|
||||
.dims = dims,
|
||||
.bounds = bounds,
|
||||
.win = win,
|
||||
.updatereq = true,
|
||||
};
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
struct ct_surface *new_surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds) {
|
||||
WINDOW *const win = new_window(dims->x, dims->y, dims->width, dims->height);
|
||||
return __surface(dims, bounds, win);
|
||||
}
|
||||
|
||||
void destroy_surface(const struct ct_surface *const surface) {
|
||||
delwin(surface->win);
|
||||
free(surface->dims);
|
||||
}
|
||||
|
||||
void resize_surface(struct ct_surface *const surface,
|
||||
struct ct_dims *const dims) {
|
||||
free(surface->dims);
|
||||
surface->dims = dims;
|
||||
surface->updatereq = true;
|
||||
|
||||
resizemv_window(surface->win, dims->x, dims->y, dims->width, dims->height);
|
||||
}
|
||||
|
||||
void rebind_surface(struct ct_surface *const surface,
|
||||
struct ct_bounds *const bounds) {
|
||||
free(surface->bounds);
|
||||
surface->bounds = bounds;
|
||||
}
|
||||
|
||||
int sfwidth(const struct ct_surface *const surface) {
|
||||
return getmaxx(surface->win);
|
||||
}
|
||||
|
||||
int sfheight(const struct ct_surface *const surface) {
|
||||
return getmaxy(surface->win);
|
||||
}
|
||||
|
||||
int sfposx(const struct ct_surface *const surface) {
|
||||
return getbegx(surface->win);
|
||||
}
|
||||
|
||||
int sfposy(const struct ct_surface *const surface) {
|
||||
return getbegy(surface->win);
|
||||
}
|
||||
|
||||
struct ct_dims *sfdims(const struct ct_surface *const surface) {
|
||||
int x, y, width, height;
|
||||
sfpos(surface, x, y);
|
||||
sfsize(surface, width, height);
|
||||
return new_dims(x, y, width, height);
|
||||
}
|
||||
|
||||
void sfclear(struct ct_surface *const surface) {
|
||||
wclear(surface->win);
|
||||
surface->updatereq = true;
|
||||
}
|
||||
|
||||
void sfflush(struct ct_surface *const surface) {
|
||||
wnoutrefresh(surface->win);
|
||||
surface->updatereq = false;
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef CURSETREE_SURFACE_H
|
||||
#define CURSETREE_SURFACE_H
|
||||
|
||||
#include "dims.h"
|
||||
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
struct ct_surface {
|
||||
struct ct_dims *dims;
|
||||
struct ct_bounds *bounds;
|
||||
WINDOW *win;
|
||||
unsigned char updatereq;
|
||||
};
|
||||
|
||||
struct ct_surface *new_surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds);
|
||||
void destroy_surface(const struct ct_surface *const surface);
|
||||
|
||||
void resize_surface(struct ct_surface *const surface,
|
||||
struct ct_dims *const dims);
|
||||
void rebind_surface(struct ct_surface *const surface,
|
||||
struct ct_bounds *const bounds);
|
||||
|
||||
#define sfpos(surface, x, y) (x = sfposx(surface), y = sfposy(surface))
|
||||
#define sfsize(surface, width, height) (width = sfwidth(surface), height = sfheight(surface))
|
||||
|
||||
int sfwidth(const struct ct_surface *const surface);
|
||||
int sfheight(const struct ct_surface *const surface);
|
||||
int sfposx(const struct ct_surface *const surface);
|
||||
int sfposy(const struct ct_surface *const surface);
|
||||
struct ct_dims *sfdims(const struct ct_surface *const surface);
|
||||
|
||||
void sfclear(struct ct_surface *const surface);
|
||||
void sfflush(struct ct_surface *const surface);
|
||||
|
||||
#endif /* CURSETREE_SURFACE_H */
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "ncrswrap.h"
|
||||
#include "tree.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
static inline struct ct_node *__root_node(void) {
|
||||
return __node(termdims(), bounds_none(), NULL);
|
||||
}
|
||||
|
||||
int init_tree(struct ct_tree **const tree) {
|
||||
*tree = (struct ct_tree *)malloc(sizeof(struct ct_tree));
|
||||
(*tree)->root = __root_node();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_tree(struct ct_tree *const tree) {
|
||||
__destroy_node(tree->root);
|
||||
end_ncurses();
|
||||
free(tree);
|
||||
}
|
||||
|
||||
void resize_tree(struct ct_tree *const tree, struct ct_dims *const dims) {
|
||||
resize_node(tree->root, dims);
|
||||
}
|
||||
|
||||
void switch_nodes(struct ct_node **const node0, struct ct_node **const node1) {
|
||||
struct ct_node *const node0ptr = *node0;
|
||||
struct ct_dims *const node0dims = dup_dims((*node0)->surface->dims);
|
||||
struct ct_dims *const node1dims = dup_dims((*node1)->surface->dims);
|
||||
|
||||
*node0 = *node1;
|
||||
resize_node(*node0, node1dims);
|
||||
|
||||
*node1 = node0ptr;
|
||||
resize_node(*node1, node0dims);
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef CURSETREE_TREE_H
|
||||
#define CURSETREE_TREE_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
struct ct_tree {
|
||||
struct ct_node *root;
|
||||
};
|
||||
|
||||
/* === External Interface === */
|
||||
int init_tree(struct ct_tree **const tree);
|
||||
void destroy_tree(struct ct_tree *const tree);
|
||||
void resize_tree(struct ct_tree *const tree, struct ct_dims *const dims);
|
||||
|
||||
#endif /* CURSETREE_TREE_H */
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef CURSETREE_UTIL_H
|
||||
#define CURSETREE_UTIL_H
|
||||
|
||||
static inline int clampi(int val, int min, int max) {
|
||||
if (val > max)
|
||||
return max;
|
||||
else if (val < min)
|
||||
return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif /* CURSETREE_UTIL_H */
|
||||
22
scripts/test
22
scripts/test
|
|
@ -9,10 +9,16 @@ fi
|
|||
MODE=
|
||||
REBUILD=true
|
||||
VALGRIND=false
|
||||
TARGET=debug
|
||||
TARGET=all
|
||||
PROGRAM="$1"
|
||||
MODE_ARG="$2"
|
||||
|
||||
if [[ ! -x "$PROGRAM" ]]; then
|
||||
echo "[!] Invalid program: \"$PROGRAM\""
|
||||
echo "$USAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$MODE_ARG" =~ run.* ]]; then
|
||||
MODE="$MODE_ARG"
|
||||
REBUILD=false
|
||||
|
|
@ -20,7 +26,7 @@ fi
|
|||
if [[ "$MODE_ARG" =~ .*valgrind ]]; then
|
||||
MODE="$MODE_ARG"
|
||||
VALGRIND=true
|
||||
PROXY='valgrind -s --log-file=logs/valgrind.log --leak-check=full --show-leak-kinds=all'
|
||||
PROXY='valgrind -s --leak-check=full --show-leak-kinds=all'
|
||||
TARGET=debug
|
||||
fi
|
||||
|
||||
|
|
@ -33,16 +39,4 @@ fi
|
|||
if [[ "$REBUILD" == true ]]; then
|
||||
make clean $TARGET
|
||||
fi
|
||||
|
||||
if [[ ! -x "$PROGRAM" ]]; then
|
||||
echo "[!] Invalid program: \"$PROGRAM\""
|
||||
echo "$USAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p logs
|
||||
LD_LIBRARY_PATH=./lib $PROXY "$PROGRAM" $@
|
||||
|
||||
# If ncurses doesn't close gracefully, termios attributes
|
||||
# will require reinitialisation (not a reset! don't clear the screen!)
|
||||
tput init
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue