From 04e5688d823fd54df7043fef36d55e67717538b3 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:25:03 +1000 Subject: [PATCH 01/37] experimenting with pipewire api --- lib/main.c | 96 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/lib/main.c b/lib/main.c index a9a59dc..d875c8c 100644 --- a/lib/main.c +++ b/lib/main.c @@ -1,15 +1,16 @@ #include #include - #include #define M_PI_M2 (M_PI + M_PI) #define DEFAULT_RATE 44100 +#define DEFAULT_PERIOD 1.0 / DEFAULT_RATE + #define DEFAULT_CHANNELS 2 #define DEFAULT_VOLUME 0.7 -#define DEFAULT_FREQ 200 +#define DEFAULT_FREQ 500 #define DEFAULT_ACCUMULATOR -1 @@ -18,17 +19,72 @@ struct data { struct pw_main_loop *loop; struct pw_stream *stream; - double accumulator; - uint32_t cycle; + + /* + */ + double t, tcyc; // global time and cycle time + uint32_t frame, cycle; }; +#define NEW_DATA (struct data) \ + { \ + .t = 0, \ + .tcyc = 0, \ + .frame = 0, \ + .cycle = 0, \ + } + +typedef int16_t (*snd)(struct data*); + +inline void data_progress(struct data *state) { + state->t += DEFAULT_PERIOD / DEFAULT_FREQ; + state->tcyc += DEFAULT_PERIOD / DEFAULT_FREQ; + if (++state->frame == DEFAULT_FREQ) { + state->tcyc -= DEFAULT_PERIOD; + state->frame = 0; + state->cycle++; + } +} + +int16_t snd_sine(struct data *state) { + int16_t val; + + /* sin() gives a value between -1.0 and 1.0, we first apply + * the volume and then scale with 32767.0 to get a 16 bits value + * between [-32767 32767]. + * Another common method to convert a double to + * 16 bits is to multiple by 32768.0 and then clamp to + * [-32768 32767] to get the full 16 bits range. */ + val = sin(state->tcyc * M_PI_M2 * DEFAULT_FREQ) * 32767.0 * DEFAULT_VOLUME; + + return val; +} + +int graph_snd(snd f, struct data *state, double t_max, FILE *fstream) { + int16_t val; + if (fstream == NULL) + return 1; + + fputs("x, sin(x)\n", fstream); + while (state->t < t_max) { + val = f(state); + fprintf(fstream, "%f, %d\n", state->t, val); + data_progress(state); + } + + fclose(fstream); + return 0; +} + + /* [on_process] */ static void on_process(void *userdata) { struct data *data = userdata; struct pw_buffer *b; struct spa_buffer *buf; - int i, c, n_frames, stride; + int n_frames, stride; int16_t *dst, val; + int i, c; if ((b = pw_stream_dequeue_buffer(data->stream)) == NULL) { pw_log_warn("out of buffers: %m"); @@ -45,19 +101,7 @@ static void on_process(void *userdata) { n_frames = SPA_MIN(b->requested, n_frames); for (i = 0; i < n_frames; i++) { - // data->accumulator += M_PI_M2 * DEFAULT_FREQ / DEFAULT_RATE; // * 440 - if (data->accumulator++ == DEFAULT_RATE) { - data->accumulator = DEFAULT_ACCUMULATOR; - data->cycle++; - } - - /* sin() gives a value between -1.0 and 1.0, we first apply - * the volume and then scale with 32767.0 to get a 16 bits value - * between [-32767 32767]. - * Another common method to convert a double to - * 16 bits is to multiple by 32768.0 and then clamp to - * [-32768 32767] to get the full 16 bits range. */ - val = sin(data->accumulator * M_PI_M2 * DEFAULT_FREQ / DEFAULT_RATE) * DEFAULT_VOLUME * 32767.0; + val = snd_sine(data); for (c = 0; c < DEFAULT_CHANNELS; c++) *dst++ = val; } @@ -75,16 +119,20 @@ static const struct pw_stream_events stream_events = { .process = on_process, }; -int main(int argc, char *argv[]) { - struct data data = { - .accumulator = DEFAULT_ACCUMULATOR, - .cycle = 0, - }; +int main(int argc, char **argv) { + struct data data = NEW_DATA; const struct spa_pod *params[1]; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); - pw_init(&argc, &argv); + // DEBUG: check sine wave is actually a sine wave + FILE *fstream = fopen("sine.txt", "w"); + graph_snd(&snd_sine, &NEW_DATA, DEFAULT_PERIOD, fstream); + exit(69); + + int pw_argc = 0; + char **pw_argv = NULL; + pw_init(&pw_argc, &pw_argv); // pw_init(&argc, &argv); data.loop = pw_main_loop_new(NULL); From 342886a098683a054c4cd15283d07f7d0c448bf9 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:25:59 +1000 Subject: [PATCH 02/37] test custom curses implementation --- lib/cursed.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/cursed.h | 41 +++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 lib/cursed.c create mode 100644 lib/cursed.h diff --git a/lib/cursed.c b/lib/cursed.c new file mode 100644 index 0000000..49c17c6 --- /dev/null +++ b/lib/cursed.c @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include + +#include "cursed.h" +#include "termios.h" + +struct s_state *glstate; + +PRIVATE inline int termenable(struct s_state *st) { + struct termios term; + + // if (!st) + // return 1; + + if (ioctl(0, TCGETS, &term) == -1) + return 1; + memcpy(&st->term, &term, sizeof(struct termios)); + // control characters + // term.c_cc[VMIN] = 1; + // term.c_cc[VTIME] = 0; + // io flags + term.c_iflag &= ~(IXON | INPCK | ICRNL | ISTRIP | BRKINT); + term.c_oflag &= ~(OPOST); // disable post-processing (using \r\n manually now) + term.c_cflag |= (CS8); + // misc flags + term.c_lflag &= ~(ECHO | ICANON | IEXTEN); + if (ioctl(0, TCSETS, &term)) + return 1; + + // unbuffer stdin + // if (setvbuf(stdin, NULL, _IOLBF, 0)) + // return 1; + + return 0; +} + +PRIVATE inline int termdisable(struct s_state *st) { + if (!st) + return 1; + + if (ioctl(0, TCSETS, &st->term)) + return 1; + + return 0; +} + +PRIVATE struct s_framebuffer *init_framebuffer(pos cols, pos rows) { + unsigned long int fbsz, bmsz; // framebuf + bitmap sizes + struct s_framebuffer *buf; +} + +PRIVATE struct s_state *init_state(void) { + struct s_state *st = (struct s_state*)malloc(sizeof(struct s_state)); + if (st == NULL) exit(1); // BUG: WARNING: TODO + return st; +} + +PUBLIC _INIT void initlib(void) { + // atexit(destroylib) + glstate = init_state(); + termenable(glstate); + // (volatile void)init_window(glstate, 90, 25); +} + +PUBLIC _FINI void destroylib(void) { + // if (glstate != NULL) + termdisable(glstate); +} + + + +int main(int argc, char **argv) { + // TODO: use STDIN_FILENO instead for 0 + char c, s[10]; + int pad; + while (read(STDIN_FILENO, &c, 1) == 1) { + sprintf(s, "%d", c); + pad = 3 - strlen(s); // max is 256 (strlen 3) + + printf("0x%.02hhx %s", c, s); + if (!iscntrl(c)) { + for (int i=0; i < pad; i++) + putchar(' '); + printf(" (%c)", c); + } + printf("\r\n"); + } + + return EXIT_SUCCESS; +} diff --git a/lib/cursed.h b/lib/cursed.h new file mode 100644 index 0000000..439f51c --- /dev/null +++ b/lib/cursed.h @@ -0,0 +1,41 @@ +#ifndef CURSED_H +#define CURSED_H + +#include +#include + +#define PACKED __attribute__((packed, aligned(1))) +#define PUBLIC __attribute((visibility("default"))) +#define PROTECTED __attribute__((visibility("hidden"))) +#define PRIVATE static + +#define _INIT __attribute__((constructor)) +#define _FINI __attribute__((destructor)) + +typedef unsigned char uid; // >= 8B +typedef unsigned short int pos; // >= 16B + +struct s_framebuffer { + pos *buf; // framebuffer + bool bitmap[]; +} PACKED; + +struct s_window { + uid id; + pos cols; + pos rows; + struct s_framebuffer frame; + + pos x; + pos y; +} PACKED; + +struct s_state { + struct termios term; +} PACKED; + +// === Public API === +PRIVATE struct s_framebuffer *init_framebuffer(pos cols, pos rows); +PUBLIC struct s_window *init_window(uid id, pos cols, pos rows); + +#endif /* CURSED_H */ From 5a4f75c418de58a3f3f50c8f6cb54a6bcf3def3c Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:26:27 +1000 Subject: [PATCH 03/37] test standard ncurses graphing template --- lib/graph.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/graph.h | 6 ++++++ 2 files changed, 60 insertions(+) create mode 100644 lib/graph.c create mode 100644 lib/graph.h diff --git a/lib/graph.c b/lib/graph.c new file mode 100644 index 0000000..4924733 --- /dev/null +++ b/lib/graph.c @@ -0,0 +1,54 @@ +#include + +// void init_colors() { +// start_color(); +// init_pair(1, COLOR_GREEN, COLOR_BLACK); +// init_pair(2, COLOR_CYAN, COLOR_BLACK); +// init_pair(3, COLOR_MAGENTA, COLOR_BLACK); +// init_pair(4, COLOR_YELLOW, COLOR_BLACK); +// } + +// int main(void) { +// initscr(); +// printw("Goodbye World..."); +// refresh(); +// getch(); +// endwin(); + +// return 0; +// } + +int main(void) { + initscr(); + raw(); + // cbreak(); + // noecho(); + // echo(); + // curs_set(0); + keypad(stdscr, TRUE); // enable F1, F2, etc + noecho(); + // nodelay(stdscr, TRUE); + + // getmaxyx(stdscr, max_y, max_x); + // init_colors(); + printw("Type: "); + refresh(); + + int ch; + while (1) { + ch = getch(); + if (ch == KEY_F(1)) { + printw("[!] F1\n"); + break; + } + + attron(A_BOLD); + printw("%c", ch); + attroff(A_BOLD); + refresh(); + // napms(50); + } + + endwin(); + return 0; +} diff --git a/lib/graph.h b/lib/graph.h new file mode 100644 index 0000000..f72bbc6 --- /dev/null +++ b/lib/graph.h @@ -0,0 +1,6 @@ +#ifndef DORNE_GRAPH_H +#define DORNE_GRAPH_H + + + +#endif /* DORNE_GRAPH_H */ From 6eb51ef641bd97c7f1b79a0866d0cf92d1f03a6f Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:26:40 +1000 Subject: [PATCH 04/37] example sine ncurses tempalte --- lib/sine.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 lib/sine.c diff --git a/lib/sine.c b/lib/sine.c new file mode 100644 index 0000000..b0832ff --- /dev/null +++ b/lib/sine.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include + +#define DEFAULT_AMPLITUDE 1 +#define DEFAULT_PERIOD .35 +#define DEFAULT_DELAY_MULTIPLIER 150 +#define BASE_DELAY 100 + +// Color count +#define NUM_COLORS 6 + +typedef unsigned short ushort; + +ushort printwave(double amplitude, double period, short phase_shift, + ushort color_index) { + + double x; + for (x = 0.0; x < (COLS + phase_shift); x += 1.0) { + + // Swap color + color_index += 1; + attron(COLOR_PAIR((color_index % NUM_COLORS) + 1)); + + // Find Y + double ratio = (2.0 * M_PI) / LINES; + double y = sin(period * x * ratio); + y *= amplitude; + y += LINES / 2; + + // Print cell + mvprintw((int)(y), (int)(x - phase_shift), " "); + } + + return color_index; +} + +int main(int argc, char *argv[]) { + // Curses init + WINDOW *screen = initscr(); + start_color(); + nodelay(screen, 1); + cbreak(); + noecho(); + curs_set(0); + keypad(screen, TRUE); + + // Color pairs + init_pair(1, COLOR_RED, COLOR_BLACK); + init_pair(2, COLOR_GREEN, COLOR_BLACK); + init_pair(3, COLOR_YELLOW, COLOR_BLACK); + init_pair(4, COLOR_BLUE, COLOR_BLACK); + init_pair(5, COLOR_MAGENTA, COLOR_BLACK); + init_pair(6, COLOR_CYAN, COLOR_BLACK); + init_pair(7, COLOR_WHITE, COLOR_BLACK); + attron(A_BOLD); + attron(A_STANDOUT); + + // Wave attributes + unsigned char delayx = DEFAULT_DELAY_MULTIPLIER; + ushort color_index = 0; + short phase_shift = 0; + double amplitude = (LINES / 2) * DEFAULT_AMPLITUDE; + double period = DEFAULT_PERIOD; + + while (1) { + + erase(); + + color_index = printwave(amplitude, period, phase_shift, color_index); + + attron(COLOR_PAIR(7)); + mvprintw(0, 0, "PERIOD %.2f", period); + mvprintw(1, 0, "AMP: %.2f", amplitude); + mvprintw(2, 0, "PHASE: %d", phase_shift); + mvprintw(3, 0, "DELAY: x%hu", delayx); + + refresh(); + + switch (getch()) { + case KEY_UP: + case 'k': + amplitude += 1.0; + break; + case KEY_DOWN: + case 'j': + amplitude -= 1.0; + break; + case KEY_LEFT: + case 'h': + period -= .05; + break; + case KEY_RIGHT: + case 'l': + period += .05; + break; + case ' ': + phase_shift = 0.0; + break; + case '+': + delayx += 1; + break; + case '-': + delayx -= 1; + break; + case 'q': + endwin(); + return 0; + default: + break; + } + + usleep(BASE_DELAY * delayx); + + phase_shift += 1; + + if (phase_shift * period >= LINES) + phase_shift = 0; + } + + endwin(); + return 0; +} From 883361111c99c0951861d388bbd0fdf76344fcec Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:27:01 +1000 Subject: [PATCH 05/37] Make now builds graph and sine examples --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile b/Makefile index 1ec2c86..955aeab 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,14 @@ $(BIN)/pw-test: $(call mklib, main.c) $(CCOMPILER) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^ $(CLINKER) $(LDFLAGS) -o $@ $(BUILD)/pw-test.o +$(BIN)/graph: $(call mklib, graph.c) + $(CCOMPILER) $(CFLAGS) -o $(BUILD)/graph.o -c $^ + $(CLINKER) $(LDFLAGS) -lncurses -o $@ $(BUILD)/graph.o + +$(BIN)/sine: $(call mklib, sine.c) + $(CCOMPILER) $(CFLAGS) -o $(BUILD)/sine.o -c $^ + $(CLINKER) $(LDFLAGS) -lncurses -o $@ $(BUILD)/sine.o + $(BUILD) $(BIN): mkdir -p $@ From 492ec8832c239eda4bc3bf42b26934c3d0e26d2e Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 11:46:54 +1000 Subject: [PATCH 06/37] add TODO.md --- TODO.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..06dbe88 --- /dev/null +++ b/TODO.md @@ -0,0 +1,4 @@ +Use /dev/ptmx, to get ptmx (master) and pts (slave) file descriptors, +then fork and exec shfx as child (+ close ptmx), then close pts as parent. +>[!NOTE] +> Use `termios(3)` to enable raw mode (implemented in `cursed.c`) (for the slave or master?) From bd87f194f20872fcf1f584bac334065bf87b11ac Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 15:43:20 +1000 Subject: [PATCH 07/37] begin shfx (shell f(x)), graphing cli --- shfx/main.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 shfx/main.c diff --git a/shfx/main.c b/shfx/main.c new file mode 100644 index 0000000..a70bd04 --- /dev/null +++ b/shfx/main.c @@ -0,0 +1,44 @@ +#include +#include + +#include + +#define BASE_DELAY 1000000 + +int main(int argc, char *argv[]) { + // Curses init + WINDOW *screen = initscr(); + start_color(); + nodelay(screen, 1); + cbreak(); + noecho(); + curs_set(0); + keypad(screen, TRUE); + + // Color pairs + init_pair(1, COLOR_BLACK, COLOR_CYAN); + + // Set background + wbkgd(screen, 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; +} From c68fc6de5e2f0b9137d1838a3b01667c97ab0f44 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 15:43:54 +1000 Subject: [PATCH 08/37] add custom pty interface --- cli/main.c | 24 ++++++++++ cli/mkpty.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/mkpty.h | 14 ++++++ 3 files changed, 170 insertions(+) create mode 100644 cli/main.c create mode 100644 cli/mkpty.c create mode 100644 cli/mkpty.h diff --git a/cli/main.c b/cli/main.c new file mode 100644 index 0000000..86f4ffd --- /dev/null +++ b/cli/main.c @@ -0,0 +1,24 @@ +#include "mkpty.h" +#include "sys/types.h" + + +// 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) { + pid_t pid; + switch (pid = forkmkpty()) { + case -1: + break; + case 0: + default: + break; + } +} diff --git a/cli/mkpty.c b/cli/mkpty.c new file mode 100644 index 0000000..4344a85 --- /dev/null +++ b/cli/mkpty.c @@ -0,0 +1,132 @@ +/* _XOPEN_SOURCE unlocks pty/ptmx/pts declarations. */ +#define _XOPEN_SOURCE 600 +/* _GNU_SOURCE unlocks the ptsname_r declaration*/ +#define _GNU_SOURCE +#include +#include +#include +#include /* TIOC* constants */ +#include + +#ifdef PATH_MAX +# define SNAME_MAX PATH_MAX +#else +# define SNAME_MAX 512 +#endif /* PATH_MAX */ + +/* Allocate PTY master and slave file descriptors. + * errno will have been set if newpty() fails. + * + * NOTE: This function is my alternative to GLibC's + * openpty() function. It exists as a learning resource. + * REF: glibc.git:/login/openpty.c + */ +int mkpty(int *fdmx, int *fds) { + int _fdmx = -1, _fds = -1; + char sname[SNAME_MAX]; + + // Configure PTY master (file descriptor) + _fdmx = posix_openpt(O_RDWR | O_NOCTTY); + if (_fdmx == -1) + return EXIT_FAILURE; + + if (grantpt(_fdmx)) + goto fail; + if (unlockpt(_fdmx)) + goto fail; + +#ifdef TIOCGPTPEER + /* Try to allocate slave fd solely based on PTMX fd first. */ + _fds = ioctl(_fdmx, TIOCGPTPEER, O_RDWR | O_NOCTTY); +#endif + if (_fds == -1) { + /* Fallback to path-based slave fd allocation + * (if the kernel doesn't support TIOCGPTPEER, ie Linux <4.13) */ + if(ptsname_r(_fdmx, sname, sizeof(sname))) + goto fail; + + _fds = open(sname, O_RDWR | O_NOCTTY); + if (_fds == -1) + goto fail; + } + + // Propagate file descriptors via parameters + *fdmx = _fdmx; + *fds = _fds; + return EXIT_SUCCESS; + +fail: + if (_fdmx == -1) { + close(_fdmx); + if (_fds == -1) + close(_fds); + } + return EXIT_FAILURE; +} + +/* + */ +pid_t forkmkpty() { + int fdmx, fds; + pid_t pid; + if (mkpty(&fdmx, &fds)) + return EXIT_FAILURE; + + switch (pid = fork()) { + case -1: + close(fdmx); + close(fds); + return -1; + case 0: + /* Child Process */ + close(fdmx); + break; + + default: + /* Parent Process */ + close(fds); + break; + } + + /* Both Processes */ + return pid; +} + +/* Set pseudoterminal slave's window size. + * Returns 0 on success, and fails with -1 if the kernel doesn't + * implement this, or 1 for general errors (errno will be set). + * NOTE: Typically this is part of a glibc openpty() call. + */ +int setptsxy(const unsigned short rows, const unsigned short cols, const int fds) { +#ifndef TIOCSWINSZ + /* Fail if kernel doesn't support TIOCSWINSZ. */ + return -1; +#else + struct winsize win = { + .ws_row = rows, + .ws_col = cols, + }; + + if (ioctl(fds, TIOCSWINSZ, &win)) + return EXIT_FAILURE; + return EXIT_SUCCESS; +#endif /* TIOCSWINSZ */ +} + +/* Get pseudoterminal slave's window size. + * Returns 0 on success, and fails with -1 if the kernel doesn't + * implement this, or 1 for general errors (errno will be set). + */ +int getptsxy(unsigned short *rows, unsigned short *cols, const int fds) { +#ifndef TIOCGWINSZ + /* Fail if kernel doesn't support TIOCGWINSZ. */ + return -1; +#else + struct winsize win = (struct winsize){ 0 }; + if (ioctl(fds, TIOCGWINSZ, &win)) + return EXIT_FAILURE; + *rows = win.ws_row; + *cols = win.ws_col; + return EXIT_SUCCESS; +#endif /* TIOCGWINSZ */ +} diff --git a/cli/mkpty.h b/cli/mkpty.h new file mode 100644 index 0000000..ed0bce8 --- /dev/null +++ b/cli/mkpty.h @@ -0,0 +1,14 @@ +#ifndef DORNE_MKPTY_H +#define DORNE_MKPTY_H + +#include + +/* Custom implementations of openpty() */ +int mkpty(int *fdmx, int *fds); +/* Custom implementations of forkpty() */ +pid_t forkmkpty(); + +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 /* DORNE_MKPTY_H */ From c040219350c2d8283cd34717b87cdb72afe696e3 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 17:34:30 +1000 Subject: [PATCH 09/37] dorne GPLv3 license --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 8adc42aabc1398976bd1a6819a0059c6c39092fe Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 17:34:55 +1000 Subject: [PATCH 10/37] add glibc licenses (for next commit) --- LICENSES/GLIBC-COPYING | 339 +++++++++++++++++++++++++ LICENSES/GLIBC-COPYING.LIB | 502 +++++++++++++++++++++++++++++++++++++ LICENSES/README.md | 8 + LICENSES/UC-LICENSE | 24 ++ 4 files changed, 873 insertions(+) create mode 100644 LICENSES/GLIBC-COPYING create mode 100644 LICENSES/GLIBC-COPYING.LIB create mode 100644 LICENSES/README.md create mode 100644 LICENSES/UC-LICENSE diff --git a/LICENSES/GLIBC-COPYING b/LICENSES/GLIBC-COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSES/GLIBC-COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/LICENSES/GLIBC-COPYING.LIB b/LICENSES/GLIBC-COPYING.LIB new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/LICENSES/GLIBC-COPYING.LIB @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/LICENSES/README.md b/LICENSES/README.md new file mode 100644 index 0000000..71c5c5b --- /dev/null +++ b/LICENSES/README.md @@ -0,0 +1,8 @@ +## LICENSES +### Dorne +Dorne is licensed under the GPLv3 copyleft license [`LICENSE`](../LICENSE). + +### Modifications +Dorne makes use of modified functions from the GNU C Library which +are licensed under [`LICENSES/GLIBC-COPYING`](GLIBC-COPYING), +[`LICENSES/GLIBC-COPYING.LIB`](GLIBC-COPYING.LIB), and [`LICENSES/UC-LICENSE`](UC-LICENSE). diff --git a/LICENSES/UC-LICENSE b/LICENSES/UC-LICENSE new file mode 100644 index 0000000..217e97f --- /dev/null +++ b/LICENSES/UC-LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 1990, 1993 +The Regents of the University of California. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. From e599801f2e050531587ad075fce990cfc8912564 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 17:35:37 +1000 Subject: [PATCH 11/37] finish mkpty.c --- cli/mkpty.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/cli/mkpty.c b/cli/mkpty.c index 4344a85..1455f48 100644 --- a/cli/mkpty.c +++ b/cli/mkpty.c @@ -1,17 +1,30 @@ +/* WARNING: The mkpty(), forkmkpty(), & bindpty() functions are based on + * WARNING: the glibc openpty(), forkpty(), & login_tty() functions respectively. + * WARNING: + * WARNING: The GNU C Library's COPYING & COPYING.LIB licenses are available at + * WARNING: LICENSES/GLIBC-COPYING & LICENSES/GLIBC-COPYING.LIB in this repo. + * WARNING: + * WARNING: login_tty() maintains the original University of California license + * WARNING: available at LICENSES/UC-LICENSE in this repo. + */ + /* _XOPEN_SOURCE unlocks pty/ptmx/pts declarations. */ #define _XOPEN_SOURCE 600 /* _GNU_SOURCE unlocks the ptsname_r declaration*/ #define _GNU_SOURCE +#include #include #include #include #include /* TIOC* constants */ #include +#include "mkpty.h" + #ifdef PATH_MAX -# define SNAME_MAX PATH_MAX +# define TTYNAME_MAX PATH_MAX #else -# define SNAME_MAX 512 +# define TTYNAME_MAX 512 #endif /* PATH_MAX */ /* Allocate PTY master and slave file descriptors. @@ -19,11 +32,11 @@ * * NOTE: This function is my alternative to GLibC's * openpty() function. It exists as a learning resource. - * REF: glibc.git:/login/openpty.c + * REF: https://sourceware.org/git/glibc.git -> ./login/openpty.c */ int mkpty(int *fdmx, int *fds) { int _fdmx = -1, _fds = -1; - char sname[SNAME_MAX]; + char sname[TTYNAME_MAX]; // Configure PTY master (file descriptor) _fdmx = posix_openpt(O_RDWR | O_NOCTTY); @@ -64,7 +77,41 @@ fail: return EXIT_FAILURE; } -/* +/* Set fdty as the controlling terminal for the calling process. + * Returns 0 on success, and 1 on failure. + * NOTE: This function is my alternative to GLibC's + * login_tty() function. It exists as a learning resource. + * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c + * WARNING: This function maintains the original University of California + * WARNING: LICENSE (1990-1993) as per glibc.git:/login/login_tty.c + * WARNING: available at LICENSES/UC-LICENSE in this repo. + */ +int bindpty(const int fdty) { + /* We assume any kernel compiling this defines TIOCSCTTY, + * otherwise this implementation won't exactly work... + */ + if (ioctl(fdty, TIOCSCTTY, 0) == -1) + return EXIT_FAILURE; + + /* Adjust stdin/stdout/stderr to refer to fd*/ + while (dup2(fdty, STDIN_FILENO) == -1 && errno == EBUSY) + ; + while (dup2(fdty, STDOUT_FILENO) == -1 && errno == EBUSY) + ; + while (dup2(fdty, STDERR_FILENO) == -1 && errno == EBUSY) + ; + if (fdty > 2) + close(fdty); + + return EXIT_SUCCESS; +} + +/* Allocate a PTY and fork, binding the parent to ptmx (master), + * and the child to pts (slave). + * Return value is indentical to fork(2). + * NOTE: This function is my alternative to GLibC's + * forkpty() function. It exists as a learning resource. + * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c */ pid_t forkmkpty() { int fdmx, fds; @@ -80,6 +127,7 @@ pid_t forkmkpty() { case 0: /* Child Process */ close(fdmx); + bindpty(fds); break; default: @@ -107,7 +155,7 @@ int setptsxy(const unsigned short rows, const unsigned short cols, const int fds .ws_col = cols, }; - if (ioctl(fds, TIOCSWINSZ, &win)) + if (ioctl(fds, TIOCSWINSZ, &win) == -1) return EXIT_FAILURE; return EXIT_SUCCESS; #endif /* TIOCSWINSZ */ @@ -123,10 +171,11 @@ int getptsxy(unsigned short *rows, unsigned short *cols, const int fds) { return -1; #else struct winsize win = (struct winsize){ 0 }; - if (ioctl(fds, TIOCGWINSZ, &win)) + if (ioctl(fds, TIOCGWINSZ, &win) == -1) return EXIT_FAILURE; *rows = win.ws_row; *cols = win.ws_col; return EXIT_SUCCESS; #endif /* TIOCGWINSZ */ } + From a1e34376de01377fc8484ab2e7d8d7acf86bff09 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 19:42:41 +1000 Subject: [PATCH 12/37] begin removing Makefile boilerplate --- Makefile | 26 +++++++++++++++----------- config.mk | 8 ++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 955aeab..2e2a0d9 100644 --- a/Makefile +++ b/Makefile @@ -19,28 +19,32 @@ $(addprefix $(LIB)/,$1) endef # === BUILD TARGETS === -all: $(BUILD) $(BIN) $(call mkbin,pw-test graph sine) +all: $(BUILD) $(BIN) $(call mkbin,pw-test graph sine shfx cli) $(BIN)/pw-test: $(call mklib, main.c) - $(CCOMPILER) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^ - $(CLINKER) $(LDFLAGS) -o $@ $(BUILD)/pw-test.o + $(CC) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^ + $(CLD) $(CLDFLAGS) -o $@ $(BUILD)/pw-test.o -$(BIN)/graph: $(call mklib, graph.c) - $(CCOMPILER) $(CFLAGS) -o $(BUILD)/graph.o -c $^ - $(CLINKER) $(LDFLAGS) -lncurses -o $@ $(BUILD)/graph.o - -$(BIN)/sine: $(call mklib, sine.c) - $(CCOMPILER) $(CFLAGS) -o $(BUILD)/sine.o -c $^ - $(CLINKER) $(LDFLAGS) -lncurses -o $@ $(BUILD)/sine.o +$(BIN)/shfx: shfx/main.c + $(CC) $(CFLAGS) -o $(BUILD)/shfx.o -c $^ + $(CLD) $(CLDFLAGS) -lncurses -o $@ $(BUILD)/shfx.o + +$(BIN)/cli: cli/main.c cli/mkpty.c + $(CLD) $(CLDFLAGS) -o $@ $(BUILD)/cli.o $(BUILD) $(BIN): mkdir -p $@ +$1/%.o: $1/%.c + $(foreach dep, $^, + $(CC) $(CFLAGS) -o "$(BUILD)/$(basename $(notdir dep)).o" -c $(dep)) + $(LD) $(LDFLAGS) -o $@ $(addsuffix .o,$(basename $^)) + # === DEVELOPMENT TARGETS === .PHONY: debug run test debug: $(MAKE) all \ CFLAGS="$(CFLAGS) $(CFLAGS_DBG)" \ - LDFLAGS="$(LDFLAGS) $(LDFLAGS_DBG)" + CLDFLAGS="$(CLDFLAGS) $(CLDFLAGS_DBG)" run: debug - command $(BIN)/pw-test test: clean run diff --git a/config.mk b/config.mk index ff83c13..b355192 100644 --- a/config.mk +++ b/config.mk @@ -1,13 +1,13 @@ # === C Compiler Configuration === CC := gcc -# CCOMPILER = $$([ -x "$$(command -v bear)" ] && echo 'bear -- ') $(CC) -CCOMPILER = $(CC) CFLAGS := -Wall -Wextra -std=gnu23 -O CFLAGS_DBG := -g # === C Linker Configuration === -CLINKER = $(CC) -LDFLAGS := -lpipewire-0.3 -lm -lc +LD := ld +CLD = $(CC) +LDFLAGS := +CLDFLAGS := -lpipewire-0.3 -lm -lc LDFLAGS_DBG := -g # # === Nix Mutations === From 2893caf8ab0b8428e0b19f15b8e838368e6bcc07 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 19:43:54 +1000 Subject: [PATCH 13/37] fix mkpty function declarations --- cli/main.c | 10 ++++++++-- cli/mkpty.c | 2 +- cli/mkpty.h | 8 +++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cli/main.c b/cli/main.c index 86f4ffd..e2d4986 100644 --- a/cli/main.c +++ b/cli/main.c @@ -1,6 +1,7 @@ -#include "mkpty.h" -#include "sys/types.h" +#include +#include +#include "mkpty.h" // struct d_window { // int ptmx; // fd @@ -16,9 +17,14 @@ int main(int argc, char **argv) { pid_t pid; switch (pid = forkmkpty()) { case -1: + perror("forkmkpty"); break; case 0: + printf("fork: children\n"); + break; default: + printf("fork: parent\n"); break; } + return EXIT_SUCCESS; } diff --git a/cli/mkpty.c b/cli/mkpty.c index 1455f48..4cda39c 100644 --- a/cli/mkpty.c +++ b/cli/mkpty.c @@ -113,7 +113,7 @@ int bindpty(const int fdty) { * forkpty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c */ -pid_t forkmkpty() { +pid_t forkmkpty(void) { int fdmx, fds; pid_t pid; if (mkpty(&fdmx, &fds)) diff --git a/cli/mkpty.h b/cli/mkpty.h index ed0bce8..a62a27a 100644 --- a/cli/mkpty.h +++ b/cli/mkpty.h @@ -3,10 +3,12 @@ #include -/* Custom implementations of openpty() */ +/* Custom implementation of glibc::openpty() */ int mkpty(int *fdmx, int *fds); -/* Custom implementations of forkpty() */ -pid_t forkmkpty(); +/* Custom implementation of glibc::login_tty() */ +int bindpty(const int fdty); +/* Custom implementation of glibc::forkpty() */ +pid_t forkmkpty(void); int setptsxy(const unsigned short rows, const unsigned short cols, const int fds); int getptsxy(unsigned short *rows, unsigned short *cols, const int fds); From d04f14c038548503c8c61bcb55d2f9f2e647a965 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 21:03:40 +1000 Subject: [PATCH 14/37] reformat and refactor mkpty.* --- cli/mkpty.c | 62 +++++++++++++++++++++++++---------------------------- cli/mkpty.h | 20 ++++++++++++++--- 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/cli/mkpty.c b/cli/mkpty.c index 4cda39c..dd845b4 100644 --- a/cli/mkpty.c +++ b/cli/mkpty.c @@ -12,26 +12,18 @@ #define _XOPEN_SOURCE 600 /* _GNU_SOURCE unlocks the ptsname_r declaration*/ #define _GNU_SOURCE -#include #include #include -#include #include /* TIOC* constants */ #include #include "mkpty.h" -#ifdef PATH_MAX -# define TTYNAME_MAX PATH_MAX -#else -# define TTYNAME_MAX 512 -#endif /* PATH_MAX */ - /* Allocate PTY master and slave file descriptors. * errno will have been set if newpty() fails. * * NOTE: This function is my alternative to GLibC's - * openpty() function. It exists as a learning resource. + * NOTE: openpty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/openpty.c */ int mkpty(int *fdmx, int *fds) { @@ -80,59 +72,63 @@ fail: /* Set fdty as the controlling terminal for the calling process. * Returns 0 on success, and 1 on failure. * NOTE: This function is my alternative to GLibC's - * login_tty() function. It exists as a learning resource. + * NOTE: login_tty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c + */ +inline int setctty(const int fdty) { + /* We assume any kernel compiling this defines TIOCSCTTY, + * otherwise this implementation won't exactly work... */ + return (ioctl(fdty, TIOCSCTTY, 0) != -1); +} + +/* Bind fdty (terminal fd) to stdin/stdout/stderr for the calling process. + * This functions blocks until the EBUSY (see `man dup2`) race condition lifts. + * NOTE: This function is my alternative to GLibC's + * NOTE: login_tty() function. It exists as a learning resource. * WARNING: This function maintains the original University of California * WARNING: LICENSE (1990-1993) as per glibc.git:/login/login_tty.c * WARNING: available at LICENSES/UC-LICENSE in this repo. + * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c */ -int bindpty(const int fdty) { - /* We assume any kernel compiling this defines TIOCSCTTY, - * otherwise this implementation won't exactly work... - */ - if (ioctl(fdty, TIOCSCTTY, 0) == -1) - return EXIT_FAILURE; - +inline void bindpty(const int fdty) { /* Adjust stdin/stdout/stderr to refer to fd*/ - while (dup2(fdty, STDIN_FILENO) == -1 && errno == EBUSY) - ; - while (dup2(fdty, STDOUT_FILENO) == -1 && errno == EBUSY) - ; - while (dup2(fdty, STDERR_FILENO) == -1 && errno == EBUSY) - ; + BIND(fdty, STDIN_FILENO); + BIND(fdty, STDOUT_FILENO); + BIND(fdty, STDERR_FILENO); if (fdty > 2) close(fdty); - - return EXIT_SUCCESS; } -/* Allocate a PTY and fork, binding the parent to ptmx (master), - * and the child to pts (slave). +/* Allocate a PTY and fork, giving ptmx (master) to the parent + * and binding the child's stdin/stdout/stderr to pts (slave). * Return value is indentical to fork(2). * NOTE: This function is my alternative to GLibC's - * forkpty() function. It exists as a learning resource. + * NOTE: forkpty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c */ -pid_t forkmkpty(void) { - int fdmx, fds; +pid_t forkmkpty(int *fdmx) { + int _fdmx, fds; pid_t pid; - if (mkpty(&fdmx, &fds)) + if (mkpty(&_fdmx, &fds)) return EXIT_FAILURE; switch (pid = fork()) { case -1: - close(fdmx); + close(_fdmx); close(fds); return -1; case 0: /* Child Process */ - close(fdmx); + close(_fdmx); + setctty(fds); bindpty(fds); break; default: /* Parent Process */ close(fds); + // propagate ptmx (master) fd + *fdmx = _fdmx; break; } diff --git a/cli/mkpty.h b/cli/mkpty.h index a62a27a..3c80b95 100644 --- a/cli/mkpty.h +++ b/cli/mkpty.h @@ -1,16 +1,30 @@ #ifndef DORNE_MKPTY_H #define DORNE_MKPTY_H +#include +#include #include +#include + +#ifdef PATH_MAX +#define TTYNAME_MAX PATH_MAX +#else +#define TTYNAME_MAX 512 +#endif /* PATH_MAX */ + +#define BIND(fdsrc, fddst) \ + while (dup2(fdsrc, fddst) == -1 && errno == EBUSY) \ + ; /* Custom implementation of glibc::openpty() */ int mkpty(int *fdmx, int *fds); /* Custom implementation of glibc::login_tty() */ -int bindpty(const int fdty); +void bindpty(const int fdty); /* Custom implementation of glibc::forkpty() */ -pid_t forkmkpty(void); +pid_t forkmkpty(int *fdmx); -int setptsxy(const unsigned short rows, const unsigned short cols, const int fds); +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 /* DORNE_MKPTY_H */ From ac590806bfcfa25c91a512412cd63bde89294bc1 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 21:05:42 +1000 Subject: [PATCH 15/37] rename mkpty.* -> _pty.* --- cli/{mkpty.c => _pty.c} | 2 +- cli/{mkpty.h => _pty.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cli/{mkpty.c => _pty.c} (99%) rename cli/{mkpty.h => _pty.h} (100%) diff --git a/cli/mkpty.c b/cli/_pty.c similarity index 99% rename from cli/mkpty.c rename to cli/_pty.c index dd845b4..60509e8 100644 --- a/cli/mkpty.c +++ b/cli/_pty.c @@ -17,7 +17,7 @@ #include /* TIOC* constants */ #include -#include "mkpty.h" +#include "_pty.h" /* Allocate PTY master and slave file descriptors. * errno will have been set if newpty() fails. diff --git a/cli/mkpty.h b/cli/_pty.h similarity index 100% rename from cli/mkpty.h rename to cli/_pty.h From b2f204a2cb8ca9608e2c21be3ef1c7e10fcf41f3 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Tue, 9 Sep 2025 21:07:34 +1000 Subject: [PATCH 16/37] add epty.* to extend _pty.* stdout/stderr independence for child process --- cli/epty.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ cli/epty.h | 8 ++++++++ 2 files changed, 53 insertions(+) create mode 100644 cli/epty.c create mode 100644 cli/epty.h diff --git a/cli/epty.c b/cli/epty.c new file mode 100644 index 0000000..85182e4 --- /dev/null +++ b/cli/epty.c @@ -0,0 +1,45 @@ +#include + +#include "mkpty.h" + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +/* Allocate a PTY and fork, giving fdmx (master) to the parent + * and binding the child's stdin/stdout to fds (slave). + * Return value is indentical to fork(2). + * NOTE: This function is my alternative to GLibC's + * NOTE: forkpty() function. It exists as a learning resource. + * REF: https://sourceware.org/git/glibc.git -> ./login/forkpty.c + */ +pid_t forkepty(int *fdmx, int *fderr) { + // master/slave, and stderr pipe fds + int epipe[2]; + pid_t pid; + + if (pipe(epipe) == -1) + return EXIT_FAILURE; + switch (pid = forkmkpty(fdmx)) { + case -1: + /* forkmkpty() will close fdmx/fds for us */ + close(epipe[PIPE_READ]); + close(epipe[PIPE_WRITE]); + return -1; + case 0: + /* Child Process */ + /* forkmkpty() will close fdmx for us */ + close(epipe[PIPE_READ]); + BIND(epipe[PIPE_WRITE], STDERR_FILENO); + break; + + default: + /* Parent Process */ + /* forkmkpty() will close fds for us */ + close(epipe[PIPE_WRITE]); + *fderr = epipe[PIPE_READ]; + break; + } + + /* Both Processes */ + return pid; +} diff --git a/cli/epty.h b/cli/epty.h new file mode 100644 index 0000000..8dd18e4 --- /dev/null +++ b/cli/epty.h @@ -0,0 +1,8 @@ +#ifndef DORNE_EPTY_H +#define DORNE_EPTY_H + +#include + +pid_t forkepty(int *fdmx, int *fderr); + +#endif /* DORNE_EPTY_H */ From 3f9b404012f516f984b41a7c269362d50eda136a Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 01:23:38 +1000 Subject: [PATCH 17/37] simplify Makefile using macros --- Makefile | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 2e2a0d9..a755c16 100644 --- a/Makefile +++ b/Makefile @@ -5,22 +5,27 @@ include config.mk # === BUILD ENVIRONMENT === BIN := bin BUILD := build -LIB := lib -# Macro definitions -define mkbin -$(addprefix $(BIN)/,$1) +LIB := lib +CLI := cli + +# === MACRO DEFINITIONS === +define objpath +$(addprefix $(BUILD)/, + $(addsuffix .o, + $(basename $(1)))) endef -define mkbuild -$(addprefix $(BUILD)/,$1) -endef -define mklib -$(addprefix $(LIB)/,$1) +define mkobj +$(foreach DEP, $?, + mkdir -p $(dir $(call objpath, $(DEP))) + $(CC) $(CFLAGS) -o $(call objpath, $(DEP)) -c $(DEP)) + +$(LD) -r $(LDFLAGS) -o $@ $(call objpath, $?) endef # === BUILD TARGETS === -all: $(BUILD) $(BIN) $(call mkbin,pw-test graph sine shfx cli) -$(BIN)/pw-test: $(call mklib, main.c) +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) -o $@ $(BUILD)/pw-test.o @@ -28,16 +33,18 @@ $(BIN)/shfx: shfx/main.c $(CC) $(CFLAGS) -o $(BUILD)/shfx.o -c $^ $(CLD) $(CLDFLAGS) -lncurses -o $@ $(BUILD)/shfx.o -$(BIN)/cli: cli/main.c cli/mkpty.c - $(CLD) $(CLDFLAGS) -o $@ $(BUILD)/cli.o +$(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o epty.o) + $(CLD) $(CLDFLAGS) -o $@ $^ $(BUILD) $(BIN): mkdir -p $@ -$1/%.o: $1/%.c - $(foreach dep, $^, - $(CC) $(CFLAGS) -o "$(BUILD)/$(basename $(notdir dep)).o" -c $(dep)) - $(LD) $(LDFLAGS) -o $@ $(addsuffix .o,$(basename $^)) +$(BUILD)/dorne.o: $(addprefix $(CLI)/, main.c) + $(mkobj) +$(BUILD)/epty.o: $(addprefix $(CLI)/, epty.c _pty.c) + $(mkobj) + +# $1/%.o: $1/%.c # === DEVELOPMENT TARGETS === .PHONY: debug run test From 8991d8ec04327b43c8cf07573d1c502cb883058e Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 01:24:41 +1000 Subject: [PATCH 18/37] fix epty includes mkpty.h not _pty.h --- cli/epty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/epty.c b/cli/epty.c index 85182e4..050a2d7 100644 --- a/cli/epty.c +++ b/cli/epty.c @@ -1,6 +1,6 @@ #include -#include "mkpty.h" +#include "_pty.h" #define PIPE_READ 0 #define PIPE_WRITE 1 From 2e10e885045317e553d27e8e630e6518a669c9aa Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 01:25:08 +1000 Subject: [PATCH 19/37] begin simple child process interface --- cli/child.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/child.h | 14 ++++++++++++ cli/main.c | 19 +++++----------- 3 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 cli/child.c create mode 100644 cli/child.h diff --git a/cli/child.c b/cli/child.c new file mode 100644 index 0000000..6fe3313 --- /dev/null +++ b/cli/child.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include + +#include "child.h" +#include "epty.h" + +/* SIGTERM grace period before a child is sent SIGKILL. + * Value is in microseconds (us), 1000us = 1ms */ +#define CHILD_GRACE_US 100000 + +/* Check if a child is still alive by pid + * by kill(3p) sending a null signal (0). + */ +static int is_alive(struct d_child *child) { + return (kill(child->pid, 0) == 0); +} + +/* Force a child to die, first by sending SIGTERM, otherwise SIGKILL. + * NOTE: killchild() ASSUMES the child is LIVING at the start. + * NOTE: Keep this in mind when threading! + */ +void killchild(struct d_child *child) { + int stat; + + /* Request Death */ + kill(child->pid, SIGTERM); + usleep(CHILD_GRACE_US); + + /* Force Death */ + if (is_alive(child)) + kill(child->pid, SIGKILL); + + /* Reap */ + waitpid(child->pid, &stat, 0); +} + +/* Fork to spawn a child process running bin/shfx in an "epty". + */ +int spawnchild(struct d_child *child) { + *child = (struct d_child){ 0 }; + + /* fork(2) and allocate an "error-piped pseudoterminal" (epty) */ + switch (child->pid = forkepty(&child->fdmx, &child->fderr)) { + case -1: + perror("forkepty"); + return EXIT_FAILURE; + case 0: + char *args[] = {"shfx", NULL}; + execvp("shfx", args); + perror("execvp"); + exit(1); + default: + usleep(1000); + char bufout[10]; + bufout[9] = '\0'; + read(child->fdmx, bufout, 9); + printf("child stdout: \"%s\"\n", bufout); + break; + } + return EXIT_SUCCESS; +} diff --git a/cli/child.h b/cli/child.h new file mode 100644 index 0000000..6ec3978 --- /dev/null +++ b/cli/child.h @@ -0,0 +1,14 @@ +#ifndef DORNE_CHILD_H +#define DORNE_CHILD_H + +#include + +struct d_child { + pid_t pid; + int fdmx; /* PTY master fd (read/write) */ + int fderr; /* child's stderr (readonly) */ +} __attribute__((packed, aligned(4))); + +int spawnchild(struct d_child *child); + +#endif /* DORNE_CHILD_H */ diff --git a/cli/main.c b/cli/main.c index e2d4986..af57f88 100644 --- a/cli/main.c +++ b/cli/main.c @@ -1,7 +1,8 @@ -#include +#include #include +#include -#include "mkpty.h" +#include "child.h" // struct d_window { // int ptmx; // fd @@ -14,17 +15,7 @@ // } int main(int argc, char **argv) { - pid_t pid; - switch (pid = forkmkpty()) { - case -1: - perror("forkmkpty"); - break; - case 0: - printf("fork: children\n"); - break; - default: - printf("fork: parent\n"); - break; - } + struct d_child child; + spawnchild(&child); return EXIT_SUCCESS; } From c1e28f2f2e4fe96639ff592e8bcb1b9b81b0d1c1 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 01:25:52 +1000 Subject: [PATCH 20/37] add child related TODO items --- TODO.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 06dbe88..f3b7d7f 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,8 @@ -Use /dev/ptmx, to get ptmx (master) and pts (slave) file descriptors, +- [X] Use /dev/ptmx, to get ptmx (master) and pts (slave) file descriptors, then fork and exec shfx as child (+ close ptmx), then close pts as parent. >[!NOTE] > Use `termios(3)` to enable raw mode (implemented in `cursed.c`) (for the slave or master?) + +- [ ] Implement a SIGCHLD handler instead of using `waitpid` in `killchild()`, see 2nd example in `man wait(3p)` +- [ ] Use threads to launch `killchild` to avoid blocking, then just join all the threads using atexit() + From 361d63be94366c63e8792702e8086c024ec94be5 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 22:47:59 +1000 Subject: [PATCH 21/37] TODO.md --with-pthread question --- TODO.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.md b/TODO.md index f3b7d7f..36d892f 100644 --- a/TODO.md +++ b/TODO.md @@ -6,3 +6,7 @@ then fork and exec shfx as child (+ close ptmx), then close pts as parent. - [ ] Implement a SIGCHLD handler instead of using `waitpid` in `killchild()`, see 2nd example in `man wait(3p)` - [ ] Use threads to launch `killchild` to avoid blocking, then just join all the threads using atexit() +- [ ] Should I compile ncurses with --with-pthread? (see `man 3x ncurses`) + What about --enable-widec? (are these just ligatures?) + + From c3074a75eb7825f4b77c5dbcfd40e8d89084ca2b Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 22:49:05 +1000 Subject: [PATCH 22/37] add ncurses wrapper --- cli/_pty.c | 2 +- cli/curse.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/curse.h | 21 +++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 cli/curse.c create mode 100644 cli/curse.h diff --git a/cli/_pty.c b/cli/_pty.c index 60509e8..0fdd9d2 100644 --- a/cli/_pty.c +++ b/cli/_pty.c @@ -55,7 +55,7 @@ int mkpty(int *fdmx, int *fds) { goto fail; } - // Propagate file descriptors via parameters + /* Propagate file descriptors via parameters */ *fdmx = _fdmx; *fds = _fds; return EXIT_SUCCESS; diff --git a/cli/curse.c b/cli/curse.c new file mode 100644 index 0000000..bc5a1c9 --- /dev/null +++ b/cli/curse.c @@ -0,0 +1,77 @@ +#include +#include + +#include "curse.h" + +#define BASE_DELAY 1000000 +#define CRS_LOCALE "en_US.UTF-8" + +/* Set ncurses terminal mode (buffering, character processing, + * Key->SIG handling, and other termios(3) functionality). + */ +inline int termmode(enum crs_mode mode) { + switch (mode) { + case WMODE_CBREAK: + return cbreak(); + case WMODE_RAW: + return raw(); + case WMODE_NOCBREAK: + return nocbreak(); + case WMODE_NORAW: + return noraw(); + /* defaulting is not possible. */ + } +} + +/* Initialise ncurses for our usecase. + * WARNING: This function should only be called once. + */ +inline void init_ncurses(void) { + // ncurses expects a locale for consistent behaviour + setlocale(LC_ALL, CRS_LOCALE); + + /* NCurses Init */ + *stdscr = initscr(); + start_color(); + + /* Screen Configuration */ + termmode(WMODE_CBREAK); + noecho(); // manually echo <- getch(3x) + nodelay(*stdscr, TRUE); // getch(3x) nonblocking IO + keypad(*stdscr, TRUE); // allow function keys + // intrflush(3x) - flush terminal input buffer on interrupt key + intrflush(*stdscr, FALSE); + + curs_set(0); // hide cursor + + // init_pair(1, COLOR_BLACK, COLOR_CYAN); +} + +int main(int argc, char *argv[]) { + WINDOW *stdscr; + crs_init(&stdscr); + + // 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; +} diff --git a/cli/curse.h b/cli/curse.h new file mode 100644 index 0000000..8234a9a --- /dev/null +++ b/cli/curse.h @@ -0,0 +1,21 @@ +#ifndef DORNE_CURSE_H +#define DORNE_CURSE_H + +/* libncurses with wide-character support. */ +#include + +enum crs_mode { + /* tty cbreak mode */ + WMODE_CBREAK, + /* tty raw mode */ + WMODE_RAW, + /* tty cooked mode (ISIG & IXON not modified)*/ + WMODE_NOCBREAK, + /* tty cooked mode (ISIG & IXON set) */ + WMODE_NORAW, +}; + +int termmode(enum crs_mode mode); +void init_ncurses(void); + +#endif /* DORNE_CURSE_H */ From 79272e8421ad9a8a8f32ef90441bebeaf3f66904 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 22:49:24 +1000 Subject: [PATCH 23/37] structure dorne cli as a binary tree --- cli/tree.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cli/tree.h | 58 +++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 cli/tree.c create mode 100644 cli/tree.h diff --git a/cli/tree.c b/cli/tree.c new file mode 100644 index 0000000..04922e6 --- /dev/null +++ b/cli/tree.c @@ -0,0 +1,116 @@ +#include +#include + +#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_node_window(WINDOW *win) { + struct crs_node *node = __alloc_node(NODE_WINDOW); + node->win = win; + + return node; +} + +static struct crs_node *init_node_abstract(struct crs_node *node1, + struct crs_node *node2, + float ratio) { + struct crs_node *node = __alloc_node(NODE_ABSTRACT); + node->ratio = ratio; + + node->child[0] = node1; + node->child[1] = node2; + return node; +} + +static void destroy_node(struct crs_node *node) { + if (node->type == NODE_WINDOW) { + /* Window Node */ + delwin(node->win); + goto end; + } + /* Abstract Node */ + destroy_node(node->child[0]); + destroy_node(node->child[1]); + +end: + free(node); +} + +/* 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 - invert index of the original node in the new abstract node + */ +static void bifurcate_window_node(struct crs_node **node, enum crs_axis axis, + int invert, float ratio) { + assert((*node)->type == NODE_ABSTRACT); + + struct crs_node *original_node = *node; + struct crs_node *bi_node = init_node_window(); // WARNING: TODO + + if (!invert) { + /* Inverted Bifurcation */ + *node = init_node_abstract(bi_node, original_node, ratio); + } else { + /* Non-Inverted Bifurcation */ + *node = init_node_abstract(original_node, bi_node, ratio); + } + + resize_abstract_node(*node); +} + +/* 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) { + WINDOW *rootwin = newwin(0, 0, 0, 0); + return init_node_window(rootwin); +} + +int init_tree(struct crs_tree **tree) { + *tree = (struct crs_tree *)malloc(sizeof(struct crs_tree)); + + /* Initialise NCurses Library & Standard Screen */ + crs_init(&(*tree)->stdscr); + + /* */ + (*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 *tree) { + /* WARNING: is it ok to delwin(stdscr) ?? */ + destroy_node(tree->root); + + endwin(); +} diff --git a/cli/tree.h b/cli/tree.h new file mode 100644 index 0000000..d5ba171 --- /dev/null +++ b/cli/tree.h @@ -0,0 +1,58 @@ +#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: + * void NODEDIMS(struct crs_node *node, struct crs_nodedims dims); + */ +#define NODEDIMS(node, dims) (getbegyx(dims.y, dims.x); getmaxyx(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 { + float ratio; + struct crs_node *child[NODE_CHILD_N]; + }; + }; +}; + +struct crs_tree { + WINDOW *stdscr; + struct crs_node *root; +}; + +/* === External Interface === */ +// struct crs_node *init_node_window(void); +// struct crs_node *init_node_abstract(void); +// void destroy_node(struct crs_node *node); + +int init_tree(struct crs_tree **tree); +void update_tree(struct crs_tree *tree); +void destroy_tree(struct crs_tree *tree); + +#endif /* DORNE_TREE_H */ From a55c25d3196337274629803456be948b91d073f1 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 22:54:20 +1000 Subject: [PATCH 24/37] separate initscr(3x) wrapper to new function --- cli/curse.c | 20 +++++++++++++------- cli/curse.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cli/curse.c b/cli/curse.c index bc5a1c9..f2eda88 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -31,25 +31,31 @@ inline void init_ncurses(void) { setlocale(LC_ALL, CRS_LOCALE); /* NCurses Init */ - *stdscr = initscr(); start_color(); /* Screen Configuration */ termmode(WMODE_CBREAK); noecho(); // manually echo <- getch(3x) - nodelay(*stdscr, TRUE); // getch(3x) nonblocking IO - keypad(*stdscr, TRUE); // allow function keys - // intrflush(3x) - flush terminal input buffer on interrupt key - intrflush(*stdscr, FALSE); curs_set(0); // hide cursor // init_pair(1, COLOR_BLACK, COLOR_CYAN); } +WINDOW *init_window(int x, int y, int width, int height) { + WINDOW *win = newwin(height, width, y, x); + + nodelay(win, TRUE); // getch(3x) nonblocking IO + keypad(win, TRUE); // allow function keys + // intrflush(3x) - flush terminal input buffer on interrupt key + intrflush(win, FALSE); + + return win; +} + int main(int argc, char *argv[]) { - WINDOW *stdscr; - crs_init(&stdscr); + init_ncurses(); + WINDOW *stdscr = init_window(0, 0, 0, 0); // Set background wbkgd(stdscr, COLOR_PAIR(1)); diff --git a/cli/curse.h b/cli/curse.h index 8234a9a..67d599f 100644 --- a/cli/curse.h +++ b/cli/curse.h @@ -17,5 +17,6 @@ enum crs_mode { int termmode(enum crs_mode mode); void init_ncurses(void); +WINDOW *init_window(int x, int y, int width, int height); #endif /* DORNE_CURSE_H */ From 4d7402fa52450201dc666e8848aa936855576445 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Wed, 10 Sep 2025 23:05:07 +1000 Subject: [PATCH 25/37] add curses.c WINDOW init funcs --- cli/curse.c | 40 +++++++++++++++++++++++++++------------- cli/curse.h | 13 +++++++------ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/cli/curse.c b/cli/curse.c index f2eda88..049082b 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -9,15 +9,15 @@ /* Set ncurses terminal mode (buffering, character processing, * Key->SIG handling, and other termios(3) functionality). */ -inline int termmode(enum crs_mode mode) { +inline int termmode(enum crs_termmode mode) { switch (mode) { - case WMODE_CBREAK: + case TMODE_CBREAK: return cbreak(); - case WMODE_RAW: + case TMODE_RAW: return raw(); - case WMODE_NOCBREAK: + case TMODE_NOCBREAK: return nocbreak(); - case WMODE_NORAW: + case TMODE_NORAW: return noraw(); /* defaulting is not possible. */ } @@ -34,28 +34,42 @@ inline void init_ncurses(void) { start_color(); /* Screen Configuration */ - termmode(WMODE_CBREAK); - noecho(); // manually echo <- getch(3x) + termmode(TMODE_CBREAK); + noecho(); // manually echo from getch(3x) curs_set(0); // hide cursor - - // init_pair(1, COLOR_BLACK, COLOR_CYAN); } -WINDOW *init_window(int x, int y, int width, int height) { - WINDOW *win = newwin(height, width, y, x); - +/* Apply a default IO configuration for an ncurses WINDOW. + */ +static inline void __conf_window(WINDOW *win) { nodelay(win, TRUE); // getch(3x) nonblocking IO keypad(win, TRUE); // allow function keys // intrflush(3x) - flush terminal input buffer on interrupt key intrflush(win, FALSE); +} + +/* Initialise (with default IO configuration) a new ncruses WINDOW. + */ +WINDOW *new_window(int x, int y, int width, int height) { + WINDOW *win = newwin(height, width, y, x); + __conf_window(win); return win; } +/* Initialise (with default IO configuration) the root ncurses WINDOW. + * NOTE: This is typically done via initscr(3x) and called "stdscr". + */ +inline WINDOW *root_window(void) { + WINDOW *rootwin = new_window(0, 0, 0, 0); + __conf_window(rootwin); + return rootwin; +} + int main(int argc, char *argv[]) { init_ncurses(); - WINDOW *stdscr = init_window(0, 0, 0, 0); + WINDOW *stdscr = new_window(0, 0, 0, 0); // Set background wbkgd(stdscr, COLOR_PAIR(1)); diff --git a/cli/curse.h b/cli/curse.h index 67d599f..24bc681 100644 --- a/cli/curse.h +++ b/cli/curse.h @@ -4,19 +4,20 @@ /* libncurses with wide-character support. */ #include -enum crs_mode { +enum crs_termmode { /* tty cbreak mode */ - WMODE_CBREAK, + TMODE_CBREAK, /* tty raw mode */ - WMODE_RAW, + TMODE_RAW, /* tty cooked mode (ISIG & IXON not modified)*/ - WMODE_NOCBREAK, + TMODE_NOCBREAK, /* tty cooked mode (ISIG & IXON set) */ - WMODE_NORAW, + TMODE_NORAW, }; -int termmode(enum crs_mode mode); +int termmode(enum crs_termmode mode); void init_ncurses(void); WINDOW *init_window(int x, int y, int width, int height); +WINDOW *root_window(void); #endif /* DORNE_CURSE_H */ From 2db9e5d141ee34318a16e66ab8497d36792bdd86 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:34:48 +1000 Subject: [PATCH 26/37] ignore valgrind artefacts --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 91162f3..840bb0f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ sandbox/ .cache/ compile_commands.json +# valgrind +vgcore.* + From a04cc6a6e54ab659b8f9c290831cb2895e91de1e Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:36:10 +1000 Subject: [PATCH 27/37] generalise test script --- scripts/test | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/scripts/test b/scripts/test index ed3dcba..6da6b71 100755 --- a/scripts/test +++ b/scripts/test @@ -1,5 +1,5 @@ #!/usr/bin/env bash -USAGE='test [[run]-[valgrind]] ...' +USAGE='test program [[run]-[valgrind]] ...' if [[ "$1" =~ help ]]; then echo "$USAGE" exit 0 @@ -10,17 +10,27 @@ MODE= REBUILD=true VALGRIND=false TARGET=all -if [[ "$1" =~ run.* ]]; then - MODE="$1" +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 fi -if [[ "$1" =~ .*valgrind ]]; then - MODE="$1" +if [[ "$MODE_ARG" =~ .*valgrind ]]; then + MODE="$MODE_ARG" VALGRIND=true PROXY='valgrind -s --leak-check=full --show-leak-kinds=all' TARGET=debug fi + if [[ -n "$MODE" ]]; then shift fi @@ -29,4 +39,4 @@ fi if [[ "$REBUILD" == true ]]; then make clean $TARGET fi -LD_LIBRARY_PATH=./lib $PROXY ./cursed $@ +LD_LIBRARY_PATH=./lib $PROXY "$PROGRAM" $@ From 1f26441c71d7027709c20694cffe6902a95ec5f4 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:37:01 +1000 Subject: [PATCH 28/37] fix bad inline usage --- cli/_pty.c | 4 ++-- cli/curse.c | 15 +++++++++------ cli/curse.h | 6 ++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/cli/_pty.c b/cli/_pty.c index 0fdd9d2..6625e3d 100644 --- a/cli/_pty.c +++ b/cli/_pty.c @@ -75,7 +75,7 @@ fail: * NOTE: login_tty() function. It exists as a learning resource. * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c */ -inline int setctty(const int fdty) { +static inline int setctty(const int fdty) { /* We assume any kernel compiling this defines TIOCSCTTY, * otherwise this implementation won't exactly work... */ return (ioctl(fdty, TIOCSCTTY, 0) != -1); @@ -90,7 +90,7 @@ inline int setctty(const int fdty) { * WARNING: available at LICENSES/UC-LICENSE in this repo. * REF: https://sourceware.org/git/glibc.git -> ./login/login_tty.c */ -inline void bindpty(const int fdty) { +void bindpty(const int fdty) { /* Adjust stdin/stdout/stderr to refer to fd*/ BIND(fdty, STDIN_FILENO); BIND(fdty, STDOUT_FILENO); diff --git a/cli/curse.c b/cli/curse.c index 049082b..37d40f3 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -9,7 +9,7 @@ /* Set ncurses terminal mode (buffering, character processing, * Key->SIG handling, and other termios(3) functionality). */ -inline int termmode(enum crs_termmode mode) { +int termmode(const enum crs_termmode mode) { switch (mode) { case TMODE_CBREAK: return cbreak(); @@ -19,14 +19,16 @@ inline int termmode(enum crs_termmode mode) { return nocbreak(); case TMODE_NORAW: return noraw(); + default: /* defaulting is not possible. */ + return 1; } } /* Initialise ncurses for our usecase. * WARNING: This function should only be called once. */ -inline void init_ncurses(void) { +void init_ncurses(void) { // ncurses expects a locale for consistent behaviour setlocale(LC_ALL, CRS_LOCALE); @@ -42,16 +44,17 @@ inline void init_ncurses(void) { /* Apply a default IO configuration for an ncurses WINDOW. */ -static inline void __conf_window(WINDOW *win) { +static inline void __conf_window(WINDOW *const win) { nodelay(win, TRUE); // getch(3x) nonblocking IO keypad(win, TRUE); // allow function keys // intrflush(3x) - flush terminal input buffer on interrupt key intrflush(win, FALSE); } -/* Initialise (with default IO configuration) a new ncruses WINDOW. +/* Initialise (with default IO configuration) a new ncurses WINDOW. */ -WINDOW *new_window(int x, int y, int width, int height) { +WINDOW *new_window(const int x, const int y, const int width, + const int height) { WINDOW *win = newwin(height, width, y, x); __conf_window(win); @@ -61,7 +64,7 @@ WINDOW *new_window(int x, int y, int width, int height) { /* Initialise (with default IO configuration) the root ncurses WINDOW. * NOTE: This is typically done via initscr(3x) and called "stdscr". */ -inline WINDOW *root_window(void) { +WINDOW *root_window(void) { WINDOW *rootwin = new_window(0, 0, 0, 0); __conf_window(rootwin); return rootwin; diff --git a/cli/curse.h b/cli/curse.h index 24bc681..8d517eb 100644 --- a/cli/curse.h +++ b/cli/curse.h @@ -15,9 +15,11 @@ enum crs_termmode { TMODE_NORAW, }; -int termmode(enum crs_termmode mode); +int termmode(const enum crs_termmode mode); + void init_ncurses(void); -WINDOW *init_window(int x, int y, int width, int height); +WINDOW *init_window(const int x, const int y, const int width, + const int height); WINDOW *root_window(void); #endif /* DORNE_CURSE_H */ From 206f1e6a0956f1a2bf5b9a73a388fb50dc77422b Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:39:49 +1000 Subject: [PATCH 29/37] comment old curse.c main function --- cli/curse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/curse.c b/cli/curse.c index 37d40f3..58b2dc2 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -70,7 +70,8 @@ WINDOW *root_window(void) { return rootwin; } -int main(int argc, char *argv[]) { +/* +int main(const int argc, const char *const argv[]) { init_ncurses(); WINDOW *stdscr = new_window(0, 0, 0, 0); @@ -98,3 +99,4 @@ end: endwin(); return 0; } +*/ From 669f620a6aa6d340d617941deaedf583767c5ff0 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:40:25 +1000 Subject: [PATCH 30/37] add resizemv_window() method to curse.* interface --- cli/curse.c | 10 ++++++++++ cli/curse.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/cli/curse.c b/cli/curse.c index 58b2dc2..3274239 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -70,6 +70,16 @@ WINDOW *root_window(void) { return rootwin; } +/* 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(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(); diff --git a/cli/curse.h b/cli/curse.h index 8d517eb..338ffe6 100644 --- a/cli/curse.h +++ b/cli/curse.h @@ -22,4 +22,7 @@ WINDOW *init_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 */ From 8c4f288a972c63f72ee00884448b71d818cff2ae Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 17:41:14 +1000 Subject: [PATCH 31/37] finish bulk of tree.* implementation --- Makefile | 10 ++-- cli/main.c | 25 +++++++- cli/tree.c | 166 +++++++++++++++++++++++++++++++++++++++++++++-------- cli/tree.h | 23 ++++---- 4 files changed, 181 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index a755c16..5c16f0d 100644 --- a/Makefile +++ b/Makefile @@ -33,18 +33,18 @@ $(BIN)/shfx: shfx/main.c $(CC) $(CFLAGS) -o $(BUILD)/shfx.o -c $^ $(CLD) $(CLDFLAGS) -lncurses -o $@ $(BUILD)/shfx.o -$(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o epty.o) - $(CLD) $(CLDFLAGS) -o $@ $^ +$(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o ilovecurses.o) + $(CLD) $(CLDFLAGS) -lncurses -o $@ $^ $(BUILD) $(BIN): mkdir -p $@ $(BUILD)/dorne.o: $(addprefix $(CLI)/, main.c) $(mkobj) -$(BUILD)/epty.o: $(addprefix $(CLI)/, epty.c _pty.c) +$(BUILD)/ilovecurses.o: $(addprefix $(CLI)/, tree.c curse.c) + $(mkobj) +$(BUILD)/epty.o: $(addprefix $(CLI)/, child.c epty.c _pty.c) $(mkobj) - -# $1/%.o: $1/%.c # === DEVELOPMENT TARGETS === .PHONY: debug run test diff --git a/cli/main.c b/cli/main.c index af57f88..2b5ab1e 100644 --- a/cli/main.c +++ b/cli/main.c @@ -2,7 +2,10 @@ #include #include -#include "child.h" +#include + +// #include "child.h" +#include "tree.h" // struct d_window { // int ptmx; // fd @@ -15,7 +18,23 @@ // } int main(int argc, char **argv) { - struct d_child child; - spawnchild(&child); + // struct d_child child; + // spawnchild(&child); + + struct crs_tree *tree; + init_tree(&tree); + + init_pair(1, COLOR_BLACK, COLOR_CYAN); + init_pair(2, COLOR_BLACK, COLOR_RED); + + // bifurcate_window_node(&tree->root, AXIS_X, FALSE, 0.5); + + // wbkgd(tree->root->child[0]->win, COLOR_PAIR(1)); + // wbkgd(tree->root->child[1]->win, COLOR_PAIR(1)); + + // sleep(3); + + destroy_tree(tree); + return EXIT_SUCCESS; } diff --git a/cli/tree.c b/cli/tree.c index 04922e6..41ae103 100644 --- a/cli/tree.c +++ b/cli/tree.c @@ -1,5 +1,6 @@ #include #include +#include #include "curse.h" #include "tree.h" @@ -14,21 +15,30 @@ static inline struct crs_node *__alloc_node(const enum crs_nodetype type) { /* Construct a new window node (crs_node of type NODE_WIN). */ -static struct crs_node *init_node_window(WINDOW *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 *init_node_abstract(struct crs_node *node1, - struct crs_node *node2, - float ratio) { - struct crs_node *node = __alloc_node(NODE_ABSTRACT); - node->ratio = ratio; +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); +} - node->child[0] = node1; - node->child[1] = node2; +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; } @@ -39,35 +49,138 @@ static void destroy_node(struct crs_node *node) { 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; +} + +/* 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 += _dims1->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 - invert index of the original node in the new abstract node + * invert_axis - invert index of the original node in the new abstract node */ -static void bifurcate_window_node(struct crs_node **node, enum crs_axis axis, - int invert, float ratio) { - assert((*node)->type == NODE_ABSTRACT); +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; - struct crs_node *original_node = *node; - struct crs_node *bi_node = init_node_window(); // WARNING: TODO - - if (!invert) { + + if (bifurcate_dims(*node, axis, ratio, &dims0, &dims1)) { + printf("FAILED TERRIBLY THE FUCK\n"); + exit(1); + return; + } + if (invert_axis) { /* Inverted Bifurcation */ - *node = init_node_abstract(bi_node, original_node, ratio); + node0 = auto_window_node(dims0); + node1 = *node; + resize_node(node1, dims1); } else { /* Non-Inverted Bifurcation */ - *node = init_node_abstract(original_node, bi_node, ratio); + node0 = *node; + node1 = auto_window_node(dims1); + resize_node(node0, dims0); } - resize_abstract_node(*node); + *node = init_abstract_node(node0, node1, axis, ratio, (*node)->dims); } /* Collapse an abstract node, killing one child node and resizing @@ -89,17 +202,15 @@ static void collapse_abstract_node(struct crs_node **node, /* */ static struct crs_node *init_root_node(void) { - WINDOW *rootwin = newwin(0, 0, 0, 0); - return init_node_window(rootwin); + return init_window_node(root_window()); } -int init_tree(struct crs_tree **tree) { +int init_tree(struct crs_tree **const tree) { *tree = (struct crs_tree *)malloc(sizeof(struct crs_tree)); /* Initialise NCurses Library & Standard Screen */ - crs_init(&(*tree)->stdscr); + init_ncurses(); - /* */ (*tree)->root = init_root_node(); // (*tree)->root = __alloc_node(NODE_WINDOW); @@ -108,9 +219,14 @@ int init_tree(struct crs_tree **tree) { return EXIT_SUCCESS; } -void destroy_tree(struct crs_tree *tree) { +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); } diff --git a/cli/tree.h b/cli/tree.h index d5ba171..c2263f1 100644 --- a/cli/tree.h +++ b/cli/tree.h @@ -1,16 +1,19 @@ #ifndef DORNE_TREE_H #define DORNE_TREE_H -# ifndef __NCURSES_H +#ifndef __NCURSES_H typedef struct _win_st WINDOW; -# endif /* __NCURSES_H */ +#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 NODEDIMS(node, dims) (getbegyx(dims.y, dims.x); getmaxyx(dims.y, dims.x)) +#define GET_WNODEDIMS(dims, node) \ + (getbegyx((node)->win, dims.y, dims.x)); \ + getmaxyx((node)->win, dims.y, dims.x) enum crs_nodetype { NODE_WINDOW, @@ -35,24 +38,24 @@ struct crs_node { union { WINDOW *win; struct { + enum crs_axis axis; float ratio; + struct crs_nodedims *dims; struct crs_node *child[NODE_CHILD_N]; }; }; }; struct crs_tree { - WINDOW *stdscr; struct crs_node *root; }; /* === External Interface === */ -// struct crs_node *init_node_window(void); -// struct crs_node *init_node_abstract(void); -// void destroy_node(struct crs_node *node); +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); -int init_tree(struct crs_tree **tree); -void update_tree(struct crs_tree *tree); -void destroy_tree(struct crs_tree *tree); +void bifurcate_window_node(struct crs_node **node, const enum crs_axis axis, + const int invert_axis, const float ratio); #endif /* DORNE_TREE_H */ From f73dbd7d8a66cffbb2ee1a8271f0182cc40f8768 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 19:24:48 +1000 Subject: [PATCH 32/37] ensure initscr(3x) & use newwin(3x) not stdscr(3x) for root node --- cli/curse.c | 22 ++++++++++++---------- cli/curse.h | 3 +-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cli/curse.c b/cli/curse.c index 3274239..3c465fe 100644 --- a/cli/curse.c +++ b/cli/curse.c @@ -25,6 +25,15 @@ int termmode(const enum crs_termmode mode) { } } +/* Apply a default IO configuration for an ncurses WINDOW. + */ +static inline void __conf_window(WINDOW *const win) { + nodelay(win, TRUE); // getch(3x) nonblocking IO + keypad(win, TRUE); // allow function keys + // intrflush(3x) - flush terminal input buffer on interrupt key + intrflush(win, FALSE); +} + /* Initialise ncurses for our usecase. * WARNING: This function should only be called once. */ @@ -33,6 +42,8 @@ void init_ncurses(void) { setlocale(LC_ALL, CRS_LOCALE); /* NCurses Init */ + initscr(); + __conf_window(stdscr); start_color(); /* Screen Configuration */ @@ -42,15 +53,6 @@ void init_ncurses(void) { curs_set(0); // hide cursor } -/* Apply a default IO configuration for an ncurses WINDOW. - */ -static inline void __conf_window(WINDOW *const win) { - nodelay(win, TRUE); // getch(3x) nonblocking IO - keypad(win, TRUE); // allow function keys - // intrflush(3x) - flush terminal input buffer on interrupt key - intrflush(win, FALSE); -} - /* Initialise (with default IO configuration) a new ncurses WINDOW. */ WINDOW *new_window(const int x, const int y, const int width, @@ -65,7 +67,7 @@ WINDOW *new_window(const int x, const int y, const int width, * NOTE: This is typically done via initscr(3x) and called "stdscr". */ WINDOW *root_window(void) { - WINDOW *rootwin = new_window(0, 0, 0, 0); + WINDOW *rootwin = new_window(0, 0, COLS, LINES); __conf_window(rootwin); return rootwin; } diff --git a/cli/curse.h b/cli/curse.h index 338ffe6..72f0e7e 100644 --- a/cli/curse.h +++ b/cli/curse.h @@ -18,8 +18,7 @@ enum crs_termmode { int termmode(const enum crs_termmode mode); void init_ncurses(void); -WINDOW *init_window(const int x, const int y, const int width, - const int height); +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, From 79f5c5235a357d16308e0d58fe34d68b5d20944a Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 19:26:28 +1000 Subject: [PATCH 33/37] add term_dims() func --- cli/tree.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cli/tree.c b/cli/tree.c index 41ae103..63c8088 100644 --- a/cli/tree.c +++ b/cli/tree.c @@ -87,6 +87,13 @@ static struct crs_nodedims *get_dims(const struct crs_node *node) { 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 @@ -162,7 +169,6 @@ void bifurcate_window_node(struct crs_node **node, 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); @@ -202,7 +208,15 @@ static void collapse_abstract_node(struct crs_node **node, /* */ static struct crs_node *init_root_node(void) { - return init_window_node(root_window()); + 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) { From fce84f184418787365ff3e2ad8a2ac72a28b0a17 Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 19:27:02 +1000 Subject: [PATCH 34/37] fix bifurcation AXIS_Y bug --- cli/tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cli/tree.c b/cli/tree.c index 63c8088..0c0b975 100644 --- a/cli/tree.c +++ b/cli/tree.c @@ -119,7 +119,7 @@ static int bifurcate_dims(const struct crs_node *parent, } else { _dims0->height *= ratio; _dims1->height -= _dims0->height; - _dims1->y += _dims1->height; + _dims1->y += _dims0->height; } if (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height) { @@ -162,8 +162,7 @@ static void resize_node(struct crs_node *node, struct crs_nodedims *new_dims) { * 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, +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; From 3c2977d76b697b58b647fc108844b23767e2337b Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 19:27:49 +1000 Subject: [PATCH 35/37] BIFURCATION IMPLEMENTED --- cli/main.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/cli/main.c b/cli/main.c index 2b5ab1e..956a25e 100644 --- a/cli/main.c +++ b/cli/main.c @@ -5,6 +5,7 @@ #include // #include "child.h" +#include "curse.h" #include "tree.h" // struct d_window { @@ -24,17 +25,58 @@ int main(int argc, char **argv) { struct crs_tree *tree; init_tree(&tree); - init_pair(1, COLOR_BLACK, COLOR_CYAN); - init_pair(2, COLOR_BLACK, COLOR_RED); - - // bifurcate_window_node(&tree->root, AXIS_X, FALSE, 0.5); - - // wbkgd(tree->root->child[0]->win, COLOR_PAIR(1)); - // wbkgd(tree->root->child[1]->win, COLOR_PAIR(1)); + 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); - // sleep(3); + /* 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); + + 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) { + // refresh(); + usleep(100000); + } destroy_tree(tree); - + // endwin(); + // free(tree); + return EXIT_SUCCESS; } From 0fcb8143cfda1a72dd66d83a794e7f253b7990cc Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 20:35:08 +1000 Subject: [PATCH 36/37] remove shfx subproject --- Makefile | 6 +----- shfx/main.c | 44 -------------------------------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 shfx/main.c diff --git a/Makefile b/Makefile index 5c16f0d..a18fee8 100644 --- a/Makefile +++ b/Makefile @@ -29,10 +29,6 @@ $(BIN)/pw-test: $(addprefix $(LIB)/, main.c) $(CC) $(CFLAGS) -o $(BUILD)/pw-test.o -c $^ $(CLD) $(CLDFLAGS) -o $@ $(BUILD)/pw-test.o -$(BIN)/shfx: shfx/main.c - $(CC) $(CFLAGS) -o $(BUILD)/shfx.o -c $^ - $(CLD) $(CLDFLAGS) -lncurses -o $@ $(BUILD)/shfx.o - $(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o ilovecurses.o) $(CLD) $(CLDFLAGS) -lncurses -o $@ $^ @@ -49,7 +45,7 @@ $(BUILD)/epty.o: $(addprefix $(CLI)/, child.c epty.c _pty.c) # === DEVELOPMENT TARGETS === .PHONY: debug run test debug: - $(MAKE) all \ + $(MAKE) all \ CFLAGS="$(CFLAGS) $(CFLAGS_DBG)" \ CLDFLAGS="$(CLDFLAGS) $(CLDFLAGS_DBG)" run: debug diff --git a/shfx/main.c b/shfx/main.c deleted file mode 100644 index a70bd04..0000000 --- a/shfx/main.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include - -#include - -#define BASE_DELAY 1000000 - -int main(int argc, char *argv[]) { - // Curses init - WINDOW *screen = initscr(); - start_color(); - nodelay(screen, 1); - cbreak(); - noecho(); - curs_set(0); - keypad(screen, TRUE); - - // Color pairs - init_pair(1, COLOR_BLACK, COLOR_CYAN); - - // Set background - wbkgd(screen, 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; -} From d35e200488704be9358588b7bf8156e7f802528a Mon Sep 17 00:00:00 2001 From: Emile Clark-Boman Date: Thu, 11 Sep 2025 20:50:55 +1000 Subject: [PATCH 37/37] fix pipewire linked with everything + rename ilovecurses -> cursetree --- Makefile | 6 +++--- config.mk | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a18fee8..36b9358 100644 --- a/Makefile +++ b/Makefile @@ -27,9 +27,9 @@ endef 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) -o $@ $(BUILD)/pw-test.o + $(CLD) $(CLDFLAGS) -lpipewire-0.3 -o $@ $(BUILD)/pw-test.o -$(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o ilovecurses.o) +$(BIN)/dorne: $(addprefix $(BUILD)/,dorne.o cursetree.o) $(CLD) $(CLDFLAGS) -lncurses -o $@ $^ $(BUILD) $(BIN): @@ -37,7 +37,7 @@ $(BUILD) $(BIN): $(BUILD)/dorne.o: $(addprefix $(CLI)/, main.c) $(mkobj) -$(BUILD)/ilovecurses.o: $(addprefix $(CLI)/, tree.c curse.c) +$(BUILD)/cursetree.o: $(addprefix $(CLI)/, tree.c curse.c) $(mkobj) $(BUILD)/epty.o: $(addprefix $(CLI)/, child.c epty.c _pty.c) $(mkobj) diff --git a/config.mk b/config.mk index b355192..259b563 100644 --- a/config.mk +++ b/config.mk @@ -7,7 +7,7 @@ CFLAGS_DBG := -g LD := ld CLD = $(CC) LDFLAGS := -CLDFLAGS := -lpipewire-0.3 -lm -lc +CLDFLAGS := -lm -lc LDFLAGS_DBG := -g # # === Nix Mutations ===