summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorpaul <paul@FreeBSD.org>1994-11-13 06:45:44 +0000
committerpaul <paul@FreeBSD.org>1994-11-13 06:45:44 +0000
commitec3127d29c777128be8df287d32e7ba0f04fb5a7 (patch)
treecd0c6245017543bfc740dc61d4255fac3130ed97 /lib
parentf427ece6c5f21d208351c2b2a3e1a7eddad1150d (diff)
downloadFreeBSD-src-ec3127d29c777128be8df287d32e7ba0f04fb5a7.zip
FreeBSD-src-ec3127d29c777128be8df287d32e7ba0f04fb5a7.tar.gz
The start of a forms editor library. Currently implements text and
input fields. It reads a template file passed to init_forms(char *) and creates a curses based form editor. See the examples directory for a basic demo.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile6
-rw-r--r--lib/libforms/Makefile13
-rw-r--r--lib/libforms/examples/Makefile7
-rw-r--r--lib/libforms/examples/example.frm6
-rw-r--r--lib/libforms/examples/tform.c18
-rw-r--r--lib/libforms/forms.c333
-rw-r--r--lib/libforms/forms.h81
-rw-r--r--lib/libforms/lex.l19
-rw-r--r--lib/libforms/yacc.y149
9 files changed, 629 insertions, 3 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 493a823..cc23579 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,9 +10,9 @@ SUBDIR=csu/${MACHINE}
.endif
# XXX MISSING: libmp libplot
-SUBDIR+= libc libcompat libcrypt libcurses libedit libf2c libkvm libmd \
- libmytinfo libncurses libresolv librpcsvc libskey libtelnet \
- libtermcap libutil liby
+SUBDIR+= libc libcompat libcrypt libcurses libedit libf2c libforms \
+ libkvm libmd libmytinfo libncurses libresolv librpcsvc libskey \
+ libtelnet libtermcap libutil liby
.if !defined(WANT_MSUN)
SUBDIR+= libm
diff --git a/lib/libforms/Makefile b/lib/libforms/Makefile
new file mode 100644
index 0000000..9dae66d
--- /dev/null
+++ b/lib/libforms/Makefile
@@ -0,0 +1,13 @@
+LIB = forms
+
+SRCS = forms.c yacc.c lex.c
+CLEANFILES += y.tab.h lex.c yacc.c
+
+CFLAGS = -I. -I${.CURDIR}
+
+beforeinstall:
+ @(cd ${.CURDIR}; cmp -s forms.h ${DESTDIR}/usr/include/forms.h || \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 forms.h \
+ ${DESTDIR}/usr/include/forms.h;)
+
+.include <bsd.lib.mk>
diff --git a/lib/libforms/examples/Makefile b/lib/libforms/examples/Makefile
new file mode 100644
index 0000000..5e175b5
--- /dev/null
+++ b/lib/libforms/examples/Makefile
@@ -0,0 +1,7 @@
+PROG = tform
+
+CFLAGS = -Wall -I. -I${.CURDIR}
+LDADD = -lforms -lncurses -ll
+DPADD = ${LIBFORMS} ${LIBNCURSES} ${LIBL}
+
+.include <bsd.prog.mk>
diff --git a/lib/libforms/examples/example.frm b/lib/libforms/examples/example.frm
new file mode 100644
index 0000000..f09ded5
--- /dev/null
+++ b/lib/libforms/examples/example.frm
@@ -0,0 +1,6 @@
+Form template: 0 0 24 79
+Text 0 0 "This is non-editable text field"
+Input 1 2 4 2 3 3 2 2 8 "Prompt1:" 2 20 10 25 "First"
+Input 2 3 1 4 2 2 5 2 8 "Prompt2:" 5 20 10 25 "Second"
+Input 3 4 2 4 1 1 2 40 8 "Prompt3:" 2 50 10 25 "Third"
+Input 4 1 2 1 4 4 10 2 8 "Prompt4:" 10 20 10 25 "Fourth"
diff --git a/lib/libforms/examples/tform.c b/lib/libforms/examples/tform.c
new file mode 100644
index 0000000..48f4d48
--- /dev/null
+++ b/lib/libforms/examples/tform.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <dialog.h>
+#include <forms.h>
+
+extern struct form *form;
+
+void
+main()
+{
+ printf("Testing forms code\n");
+
+ if (init_forms("example.frm") == -1)
+ exit(1);
+
+ edit_form(form);
+}
diff --git a/lib/libforms/forms.c b/lib/libforms/forms.c
new file mode 100644
index 0000000..5c29b10
--- /dev/null
+++ b/lib/libforms/forms.c
@@ -0,0 +1,333 @@
+#include <string.h>
+#include <ncurses.h>
+#include <forms.h>
+
+extern FILE *yyin;
+
+struct form *form;
+unsigned int keymap[FORM_NO_KEYS] = {
+ KEY_BTAB,
+ 9,
+ KEY_UP,
+ KEY_DOWN,
+ '\r',
+ '\033',
+ KEY_HOME,
+ KEY_END,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_BACKSPACE,
+ KEY_DC
+};
+
+int
+edit_field(WINDOW *window, struct field *field)
+{
+ int len;
+ int key = 0;
+ int fpos, dispos, curpos;
+ int i;
+ int done = 0;
+
+ len = strlen(field->entry.input.field);
+ if (len < field->entry.input.field_width) {
+ fpos = len;
+ curpos = len;
+ dispos = 0;
+ } else {
+ fpos = field->entry.input.field_width;
+ curpos = field->entry.input.field_width;
+ dispos = len - field->entry.input.field_width;
+ };
+
+ field->entry.input.field_attr = FORM_SELECTED_ATTR;
+ do {
+ wattrset(window, field->entry.input.field_attr);
+ wmove(window, field->entry.input.y_field, field->entry.input.x_field);
+ for (i=0; i < field->entry.input.field_width; i++)
+ if (i < (len - dispos))
+ waddch(window, field->entry.input.field[dispos+i]);
+ else
+ waddch(window, ' ');
+ wmove(window, field->entry.input.y_field, field->entry.input.x_field + curpos);
+ wrefresh(window);
+
+ key = wgetch(window);
+ if (key == keymap[FORM_LEFT] ||
+ key == keymap[FORM_RIGHT] ||
+ key == keymap[FORM_UP] ||
+ key == keymap[FORM_DOWN] ||
+ key == keymap[FORM_EXIT] ||
+ key == '\n' ||
+ key == '\r') {
+ done = 1;
+ } else if (key == keymap[FORM_FIELD_HOME]) {
+ if (len < field->entry.input.field_width) {
+ fpos = len;
+ curpos = len;
+ dispos = 0;
+ } else {
+ fpos = field->entry.input.field_width;
+ curpos = field->entry.input.field_width;
+ dispos = len - field->entry.input.field_width;
+ };
+ } else if (key == keymap[FORM_FIELD_END]) {
+ if (len < field->entry.input.field_width) {
+ dispos = 0;
+ curpos = len - 1;
+ } else {
+ dispos = len - field->entry.input.field_width - 1;
+ curpos = field->entry.input.field_width - 1;
+ }
+ fpos = len - 1;
+ } else if (key == keymap[FORM_FIELD_LEFT]) {
+ if ((!curpos) && (!dispos)) {
+ beep();
+ } else {
+ if (--curpos < 0) {
+ curpos = 0;
+ if (--dispos < 0)
+ dispos = 0;
+ }
+ if (--fpos < 0)
+ fpos = 0;
+ }
+ } else if (key == keymap[FORM_FIELD_RIGHT]) {
+ if ((curpos + dispos) == len) {
+ beep();
+ } else if ((curpos == (field->entry.input.field_width-1)) &&
+ (dispos == (field->entry.input.max_field_width - field->entry.input.field_width -1))) {
+ beep();
+ } else {
+ if (++curpos >= field->entry.input.field_width) {
+ curpos = field->entry.input.field_width - 1;
+ dispos++;
+ }
+ if (dispos >= len)
+ dispos = len - 1;
+ if (++fpos >= len) {
+ fpos = len;
+ }
+ }
+ } else if (key == keymap[FORM_FIELD_BACKSPACE]) {
+ if ((!curpos) && (!dispos)) {
+ beep();
+ } else if (fpos > 0) {
+ memmove(&field->entry.input.field[fpos-1], &field->entry.input.field[fpos], len - fpos);
+ len--;
+ fpos--;
+ if (curpos > 0)
+ --curpos;
+ if (!curpos)
+ --dispos;
+ if (dispos < 0)
+ dispos = 0;
+ } else
+ beep();
+ } else {
+ if (len < field->entry.input.max_field_width - 1) {
+ memmove(&field->entry.input.field[fpos+1], &field->entry.input.field[fpos], len - fpos);
+ field->entry.input.field[fpos] = key;
+ len++;
+ fpos++;
+ if (++curpos == field->entry.input.field_width) {
+ --curpos;
+ dispos++;
+ }
+ if (len == (field->entry.input.max_field_width - 1)) {
+ dispos = (field->entry.input.max_field_width - field->entry.input.field_width - 1);
+ }
+ } else
+ beep();
+ }
+ } while (!done);
+
+ field->entry.input.field_attr = FORM_DEFAULT_ATTR;
+ wattrset(window, field->entry.input.field_attr);
+ wmove(window, field->entry.input.y_field, field->entry.input.x_field);
+ for (i=0; i < field->entry.input.field_width; i++)
+ if (i < (len - dispos))
+ waddch(window, field->entry.input.field[dispos+i]);
+ else
+ waddch(window, ' ');
+ wmove(window, field->entry.input.y_field, field->entry.input.x_field + curpos);
+ wrefresh(window);
+
+ field->entry.input.field[len] = 0;
+ delwin(window);
+ refresh();
+ return (key);
+}
+
+int
+init_forms(char *template)
+{
+ FILE *fd;
+ struct field *link, *next;
+
+ /* Intialise lex input */
+ if (!(fd = fopen(template, "r"))) {
+ fprintf(stderr, "Couldn't open template file %s\n", template);
+ return(-1);
+ }
+
+ if (!initscr()) {
+ fprintf(stderr, "Failed to initialise curses\n");
+ return(-1);
+ }
+
+ cbreak();
+ noecho();
+ nonl();
+
+ yyin = fd;
+ yyparse();
+
+ /* Setup up links to/from fields */
+
+ for (next = form->fields; next; next = next->link) {
+ /* Ignore the link values of text fields */
+ if (next->type == FORM_FTYPE_TEXT)
+ continue;
+ link = find_link((int)next->next);
+ if (!link) {
+ fprintf(stderr, "Bad link (next) from %d to %d\n",
+ next->field_id, (int)next->next);
+ next->next = 0;
+ } else
+ next->next = link;
+ link = find_link((int)next->up);
+ if (!link) {
+ fprintf(stderr, "Bad link (up) from %d to %d\n",
+ next->field_id, (int)next->up);
+ next->up = 0;
+ } else
+ next->up = link;
+ link = find_link((int)next->down);
+ if (!link) {
+ fprintf(stderr, "Bad link (down) from %d to %d\n",
+ next->field_id, (int)next->down);
+ next->down = 0;
+ } else
+ next->down = link;
+ link = find_link((int)next->left);
+ if (!link) {
+ fprintf(stderr, "Bad link (left) from %d to %d\n",
+ next->field_id, (int)next->left);
+ next->left = 0;
+ } else
+ next->left = link;
+ link = find_link((int)next->right);
+ if (!link) {
+ fprintf(stderr, "Bad link (right) from %d to %d\n",
+ next->field_id, (int)next->right);
+ next->right = 0;
+ } else
+ next->right = link;
+ }
+}
+
+struct field *
+find_link(int id)
+{
+ struct field *next;
+
+ for (next=form->fields; next; next=next->link)
+ /* You can't move into a text field */
+ if ((id == next->field_id) && (next->type != FORM_FTYPE_TEXT))
+ return (next);
+ return(0);
+}
+
+void
+edit_form(struct form *form)
+{
+ WINDOW *window;
+ struct field *cur_field;
+ int key;
+
+ window = newwin(form->height, form->width, form->y, form->x);
+ keypad(window, TRUE);
+
+ refresh_form(window, form);
+
+ cur_field = form->fields;
+
+ do {
+ /* Just skip over text fields */
+ if (cur_field->type == FORM_FTYPE_TEXT) {
+ cur_field = cur_field->link;
+ continue;
+ }
+ switch (cur_field->type) {
+ case FORM_FTYPE_INPUT:
+ key = edit_field(window, cur_field);
+ break;
+ case FORM_FTYPE_MENU:
+ case FORM_FTYPE_BUTTON:
+ case FORM_FTYPE_TEXT: /* Should never happen */
+ default:
+ break;
+ }
+ if (key == keymap[FORM_UP]) {
+ if (cur_field->up)
+ cur_field = cur_field->up;
+ else
+ beep();
+ } else if (key == keymap[FORM_DOWN]) {
+ if (cur_field->down)
+ cur_field = cur_field->down;
+ else
+ beep();
+ } else if (key == keymap[FORM_LEFT]) {
+ if (cur_field->left)
+ cur_field = cur_field->left;
+ else
+ beep();
+ } else if (key == keymap[FORM_RIGHT]) {
+ if (cur_field->right)
+ cur_field = cur_field->right;
+ else
+ beep();
+ } else if (key == keymap[FORM_NEXT]) {
+ if (cur_field->next)
+ cur_field = cur_field->next;
+ else
+ cur_field = form->fields;
+ } else
+ beep();
+ } while (key != keymap[FORM_EXIT]);
+}
+
+void
+refresh_form(WINDOW *window, struct form *form)
+{
+ struct field *cur_field;
+
+ cur_field = form->fields;
+
+ while (cur_field) {
+ switch (cur_field->type) {
+ case FORM_FTYPE_INPUT:
+ wattrset(window, cur_field->entry.input.prompt_attr);
+ mvwprintw(window, cur_field->entry.input.y_prompt,
+ cur_field->entry.input.x_prompt,
+ "%s", cur_field->entry.input.prompt);
+ wattrset(window, cur_field->entry.input.field_attr);
+ mvwprintw(window, cur_field->entry.input.y_field,
+ cur_field->entry.input.x_field,
+ "%s", cur_field->entry.input.field);
+ break;
+ case FORM_FTYPE_TEXT:
+ wattrset(window, cur_field->entry.text.attr);
+ mvwprintw(window, cur_field->entry.text.y,
+ cur_field->entry.text.x,
+ "%s", cur_field->entry.text.text);
+ break;
+ default:
+ break;
+ }
+ cur_field = cur_field->link;
+ }
+ wrefresh(window);
+}
diff --git a/lib/libforms/forms.h b/lib/libforms/forms.h
new file mode 100644
index 0000000..606bd1c
--- /dev/null
+++ b/lib/libforms/forms.h
@@ -0,0 +1,81 @@
+#define FORM_NO_KEYS 12
+#define FORM_LEFT 0
+#define FORM_RIGHT 1
+#define FORM_UP 2
+#define FORM_DOWN 3
+#define FORM_NEXT 4
+#define FORM_EXIT 5
+#define FORM_FIELD_HOME 6
+#define FORM_FIELD_END 7
+#define FORM_FIELD_LEFT 8
+#define FORM_FIELD_RIGHT 9
+#define FORM_FIELD_BACKSPACE 10
+#define FORM_FIELD_DELETE 11
+
+/* Attribute values */
+#define FORM_DEFAULT_ATTR 0
+#define FORM_SELECTED_ATTR 0
+
+/* Field types */
+#define FORM_FTYPE_INPUT 0
+#define FORM_FTYPE_MENU 1
+#define FORM_FTYPE_BUTTON 2
+#define FORM_FTYPE_TEXT 3
+
+#define MAX_FIELD_SIZE 80
+
+struct form {
+ int x;
+ int y;
+ int height;
+ int width;
+ struct field *fields;
+};
+
+struct input_field {
+ int y_prompt;
+ int x_prompt;
+ int prompt_width;
+ int prompt_attr;
+ char *prompt;
+ int y_field;
+ int x_field;
+ int field_width;
+ int max_field_width;
+ int field_attr;
+ char *field;
+};
+
+struct text_field {
+ int y;
+ int x;
+ int attr;
+ char *text;
+};
+
+struct field {
+ int field_id;
+ int type;
+ union {
+ struct input_field input;
+ struct text_field text;
+#ifdef notyet
+ struct menu_field menu
+ struct button_field button;
+#endif
+ } entry;
+ struct field *link;
+ struct field *next;
+ struct field *up;
+ struct field *down;
+ struct field *left;
+ struct field *right;
+};
+
+extern unsigned int keymap[FORM_NO_KEYS];
+
+int init_forms();
+int edit_line(WINDOW *window, struct field *);
+void edit_form(struct form *);
+void refresh_form(WINDOW *, struct form *);
+struct field *find_link(int);
diff --git a/lib/libforms/lex.l b/lib/libforms/lex.l
new file mode 100644
index 0000000..deb6c8d
--- /dev/null
+++ b/lib/libforms/lex.l
@@ -0,0 +1,19 @@
+%{
+#include "y.tab.h"
+%}
+
+%%
+"Form template:" { yylval.ival = FORM; return FORM; }
+Input { yylval.ival = INPUT; return INPUT; }
+Text { yylval.ival = TEXT; return TEXT; }
+
+[0-9]+ { yylval.ival = atoi(yytext); return NUMBER; }
+\"[^"]* {
+ if (yytext[yyleng-1] == '\\') {
+ yymore();
+ } else {
+ input();
+ yylval.sval = yytext+1;
+ return STRING;
+ }
+ }
diff --git a/lib/libforms/yacc.y b/lib/libforms/yacc.y
new file mode 100644
index 0000000..2bc953e
--- /dev/null
+++ b/lib/libforms/yacc.y
@@ -0,0 +1,149 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ncurses.h>
+#include <forms.h>
+
+extern struct form *form;
+
+struct field *cur_field;
+int id,next, up, down, left, right;
+%}
+
+%start file
+
+%union {
+ int ival;
+ char *sval;
+}
+
+%token <sval> STRING
+%token <ival> NUMBER
+%token <ival> INPUT
+%token <ival> TEXT
+%token <ival> FORM
+
+%type <sval> String
+
+%%
+
+file : /* Empty */
+ | file form
+ | file fields
+ | error
+ ;
+
+form : FORM NUMBER NUMBER NUMBER NUMBER
+ {
+ form = (struct form *) malloc(sizeof(struct form));
+ if (!form)
+ return(-1);
+ form->x = $2;
+ form->y = $3;
+ form->height = $4;
+ form->width = $5;
+ form->fields = 0;
+ }
+ ;
+
+fields : input
+ | text
+ ;
+
+input : INPUT NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER String NUMBER NUMBER NUMBER NUMBER String
+ {
+ if (alloc_field() == -1)
+ return(-1);
+ cur_field->field_id = $2;
+ /*
+ * These will hold addresses but store
+ * the field id's in them temporarily
+ */
+ cur_field->next = (struct field *) $3;
+ cur_field->up = (struct field *) $4;
+ cur_field->down = (struct field *) $5;
+ cur_field->left = (struct field *) $6;
+ cur_field->right = (struct field *) $7;
+ cur_field->type = FORM_FTYPE_INPUT;
+ cur_field->entry.input.y_prompt = $8;
+ cur_field->entry.input.x_prompt = $9;
+ cur_field->entry.input.prompt_width = $10;
+ cur_field->entry.input.prompt_attr = FORM_DEFAULT_ATTR;
+ cur_field->entry.input.prompt = (char *) malloc($10+1);
+ if (!cur_field->entry.input.prompt)
+ return(-1);
+ strncpy(cur_field->entry.input.prompt, $11, $10);
+ cur_field->entry.input.prompt[$10] = 0;
+ cur_field->entry.input.y_field = $12;
+ cur_field->entry.input.x_field = $13;
+ cur_field->entry.input.field_width = $14;
+ cur_field->entry.input.max_field_width = $15;
+ cur_field->entry.input.field = (char *) malloc(strlen($16));
+ cur_field->entry.input.field_attr = FORM_DEFAULT_ATTR;
+ if (!cur_field->entry.input.field)
+ return(-1);
+ strcpy(cur_field->entry.input.field, $16);
+ }
+ ;
+
+text : TEXT NUMBER NUMBER String
+ {
+ if (alloc_field() == -1)
+ return(-1);
+ cur_field->field_id = 0;
+ cur_field->type = FORM_FTYPE_TEXT;
+ cur_field->entry.text.y = $2;
+ cur_field->entry.text.x = $3;
+ cur_field->entry.text.attr = FORM_DEFAULT_ATTR;
+ cur_field->entry.text.text = (char *) malloc(strlen($4));
+ if (!cur_field->entry.text.text)
+ return (-1);
+ strcpy(cur_field->entry.text.text, $4);
+ }
+ ;
+
+String : STRING
+ {
+ char *t, *old, *new;
+
+ t = strdup($1);
+ free($1);
+ /*
+ * Deal with any escaped characters,
+ * only works for " and \ really.
+ */
+ for (old=t, new=t; *old; old++, new++) {
+ if (*old == '\\')
+ old++;
+ *new = *old;
+ }
+ *new = '\0';
+ $$ = t;
+ }
+
+%%
+void
+yyerror(char *s)
+{
+ printf("%s\n", s);
+ exit(1);
+}
+
+int
+alloc_field()
+{
+ if (!form->fields) {
+ form->fields = (struct field *) malloc(sizeof(struct field));
+ if (!form->fields)
+ return(-1);
+ cur_field = form->fields;
+ } else {
+ cur_field->link = (struct field *) malloc(sizeof(struct field));
+ if (!cur_field->link)
+ return(-1);
+ cur_field = cur_field->link;
+ }
+
+ return(0);
+}
OpenPOWER on IntegriCloud