Index: main/form2.c
===================================================================
--- main/form2.c	(revision main,4)
+++ main/form2.c	(revision main,4)
@@ -0,0 +1,194 @@
+#include <form.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+#define _MAX_FORMS 16
+#define _MAX_FIELDS 16
+
+#define _KEY_BITS 4
+#define _IDX_MASK (~(0u) << _KEY_BITS)
+#define _KEY_MASK (~_IDX_MASK)
+
+
+
+#define DC(v, c) const int v = c
+
+DC(req_next_field, REQ_NEXT_FIELD);
+DC(req_del_prev, REQ_DEL_PREV);
+DC(key_backspace, KEY_BACKSPACE);
+DC(req_end_line, REQ_END_LINE);
+DC(req_end_field, REQ_END_FIELD);
+DC(req_beg_field, REQ_BEG_FIELD);
+DC(key_left, KEY_LEFT);
+DC(key_right, KEY_RIGHT);
+DC(req_left_char, REQ_LEFT_CHAR);
+DC(req_right_char, REQ_RIGHT_CHAR);
+
+
+
+typedef unsigned form2_h;
+
+struct form2_t {
+	unsigned key;
+
+	FIELD *fields[_MAX_FIELDS + 1];
+	int field_count;
+
+	FORM *form_struct; /* Only set when posted. */
+};
+
+static struct form2_t *_forms[_MAX_FORMS];
+
+
+static form2_h _form2_init(unsigned i)
+{
+	_forms[i] = calloc(1, sizeof(struct form2_t));
+	if(!_forms[i]) return 0;
+
+	do {
+		_forms[i]->key = rand() & _KEY_MASK;
+	} while(i == 0 && _forms[i]->key == 0);
+
+	return (i << _KEY_BITS) | _forms[i]->key;
+}
+
+static struct form2_t **_check_ptr(form2_h form)
+{
+	unsigned i, k;
+	struct form2_t **f;
+
+	if(!form) return NULL;
+
+	i = form >> _KEY_BITS;
+	k = form & _KEY_MASK;
+
+	if(i >= _MAX_FORMS) return NULL;
+
+	f = _forms + i;
+
+	if(!*f) return NULL;
+	if((*f)->key != k) return NULL;
+
+	return f;
+}
+
+static struct form2_t *_check(form2_h form)
+{
+	struct form2_t **f = _check_ptr(form);
+	if(!f) return NULL;
+	return *f;
+}
+
+form2_h form2_create(void)
+{
+	int i;
+
+	for(i = 0; i < _MAX_FORMS; i++)
+		if(!_forms[i]) return _form2_init(i);
+
+	return 0;
+}
+
+int form2_add_field(form2_h form, int row, int col, int width, int height,
+		int data_height)
+{
+	struct form2_t *f = _check(form);
+	int *i;
+
+	if(!f) return 0;
+
+	i = &(f->field_count);
+	if(*i == _MAX_FIELDS) return 0;
+
+	init_pair(1, COLOR_WHITE, COLOR_BLUE);
+
+	f->fields[*i] = new_field(height, width, row, col, data_height, 0);
+	set_field_back(f->fields[*i], A_UNDERLINE | COLOR_PAIR(1));
+	field_opts_off(f->fields[*i], O_AUTOSKIP);
+
+	++(*i);
+
+	return 1;
+}
+
+int form2_destroy(form2_h form)
+{
+	struct form2_t **f = _check_ptr(form);
+	int i;
+
+	if(!f) return 0;
+
+	for(i = 0; i < (*f)->field_count; i++) {
+		free_field((*f)->fields[i]);
+	}
+
+	free(*f);
+	*f = NULL;
+
+	return 1;
+}
+
+int form2_post(form2_h form)
+{
+	struct form2_t *f = _check(form);
+
+	if(!f) return 0;
+	if(f->form_struct) return 0;
+
+	f->form_struct = new_form(f->fields);
+
+	post_form(f->form_struct);
+
+	return 1;
+}
+
+int form2_drive(form2_h form, int c)
+{
+	struct form2_t *f = _check(form);
+
+	if(!f) return 0;
+	if(!f->form_struct) return 0;
+
+	form_driver(f->form_struct, c);
+
+	return 1;
+}
+
+int form2_unpost(form2_h form)
+{
+	struct form2_t *f = _check(form);
+
+	if(!f) return 0;
+	if(!f->form_struct) return 0;
+
+	unpost_form(f->form_struct);
+	free_form(f->form_struct);
+	f->form_struct = NULL;
+
+	return 1;
+}
+
+int form2_field_len(form2_h form, int i)
+{
+	struct form2_t *f = _check(form);
+
+	if(!f) return -1;
+	if(!f->form_struct) return -1;
+
+	return strlen(field_buffer(f->fields[i], 0));
+}
+
+int form2_copy_field(form2_h form, int i, char *buff, int len)
+{
+	struct form2_t *f = _check(form);
+
+	if(!f) return -1;
+	if(!f->form_struct) return -1;
+
+	strncpy(buff, field_buffer(f->fields[i], 0), len);
+	buff[len - 1] = '\0';
+
+	return 1;
+}
Index: main/Makefile
===================================================================
--- main/Makefile	(revision main,2)
+++ main/Makefile	(revision main,4)
@@ -1,3 +1,9 @@
-menu2.so: menu2.c
-	rm -f menu2.so
-	gcc -shared -fPIC -o menu2.so menu2.c -lmenu -Wall -pedantic
+all: menu2.so form2.so
+
+menu2.so: LIBS := -lmenu
+
+form2.so: LIBS := -lform
+
+%.so: %.c
+	rm -f $@
+	gcc -shared -fPIC -o $@ $< $(LIBS) -Wall -pedantic
Index: main/curses.lisp
===================================================================
--- main/curses.lisp	(revision main,2)
+++ main/curses.lisp	(revision main,4)
@@ -19,4 +19,8 @@
 (defcfun noecho :int)
 (defcfun getch :int)
