summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgonzo <gonzo@toniatuh.com>2023-06-09 21:46:26 +0200
committergonzo <gonzo@toniatuh.com>2023-06-09 21:46:26 +0200
commit1fb2975906401893eb46f98d2d1a3837dcb2e8d8 (patch)
tree5b79a3274e69fbae924bb90b7fc868e6e4487a62
parent2c380f8df666fcebd979511f33e7d72291b389cd (diff)
downloadloan_calc-1fb2975906401893eb46f98d2d1a3837dcb2e8d8.tar.gz
rough ncurses main
-rw-r--r--Makefile4
-rw-r--r--main.c197
2 files changed, 199 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 14f15ab..ae3eee8 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ CC=clang --std=c11
AR=ar ruvcs
CFLAGS=-Wall -Wextra -Werror -Weverything -pedantic
-LIBS=-lform -lncurses -lm
+LIBS=-lncurses -lform -lm
BLDFLAGS=-g
RELFLAGS=-O2
@@ -30,7 +30,7 @@ $(OBJ): $(HEAD)
$(LOBJ): $(LHEAD)
%.o: %.c
- $(CC) -o ./src/$@ -c $< $(CFLAGS)
+ $(CC) -o $@ -c $< $(CFLAGS)
$(TARGET): $(OBJ) $(LIB)
$(CC) -o $@ $(OBJ) $(LIB) $(LIBS) $(BLDFLAGS)
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..e90a92b
--- /dev/null
+++ b/main.c
@@ -0,0 +1,197 @@
+#include <ncurses.h>
+#include <form.h>
+#include <signal.h>
+#include "contract.h"
+#include "loans.h"
+
+static int WIDTH, HEIGHT;
+static int padscroll, duration;
+static WINDOW *pad;
+_Noreturn static void finish(int sig);
+void display_custom_form(FORM *);
+void print_contract(WINDOW *w, int x, int y, contract *c);
+void run_sim(FORM *);
+
+int main() {
+ int ch, i;
+
+ /* setup ncurses */
+ signal(SIGINT, finish); /* arrange interrupts to terminate */
+ initscr(); /* initialize the curses library */
+ cbreak(); /* take input chars one at a time don't wait for CR */
+ noecho(); /* echo input */
+ nonl(); /* do not LF->CR-LF on output */
+ intrflush(stdscr, FALSE); /* do not flush on interrupts */
+ keypad(stdscr, TRUE); /* enable keyboard mapping */
+ getmaxyx(stdscr, HEIGHT, WIDTH);
+
+ /* create the form */
+ FIELD *fields[8];
+ FORM *form;
+ char *contract_types[] = { "loan", "savings", NULL };
+ char *contract_subtypes[] = { "bullet", "sla", "mort", NULL };
+
+ /* initialize fields */
+ fields[0] = new_field(1, 11, 4, 22, 0, 0); /* contract type */
+ set_field_type(fields[0], TYPE_ENUM, contract_types, FALSE, TRUE);
+ fields[1] = new_field(1, 11, 5, 22, 0, 0); /* contract subtype */
+ set_field_type(fields[1], TYPE_ENUM, contract_subtypes, FALSE, TRUE);
+ fields[2] = new_field(1, 11, 6, 22, 0, 0); /* contract duration */
+ set_field_type(fields[2], TYPE_INTEGER, 1, 0, INT_MAX);
+ fields[3] = new_field(1, 11, 7, 22, 0, 0); /* yearly payments */
+ set_field_type(fields[3], TYPE_INTEGER, 1, 0, INT_MAX);
+ fields[4] = new_field(1, 11, 8, 22, 0, 0); /* delay duration */
+ set_field_type(fields[4], TYPE_INTEGER, 1, 0, INT_MAX);
+ fields[5] = new_field(1, 11, 9, 22, 0, 0); /* starting amount */
+ set_field_type(fields[5], TYPE_NUMERIC, 2, 0.0, 0.0);
+ fields[6] = new_field(1, 11, 10, 22, 0, 0); /* rate */
+ set_field_type(fields[6], TYPE_NUMERIC, 3, 0.0, 1.0);
+ fields[7] = NULL;
+
+ /* configure fields */
+ for (i = 0; fields[i]; i++) {
+ set_field_back(fields[i], A_UNDERLINE); /* Print a line for the option */
+ field_opts_off(fields[i], O_AUTOSKIP); /* Don't go to next field when this */
+ /* Field is filled up */
+ }
+
+ /* create form */
+ form = new_form(fields);
+ display_custom_form(form);
+ refresh();
+
+ int formactive = TRUE;
+ /* mainloop */
+ while ((ch = getch()) != KEY_EXIT) {
+ if (formactive) {
+ switch (ch) {
+ case KEY_DOWN:
+ /* Go to next field */
+ form_driver(form, REQ_NEXT_FIELD);
+ /* Go to the end of the present buffer */
+ /* Leaves nicely at the last character */
+ form_driver(form, REQ_END_LINE);
+ break;
+ case KEY_UP:
+ form_driver(form, REQ_PREV_FIELD);
+ form_driver(form, REQ_END_LINE);
+ break;
+ case KEY_LEFT:
+ form_driver(form, REQ_PREV_CHOICE);
+ break;
+ case KEY_RIGHT:
+ form_driver(form, REQ_NEXT_CHOICE);
+ break;
+ case KEY_BACKSPACE:
+ form_driver(form, REQ_DEL_PREV);
+ break;
+ case '\r':
+ unpost_form(form);
+ formactive = FALSE;
+ curs_set(0);
+ refresh();
+ box(stdscr, 0, 0);
+ run_sim(form);
+ padscroll = 0;
+ prefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1);
+ break;
+ default:
+ /* If this is a normal character, it gets */
+ /* Printed */
+ form_driver(form, ch);
+ }
+ } else {
+ switch (ch) {
+ case KEY_DOWN:
+ padscroll += (padscroll < duration) ? 1 : 0;
+ pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1);
+ doupdate();
+ break;
+ case KEY_UP:
+ padscroll -= (padscroll > 0) ? 1 : 0;
+ pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1);
+ doupdate();
+ break;
+ case 'q':
+ display_custom_form(form);
+ formactive = TRUE;
+ curs_set(1);
+ break;
+ }
+ }
+ }
+
+ delwin(pad);
+ if (formactive) unpost_form(form);
+ free_form(form);
+ for (i = 0; fields[i]; i++)
+ free_field(fields[i]);
+
+ finish(0);
+}
+
+_Noreturn static void finish (int sig) {
+ endwin();
+
+ exit(sig);
+}
+
+void display_custom_form(FORM *form) {
+ post_form(form);
+ mvprintw(2, 5, "Initialization Parameters");
+ mvprintw(4, 2, "Contract type:");
+ mvprintw(5, 2, "Contract subtype:");
+ mvprintw(6, 2, "Contract Duration:");
+ mvprintw(7, 2, "Yearly payments:");
+ mvprintw(8, 2, "Delay Duration:");
+ mvprintw(9, 2, "Starting Amount:");
+ mvprintw(10, 2, "Rate:");
+ form_driver(form, REQ_FIRST_FIELD);
+}
+
+void print_contract(WINDOW* w, int x, int y, contract *c) {
+ mvwprintw(w, x, y,
+ "%4d/%-4d | %12.2f | %10.2f | %10.2f | %10.2f\n",
+ c->k, c->n,
+ (double)c->P, (double)c->I,
+ (double)c->D, (double)c->A);
+}
+
+void run_sim(FORM *form) {
+ /* loan_type type; */
+ int n, d, yp;
+ double r, p;
+
+ FIELD **fields = form_fields(form);
+ n = atoi(field_buffer(fields[2], 0));
+ yp = atoi(field_buffer(fields[3], 0));
+ d = atoi(field_buffer(fields[4], 0));
+ p = atof(field_buffer(fields[5], 0));
+ r = atof(field_buffer(fields[6], 0));
+
+ //adapt wrt yearly payments
+ if (yp > 1) {
+ n = n*yp;
+ d = d*yp;
+ r = r/(double)yp;
+ }
+
+ /* setup pad */
+ pad = newpad(n+1, WIDTH-2);
+ mvwprintw(stdscr, 1, 2, "Reinbursement Table");
+ mvwprintw(stdscr, 3, 3,
+ "%4s/%-4s | %12s | %10s | %10s | %10s\n",
+ "cur", "tot",
+ "principal",
+ "interest",
+ "part",
+ "annuity");
+
+ /* run simulation */
+ loan l = loan_init(MORTGAGE, n, d, r, p);
+ for (int i = 0; i <= n; i++) {
+ print_contract(pad, i, 2, l.c);
+ loan_update(l);
+ }
+ duration = n - HEIGHT + 6;
+}