+(defcfun keypad :int (win :pointer) (bf :int))
+(defcfun start-color :int)
+
+(defcvar stdscr :pointer :read-only t)
 
 
@@ -36,6 +40,92 @@
 
 
+(define-foreign-library form2
+  (t "/home/dsowen/lisp/tui/form2.so"))
+
+(use-foreign-library form2)
+
+(defmacro defcdef (name)
+  `(defcvar ,name :int :read-only t))
+
+(defcdef req-next-field)
+(defcdef req-del-prev)
+(defcdef key-backspace)
+(defcdef req-end-line)
+(defcdef req-end-field)
+(defcdef req-beg-field)
+(defcdef key-left)
+(defcdef key-right)
+(defcdef req-left-char)
+(defcdef req-right-char)
+
+(defcfun form2-create :int)
+(defcfun form2-add-field :int (form :int) (row :int) (col :int) (width :int)
+         (height :int) (data-height :int))
+(defcfun form2-destroy :int (form :int))
+(defcfun form2-post :int (form :int))
+(defcfun form2-drive :int (form :int) (c :int))
+(defcfun form2-unpost :int (form :int))
+(defcfun form2-field-len :int (form :int) (i :int))
+(defcfun form2-copy-field :int (form :int) (i :int) (buff :pointer) (len :int))
+
+(defun form2-get-value (form i)
+  (let* ((len (1+ (form2-field-len form i)))
+         (buff (cffi:foreign-alloc :char :count len)))
+    (form2-copy-field form i buff len)
+    (let ((str (foreign-string-to-lisp buff)))
+      (foreign-free buff)
+      (string-trim " " str))))
+
+
 (defun init-screen ()
   (initscr)
+  (start-color)
+  (keypad stdscr 1)
   (cbreak)
   (noecho))
+
+(defmacro ncase (keyform &rest clauses)
+  `(let ((#1=#:g0001 ,keyform))
+    (cond
+      ,@(mapcar (lambda (clause)
+                  (destructuring-bind (keys &rest forms) clause
+                    (if (eq keys t)
+                        `(t ,@forms)
+                        (progn
+                          (unless (listp keys)
+                            (setf keys (list keys)))
+                          `((member #1# (list ,@keys) :test '=)
+                            ,@forms)))))
+                clauses))))
+
+
+(defun test ()
+  (let (l)
+    (init-screen)
+    (let ((form (form2-create)))
+      (form2-add-field form 1 1 10 1 0)
+      (form2-add-field form 3 1 15 1 0)
+      (form2-post form)
+      (loop doing
+            (let ((c (getch)))
+              (ncase c
+                     ((key-backspace 127)
+                      (form2-drive form req-del-prev))
+                     (key-left
+                      (form2-drive form req-left-char))
+                     (key-right
+                      (form2-drive form req-right-char))
+                     (9
+                      (form2-drive form req-beg-field)
+                      (form2-drive form req-next-field)
+                      (form2-drive form req-end-field))
+                     (10
+                      (form2-drive form req-next-field)
+                      (return))
+                     (t
+                      (form2-drive form c)))))
+      (setf l (form2-get-value form 0))
+      (form2-unpost form)
+      (form2-destroy form))
+    (endwin)
+    l))
Index: main/lisp.sh
===================================================================
--- main/lisp.sh	(revision main,2.1.1)
+++ main/lisp.sh	(revision main,4)
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-rlfe -h .history sbcl --load /usr/share/emacs/site-lisp/slime/swank-loader.lisp --eval "(swank:create-server)"
+sbcl --load /usr/share/emacs/site-lisp/slime/swank-loader.lisp --eval "(setf swank:*communication-style* :fd-handler)" --eval "(swank:create-server)"
