diff options
| -rw-r--r-- | lib/libforms/Makefile | 6 | ||||
| -rw-r--r-- | lib/libforms/examples/Makefile | 6 | ||||
| -rw-r--r-- | lib/libforms/examples/example.c | 62 | ||||
| -rw-r--r-- | lib/libforms/examples/example.frm | 192 | ||||
| -rw-r--r-- | lib/libforms/forms.c | 400 | ||||
| -rw-r--r-- | lib/libforms/forms.h | 208 | ||||
| -rw-r--r-- | lib/libforms/internal.h | 91 | ||||
| -rw-r--r-- | lib/libforms/lex.l | 113 | ||||
| -rw-r--r-- | lib/libforms/parser.y | 935 | 
9 files changed, 1141 insertions, 872 deletions
diff --git a/lib/libforms/Makefile b/lib/libforms/Makefile index 3703960c41aa..55e06c1e2bf5 100644 --- a/lib/libforms/Makefile +++ b/lib/libforms/Makefile @@ -1,8 +1,10 @@  LIB = forms +SHLIB_MAJOR= 3 +SHLIB_MINOR= 0 -SRCS = forms.c parser.y lex.l menu.c fields.c +SRCS = debug.c bindings.c parser.y lex.l forms.c objects.c ncurses.c -CFLAGS += -I. -I${.CURDIR} -Wall -g -DHASH_STATS +CFLAGS += -I. -I${.CURDIR} -DHASH_STATS #-g -DDEBUG -Wall -ansi -pedantic -Dlint  LDFLAGS += -ll  CLEANFILES+= lex.c parser.c y.tab.h diff --git a/lib/libforms/examples/Makefile b/lib/libforms/examples/Makefile index 4f0a23fafdd7..4389b705c043 100644 --- a/lib/libforms/examples/Makefile +++ b/lib/libforms/examples/Makefile @@ -3,7 +3,7 @@ NOMAN = yet  SRCS = example.c -CFLAGS = -g -static +CFLAGS = -static #-g  .if exists(${.CURDIR}/../obj)  FORMDIR=${.CURDIR}/../obj @@ -11,7 +11,7 @@ FORMDIR=${.CURDIR}/../obj  FORMDIR=${.CURDIR}/..  .endif -LDADD = -L${FORMDIR} -lforms -lncurses -lmytinfo -ll -DPADD = /usr/lib/libforms.a +LDADD = -L${FORMDIR} -lforms -ldialog -lncurses -lmytinfo -ll +DPADD = ${LIBFORMS} ${LIBNCURSES}  .include <bsd.prog.mk> diff --git a/lib/libforms/examples/example.c b/lib/libforms/examples/example.c index 39c4432e1585..b08a4ea6e1f3 100644 --- a/lib/libforms/examples/example.c +++ b/lib/libforms/examples/example.c @@ -33,66 +33,28 @@   */  #include <stdio.h>  #include <strhash.h> +#include <ncurses.h>  #include "../forms.h" -extern hash_table *global_bindings; +void UserRoutine(OBJECT *);  main()  {  	struct Tuple *tuple; -	struct Form *form; +	struct Form *form1, *form2;  	int res; -	initscr(); - - -	if (form_load("example.frm") == FS_ERROR) -		exit(0);; - -	form = form_start("example"); - -	if (!form) { -		err(-1, "No form `example' in example.frm returned"); +	if (load_objects("example.frm") == ST_ERROR)  		exit(0); -	} - -	keypad(form->window, TRUE); -	cbreak(); -	noecho(); - -	tuple = form_get_tuple(global_bindings, "example", FT_FORM); -	if (!tuple) -		err(0, "No such form: example"); -	else -		form = (struct Form *)tuple->addr; -	print_status("This is the status line"); +	bind_tuple(root_table, "User_Routine", TT_FUNC, &UserRoutine); -	form_bind_tuple(form->bindings, "exit_form", FT_FUNC, &exit_form); -	form_bind_tuple(form->bindings, "cancel_form", FT_FUNC, &cancel_form); - -	res = form_show("example"); - -	while (form->status == FS_RUNNING) { -		do_field(form); -		wrefresh(form->window); -	} - -	wclear(form->window); -	wrefresh(form->window); - -	if  (form->status == FS_EXIT) { -		printf("Your entries were:\n\n"); -		tuple = form_get_tuple(form->bindings, "input1", FT_FIELD_INST); -		printf("Input 1 = %s\n", ((struct Field *)tuple->addr)->field.input->input); -		tuple = form_get_tuple(form->bindings, "input2", FT_FIELD_INST); -		printf("Input 2 = %s\n", ((struct Field *)tuple->addr)->field.input->input); -		tuple = form_get_tuple(form->bindings, "menu1", FT_FIELD_INST); -		res = ((struct Field *)tuple->addr)->field.menu->selected; -		printf("Menu selected = %d, %s\n", res, -			 ((struct Field *)tuple->addr)->field.menu->options[res]); -	} else if (form->status == FS_CANCEL) -		printf("You cancelled the form\n"); +	start_object("adduser"); +} -	endwin(); +void +UserRoutine(OBJECT *obj) +{ +	/* Just draw a box and return */ +	exit (1);  } diff --git a/lib/libforms/examples/example.frm b/lib/libforms/examples/example.frm index 513ced239445..eca43ab5675a 100644 --- a/lib/libforms/examples/example.frm +++ b/lib/libforms/examples/example.frm @@ -1,54 +1,162 @@ -Colours example_colors { -	pair = red, yellow -	pair = blue, white -} - -field1 { attributes = 0 text = "\standout This text is \bold bold and \blink flashy" } +# An example form file for an adduser command +!Forms Version name -field2 { -	height = 2 -	width = 22 -	text = "This is an input fieldwith a default" +Display screen1 { +	Height 1000 +	Width 1000 +	Type Ncurses {  +		# libdialog compatible color pairs +		ColorPairs { +			01	Cyan	Blue +			02	Black	Black +			03	Black	White +			04	Yellow	White +			05	White	White +			06	White	Blue +			07	Black	White +			08	White	Blue +			09	Red		White +			10	Yellow	Blue +			11	Black	White +			12	Black	White +			13	Black	White +			14	Black	White +			15	Yellow	White +			16	White	White +			17	Yellow	White +			18	Black	White +			19	White	White +			20	Black	White +			21	White	Blue +			22	Yellow	White +			23	Yellow	Blue +			24	Red		White +			25	Red		Blue +			26	Black	White +			27	White	White +			28	Green	White +			29	Green	White +		} +	} +	# +	# The AttrTable assosciates attribute strings with numeric id's. +	# It's up to the device dependant code to decide how to interprate an +	# attribute id. For ncurses the id is treated as a color pair number. +	# For other devices they'd likely be an index to some device specific +	# structure declared above. +	# +	AttrTable { +			screen					01 +			shadow					02 +			dialog					03 +			title					04 +			border					05 +			button_active			06 +			button_inactive			07 +			button_key_active		08 +			button_key_inactive		09 +			button_label_active		10 +			button_label_inactive	11 +			inputbox				12 +			inputbox_border			13 +			searchbox				14 +			searchbox_title			15 +			searchbox_border		16 +			position_indicator		17 +			menubox					18 +			menubox_border			19 +			item					20 +			item_selected			21 +			tag						22 +			tag_selected			23 +			tag_key					24 +			tag_key_selected		25 +			check					26 +			check_selected			27 +			uarrow					28 +			darrow					29 +	}  } -field3 { -	width = 10 -	default = "This is a default entry" -	limit = 30 +template { +	Width 15 +	Text "This is defined as a template and duplicated here"  } -field4 { text = "This is a labelled input field" } +Window adduser on screen1 at 0,0 { +	Attributes "\screen" -field5 { label = "A temp. label" } +	window at 1,1 { +		Height 22 +		Width 75 +		Attributes "\dialog" +		Active username -field6 { text = "Some options to choose from: " } +		box { +			Attributes "\dialog" +			Highlight "\border" +			CallFunc draw_box +			shadow { +				Attributes "\shadow" +				CallFunc draw_shadow +			} +		} -field7 { selected = 0 options = "Choose", "another", "of", "these" } +		Title at 0,9 { Text " This is a title " } -field8 { width = 6 action = "EXIT" function = exit_form } +		username at 5,20 { +			Height 1 +			Width 30 +			Attributes "\screen" +			Highlight "\tag_selected" -field9 { -action = "CANCEL" -function = cancel_form -} +			Next shells + +			Input "nobody" + +			exp at 3,3 { +				Attributes "\dialog" +				Text "The is an input object:" +			} +			prompt at 5,3 { +				Text "Username: " +			} +		} + +		shells at 9,20 { +			Attributes "\dialog" +			Highlight "\tag_selected" +			Next button +			Options { +				"sh" +				"csh" +				"tcsh" +				"bash" +			} + +			exp at 7,3 { +				Attributes "\dialog" +				Text "This is a horizontal menu:" +			} +			prompt at 9,3 { Text "Select a shell: "} +		} + +		button at 14,9 { +			Height 3 +			Width 7 +			Attributes "\tag_key_selected" +			Highlight "\tag_selected" +			Active button + +			button_box at 14,9 { +				CallFunc draw_box +			} -Form example at 0,0 { -	height = 25 -	width = 80 -	start = input1 -	colortable = example -	attributes = 0 - -	Title  {attributes = 0 text = "A Simple Demo"} at  0,30 - -	field1 at  3,23 -	field2 at  7, 2 -	field4 at 11, 2 -	field6 at 15, 2 - -	input1 {field3} at  7,45, next=input2,down=input2,up=quit,right=input2 -	input2 {field5} at 11,45, next=menu1,down=menu1,up=input1,right=menu1 -	menu1  {field7} at 15,45, next=quit,down=quit,up=input2,right=quit -	quit   {field8} at 20,20, next=cancel,down=input1,up=menu1,right=cancel -	cancel {field9} at 20,43, next=input1,down=input1,up=menu1,right=input1 +			button at 15, 10 { +				Up username Down username +				Action User_Routine +				Label "QUIT" +			} +		} +	}  } diff --git a/lib/libforms/forms.c b/lib/libforms/forms.c index f5a81a817801..575608fd08a0 100644 --- a/lib/libforms/forms.c +++ b/lib/libforms/forms.c @@ -33,309 +33,235 @@   */  #include <strhash.h> +#include <ctype.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h> +#include <ncurses.h>  #include <forms.h>  #include <err.h> -#include <ncurses.h>  #include "internal.h"  extern FILE *yyin; - -hash_table *global_bindings; - -unsigned int f_keymap[] = { -	KEY_UP,         /* F_UP */ -	KEY_DOWN,       /* F_DOWN */ -	9,          /* F_RIGHT */ -	8,          /* F_LEFT */ -	10,         /* F_NEXT */ -	KEY_LEFT,       /* F_CLEFT */ -	KEY_RIGHT,      /* F_CRIGHT */ -	KEY_HOME,       /* F_CHOME */ -	KEY_END,        /* F_CEND */ -	263,            /* F_CBS */ -	330,            /* F_CDEL */ -	10          /* F_ACCEPT */ +hash_table *root_table, *cbind; +OBJECT *cur_obj; +int done; + +/* Default attribute commands */ +struct attr_cmnd attr_cmnds[] = { +	{"box",		ATTR_BOX	}, +	{"center",	ATTR_CENTER	}, +	{"right",	ATTR_RIGHT	}  }; -int -form_load(const char *filename) -{ -	FILE *fd; +/* Internal bindings */ -	global_bindings = hash_create(0); +struct intbind { +	char *key; +	void *addr; +}; -	if (!global_bindings) -		return (FS_ERROR); +struct intbind internal_bindings[] = { +	{"draw_box", &draw_box}, +	{"draw_shadow", &draw_shadow} +};   -	if (!(fd = fopen(filename, "r"))) { -		warn("Couldn't open forms file %s", filename); -		return (FS_ERROR); -	} +/* Bind the internal function addresses */ -	yyin = fd; -	yyparse(); +void +bind_internals(hash_table *table) +{ +	int i; -	if (fclose(fd)) { -		warn("Couldn't close forms file %s", filename); -		return (FS_ERROR); -	} +	for (i=0; i < (sizeof internal_bindings)/(sizeof (struct intbind)); i++) +		if (bind_tuple(table, internal_bindings[i].key, +					   TT_FUNC, internal_bindings[i].addr) == ST_ERROR) +			errx(-1, "Failed to bind internal tuples"); +} -	hash_stats(global_bindings, 1); +/* + * Find the default device and open a display on it. + */ + +DISPLAY * +default_open(DISPLAY *display) +{ +	/* XXX -- not implemented, just calls ncurses */ +	return (ncurses_open(display)); -	return (FS_OK);  }  int -find_editable(char *key, void *data, void *arg) +load_objects(const char *filename)  { -	struct Tuple *tuple = (struct Tuple *)data; -	struct Field *field; +	FILE *fd; -	if (tuple->type != FT_FIELD_INST) -		return (1); +	root_table = hash_create(0); +	if (!root_table) +		errx(-1, "Failed to allocate root bindings table"); -	field = (struct Field *)tuple->addr; +	cbind = root_table; -	if ((field->type == FF_INPUT) || -		(field->type == FF_MENU) || -		(field->type == FF_ACTION)) { -		arg = field; -		return (0); -	} else -		return (1); -} +	bind_internals(root_table); -struct Form * -form_start(char *formname) -{ -	struct Tuple *tuple; -	struct Form *form; -	struct Field *field = 0; -	struct Field *start = 0; - -	tuple = form_get_tuple(global_bindings, formname, FT_FORM); - -	if (!tuple) { -		warnx("No such form"); -		return (0); +	if (!(fd = fopen(filename, "r"))) { +		warn("Couldn't open file %s", filename); +		return (ST_ERROR);  	} -	form = tuple->addr; - -	/* Initialise form */ -	if (!form->height) -		form->height = LINES; -	if (!form->width) -		form->width = COLS; +	yyin = fd; +	yyparse(); -	form->window = newwin(form->height, form->width, form->y, form->x); -	if (!form->window) { -		warnx("Couldn't open window, closing form"); -		return (0); +	if (fclose(fd)) { +		warn("Couldn't close file %s", filename); +		return (ST_ERROR);  	} -	/* Initialise the field instances */ - -	hash_traverse(form->bindings, init_field, field); +	return (ST_OK); +} -	tuple = form_get_tuple(form->bindings, form->startfield, FT_FIELD_INST); +int +start_object(char *objname) +{ +	TUPLE *tuple; +	OBJECT *object; -	if (!tuple) { -		warnx("No start field specified"); -		/* Search for an editable field */ -		hash_traverse(form->bindings, &find_editable, start); -		form->current_field = start; -	} else	 -		form->current_field = (struct Field *)tuple->addr; +	tuple = get_tuple(root_table, objname, TT_OBJ_INST); +	if (!tuple) +		return (ST_NOBIND); -	if (!form->current_field) -		errx(1, "No suitable start field found, aborting"); +	object = (OBJECT *)tuple->addr; +	cur_obj = object; -	form->prev_field = form->current_field; +	set_display(object->display); -	form->status = FS_RUNNING; +	cur_obj->status |= O_VISIBLE; -	return (form); +	while (!done) { +		hash_traverse(root_table, &display_tuples, root_table); +		hash_traverse(root_table, &refresh_displays, root_table); +		process_object(cur_obj); +	} +	return (ST_DONE);  }  int -form_bind_tuple(hash_table *htable, char *name, TupleType type, void *addr) +call_function(char *func, OBJECT *obj)  { -	struct Tuple *tuple; +	TUPLE *tuple; -	tuple = malloc(sizeof (struct Tuple)); -	if (!tuple) { -		warn("Couldn't allocate memory for new tuple"); -		return (FS_ERROR); -	} - -	tuple->name = name; -	tuple->type = type; -	tuple->addr = addr; -	tuple->next = 0; - -	if (!htable) -		return (FS_ERROR); -	else { -		/* Check there isn't already a tuple of this type with this name */ -		if (form_get_tuple(htable, name, type)) { -			warn("Duplicate tuple name, %s, skipping", name); -			return (FS_ERROR); -		} else -			hash_search(htable, tuple->name, tuple, NULL); -	} +	tuple = tuple_search(obj, func, TT_FUNC); +	if (!tuple) +		return (0); -	return (0); +	(*tuple->addr)(obj); +	return (1);  } -int -tuple_match_any(char *key, struct Tuple *tuple, TupleType *type) +set_display(DISPLAY *display)  { -	if (tuple->type != *type) { -		type = 0; -		return (1); -	} else { -		type = (TupleType *)tuple; -		return (0); +	switch (display->type) { +		case DT_NCURSES: +			ncurses_set_display(display); +			break; +		default: +			break;  	}  } -struct Tuple * -form_get_tuple(hash_table *htable, char *key, TupleType type) +void +display_object(OBJECT *obj)  { -	void *arg = &type; - -	/* -	 * If a key is specified then search for that key, -	 * otherwise, search the whole table for the first -	 * tuple of the required type. -	 */ - -	if (key) -		return(hash_search(htable, key, NULL, NULL)); -	else { -		hash_traverse(htable, &tuple_match_any, arg); -		return (arg); +	switch(obj->display->type) { +		case DT_NCURSES: +			ncurses_display_object(obj); +			break; +		default: +			break;  	}  } -int -show_field(char *key, void *data, void *arg) +void +process_object(OBJECT *obj)  { -	struct Tuple *tuple = (struct Tuple *)data; -	struct Field *field = (struct Field *)tuple->addr; - -	display_field(arg, field); +	TUPLE *tuple; -	return (1); +	/* Call user routine, if there is one. */ +	if (obj->UserProcFunc) +		if (call_function(obj->UserProcFunc, obj)) +			return; +	/* Find the first non-compound object or a default override */ +	while (obj->type == OT_COMPOUND) { +		tuple = tuple_search(obj, obj->object.compound->defobj, TT_OBJ_INST); +		obj = (OBJECT *)tuple->addr; +	} +	cur_obj = obj; + +	switch(obj->display->type) { +		case DT_NCURSES: +			ncurses_process_object(obj); +			break; +		default: +			break; +	}  }  int -form_show(char *formname) +refresh_displays(char *key, void *data, void *arg)  { -	struct Tuple *tuple; -	struct Form *form; -	int x, y; - -	tuple = form_get_tuple(global_bindings, formname, FT_FORM); -	if (!tuple) -		return (FS_NOBIND); - -	form = tuple->addr; - -	/* Clear form */ -	wattrset(form->window, form->attr); -	for (y=0; y < form->height; y++) -		for (x=0; x < form->width; x++) -			mvwaddch(form->window, y, x, ' '); +	TUPLE *tuple = (TUPLE *)data; +	DISPLAY *display; + +	if (tuple->type == TT_DISPLAY) +		display = (DISPLAY *)tuple->addr; +		switch (display->type) { +			case DT_NCURSES: +				ncurses_refresh_display(display); +				break; +			default: +				break; +		} -	hash_traverse(form->bindings, show_field, form->window); - -	return (FS_OK); -} - -unsigned int -do_key_bind(struct Form *form, unsigned int ch) -{ -	struct Field *field = form->current_field; -	struct Tuple *tuple=0; - -	/* XXX -- check for keymappings here --- not yet done */ - -	if (ch == FK_UP) { -		if (field->fup) { -			tuple = form_get_tuple(form->bindings, field->fup, FT_FIELD_INST); -			if (!tuple) -				print_status("Field to move up to does not exist"); -		} else -			print_status("Can't move up from this field"); -	} else if (ch == FK_DOWN) { -		if (field->fdown) { -			tuple = form_get_tuple(form->bindings, field->fdown, FT_FIELD_INST); -			if (!tuple) -				print_status("Field to move down to does not exist"); -		} else -			print_status("Can't move down from this field"); -	} else if (ch == FK_LEFT) { -		if (field->fleft) { -			tuple = form_get_tuple(form->bindings, field->fleft, FT_FIELD_INST); -			if (!tuple) -				print_status("Field to move left to does not exist"); -		} else -			print_status("Can't move left from this field"); -	} else if (ch == FK_RIGHT) { -		if (field->fright) { -			tuple = form_get_tuple(form->bindings, field->fright, FT_FIELD_INST); -			if (!tuple) -				print_status("Field to move right to does not exist"); -		} else -			print_status("Can't move right from this field"); -	} else if (ch == FK_NEXT) { -		if (field->fnext) { -			tuple = form_get_tuple(form->bindings, field->fnext, FT_FIELD_INST); -			if (!tuple) -				print_status("Field to move to next does not exist"); -		} else -			print_status("Can't move next from this field"); -	} else -		/* No motion keys pressed */ -		return (ch); - -	if (tuple) { -		form->prev_field = form->current_field; -		form->current_field = tuple->addr; -		return (FS_OK); -	} else { -		beep(); -		return (FS_ERROR); -	} +	return (1);  } -#ifdef DEBUG_NOT_YET -void -debug_dump_bindings(hash_table *htable) +int +display_tuples(char *key, void *data, void *arg)  { -	struct Tuple *binds; - -	binds = form_get_tuple(htable, 0, FT_ANY); -	while (binds) { -		printf("%s, %d, %x\n", binds->name, binds->type, (int)binds->addr); -		binds = form_next_tuple(0, FT_ANY, binds->next); +	TUPLE *tuple = (TUPLE *)data; +	OBJECT *obj; +	void (* fn)(); + +    switch(tuple->type) { +		case TT_OBJ_INST: +			obj = (OBJECT *)tuple->addr; + +			/* Call user routine, if there is one. */ +			if (obj->UserDrawFunc) { +				if (!call_function(obj->UserDrawFunc, obj)) +					display_object(obj); +			} else +				display_object(obj); + +			/* Display sub-objects */ +			if (obj->bind) +				hash_traverse(obj->bind, &display_tuples, 0); +			break; +		default: +			break;  	} +	return (1);  } -void debug_dump_form(struct Form *form) +AttrType +parse_default_attributes(char *string)  { -	struct Field *field; +	int i; -	field = form->fieldlist; - -	for ( ; field; field = field->next) { -		printf("%s, %x, next = %x\n", field->defname, (int)field, (int)field->next); -	} +	for (i=0; i < (sizeof attr_cmnds) / (sizeof (struct attr_cmnd)); i++) +		if (!strcmp(string, attr_cmnds[i].attr_name)) +			return (attr_cmnds[i].attr_type); +	return (ATTR_UNKNOWN);  } -#endif diff --git a/lib/libforms/forms.h b/lib/libforms/forms.h index ae1c06d8e341..ceac28760690 100644 --- a/lib/libforms/forms.h +++ b/lib/libforms/forms.h @@ -32,126 +32,158 @@   *   */ -#include <ncurses.h> +#ifndef _FORMS_H_ +#define _FORMS_H_ -#define FF_UNKNOWN 0 -#define FF_TEXT 1 -#define FF_ACTION 2 -#define FF_INPUT 3 -#define FF_MENU 4 +#include <ncurses.h> +#include <strhash.h>  #define F_DEFATTR 0  #define F_SELATTR A_REVERSE  /* Status values */ -#define FS_ERROR	-1 -#define FS_OK		0 -#define FS_EXIT		1 -#define FS_CANCEL	2 -#define FS_NOBIND	3 -#define FS_RUNNING  4 - +#define ST_ERROR	-1 +#define ST_OK		0 +#define ST_DONE		1 +#define ST_CANCEL	2 +#define ST_NOBIND	3 +#define ST_RUNNING  4  typedef enum { -	FT_ANY, -	FT_FORM,  -	FT_COLTAB, -	FT_FIELD_INST, -	FT_FIELD_DEF, -	FT_FUNC +	TT_ANY, +	TT_OBJ_INST, +	TT_OBJ_DEF, +	TT_FUNC, +	TT_DISPLAY, +	TT_ATTR  } TupleType; -struct Tuple { +typedef enum { +	DT_ANY, +	DT_NCURSES, +	DT_X, +	DT_VGA +} DisplayType; + +typedef enum { +	OT_ACTION, +	OT_COMPOUND, +	OT_FUNCTION, +	OT_INPUT, +	OT_MENU, +	OT_SHADOW, +	OT_TEXT +} ObjectType; + +#define FUNCP void(*)(void *) + +typedef struct Tuple {  	char *name;  	int type; -	void *addr; -	struct Tuple *next; -}; +	void (*addr)(void *); +} TUPLE; -struct col_pair { -	int f; -	int b; -}; +typedef struct NcursesDevice { +	char *ttyname; +	char *input; +	char *output; +	SCREEN *screen; +} NCURSDEV; -struct Form { -	int status; -	int no_fields; -	char *startfield; -	struct Field *current_field; -	struct Field *prev_field; +typedef struct NcursesWindow { +	WINDOW *win; +} NCURSES_WINDOW; + +typedef struct Display { +	DisplayType type;  	int height;  	int width; -	int y; -	int x; -	int attr; -	char *colortable; -	WINDOW *window; -	hash_table *bindings; -}; +	int virt_height; +	int virt_width; +	union { +		NCURSDEV *ncurses; +	} device; +	hash_table *bind; +} DISPLAY; -struct TextField { +typedef struct ActionObject {  	char *text; -}; +	char *action; +} ACTION_OBJECT; -struct ActionField { -	char *text; +typedef struct CompoundObject { +	char *defobj; +} COMPOUND_OBJECT; + +typedef struct FunctionObject {  	char *fn; -}; +} FUNCTION_OBJECT; -struct InputField { +typedef struct InputObject {  	int lbl_flag;  	char *label;  	char *input;  	int limit; -}; +} INPUT_OBJECT; -struct MenuField { +typedef struct MenuObject {  	int selected;  	int no_options;  	char **options; -}; - -struct help_link { -}; +} MENU_OBJECT; -struct Field { -	char *defname; -	char *enter; -	char *leave; -	int type; +typedef struct TextObject { +	char *text; +} TEXT_OBJECT; + +typedef union { +	NCURSES_WINDOW *ncurses; +} WIN; + +typedef union { +		ACTION_OBJECT *action; +		COMPOUND_OBJECT *compound; +		FUNCTION_OBJECT *function; +		INPUT_OBJECT  *input; +		MENU_OBJECT   *menu; +		TEXT_OBJECT   *text; +} OBJ_TYPE; + +typedef struct Object { +	ObjectType type; +	int status; +	struct Object *parent;  	int y;  	int x;  	int height;  	int width; -	int attr; -	int selattr; -	char *fnext; -	char *fup; -	char *fdown; -	char *fleft; -	char *fright; -	char *f_keymap; -	union { -		struct TextField *text; -		struct ActionField *action; -		struct InputField *input; -		struct MenuField *menu; -	}field; -	/* -	struct help_link help; -	*/ -}; - -/* Externally visible keymap table for user-definable keymaps */ -extern unsigned int keymap[]; - -/* Externally visible function declarations */ -struct Form *form_start(char *); -struct Tuple *form_get_tuple(hash_table *, char *, TupleType); -int form_bind_tuple(hash_table *, char *, TupleType, void *); -void print_status(char *); -void exit_form(struct Form *form); -void cancel_form(struct Form *form); -void print_status(char *); -int add_menu_option(struct MenuField *, char *); +	char *attributes; +	char *highlight; +	char *lnext; +	char *lup; +	char *ldown; +	char *lleft; +	char *lright; +	char *UserDrawFunc; +	char *UserProcFunc; +	char *OnEntry; +	char *OnExit; +	OBJ_TYPE object; +	hash_table *bind; +	struct Display *display; +	WIN window; +} OBJECT; + +/* Externally visible variables */ +extern hash_table *root_table; + +/* Function declarations */ +__inline struct Tuple *get_tuple(hash_table *, char *, TupleType); +TUPLE *tuple_search(OBJECT *, char *, TupleType); +int bind_tuple(hash_table *, char *, TupleType, void(*fn)()); +int add_menu_option(MENU_OBJECT *, char *); +void draw_box(OBJECT *); +void draw_shadow(OBJECT *); + +#endif /* _FORMS_H_ */ diff --git a/lib/libforms/internal.h b/lib/libforms/internal.h index f91b83956d15..ba38601f7b0f 100644 --- a/lib/libforms/internal.h +++ b/lib/libforms/internal.h @@ -32,45 +32,60 @@   *   */ -#define FK_UP		f_keymap[0] -#define FK_DOWN		f_keymap[1] -#define FK_RIGHT	f_keymap[2] -#define FK_LEFT		f_keymap[3] -#define FK_NEXT		f_keymap[4] -#define FK_CLEFT	f_keymap[5] -#define FK_CRIGHT	f_keymap[6] -#define FK_CHOME	f_keymap[7] -#define FK_CEND		f_keymap[8] -#define FK_CBS		f_keymap[9] -#define FK_CDEL		f_keymap[10] -#define FK_ACCEPT	f_keymap[11] +/* Object status values */ +#define O_VISIBLE	0x0001 +#define O_ACTIVE	0x0002 -extern unsigned int f_keymap[]; +/* Standard attribute commands */ +typedef enum { +	ATTR_BOX, +	ATTR_CENTER, +	ATTR_RIGHT, +	ATTR_SHADOW, +	ATTR_UNKNOWN +} AttrType; + +struct attr_cmnd { +	char *attr_name; +	AttrType attr_type; +}; + +/* Ncurses color pairs */ +typedef struct color_pair { +	int no; +	int fg; +	int bg; +} COLPAIR; + +extern struct attr_cmnd attr_cmnds[]; + +extern hash_table  *root_table, *cbind; +extern DISPLAY *cdisp; +extern int lineno;  /* Private function declarations */ -void display_field(WINDOW *, struct Field *); -void display_text(WINDOW *, struct Field *); -void display_input(WINDOW *, struct Field *); -void display_menu(WINDOW *, struct Field *); -void display_action(WINDOW *, struct Field *); -int print_string(WINDOW *, int, int, int, int, char *); -unsigned int do_key_bind(struct Form *, unsigned int); -int do_action(struct Form *); -int do_menu(struct Form *); -int do_input(struct Form *); -int init_field(char *, void *, void *); -int calc_string_width(char *); -void calc_field_height(struct Field *, char *); +int display_tuples(char *, void *, void *); +int refresh_displays(char *, void *, void *); +int copy_object_tree(char *, void *, void *); +void process_tuple(OBJECT *); +void process_object(OBJECT *); +void process_input_object(OBJECT *); +void process_menu_object(OBJECT *); +void process_text_object(OBJECT *); + +DISPLAY *default_open(DISPLAY *); +DISPLAY *ncurses_open(DISPLAY *); -#ifdef not -static void show_form(struct form *); -static void disp_text(struct form *); -static void disp_menu(struct form *); -static void disp_action(struct form *); -static void disp_input(struct form *); -static void field_menu(struct form *); -static void field_input(struct form *); -static void field_action(struct form *); -static int print_string(WINDOW *, int, int, int, int, char *); -static int next_field(struct form *form, int); -#endif +int ncurses_print_string(OBJECT *, char *); +void ncurses_print_status(char *); +int ncurses_bind_key(OBJECT *, unsigned int); +void ncurses_display_action(OBJECT *); +void ncurses_display_compound(OBJECT *); +void ncurses_display_function(OBJECT *); +void ncurses_display_input(OBJECT *); +void ncurses_display_menu(OBJECT *); +void ncurses_display_text(OBJECT *); +void ncurses_process_action(OBJECT *); +void ncurses_process_input(OBJECT *); +void ncurses_process_menu(OBJECT *); +void ncurses_process_text(OBJECT *); diff --git a/lib/libforms/lex.l b/lib/libforms/lex.l index 24e2e38c2503..7aa03512ef7b 100644 --- a/lib/libforms/lex.l +++ b/lib/libforms/lex.l @@ -32,6 +32,8 @@   * SUCH DAMAGE.   *   */ + +#include <string.h>  #include <unistd.h>  #include "y.tab.h" @@ -40,56 +42,81 @@ extern int charno;  extern int off;  %} +NUM		[0-9]+ +  %% -colortable		{ return COLORTABLE; } -colourtable		{ return COLORTABLE; } -Colors			{ return COLOR; } -Colours			{ return COLOR; } -black			{ return BLACK; } -red				{ return RED; } -green			{ return GREEN; } -yellow			{ return YELLOW; } -blue			{ return BLUE; } -magenta			{ return MAGENTA; } -cyan			{ return CYAN; } -white			{ return WHITE; } -pair			{ return PAIR; } -Form			{ return FORM; } -at				{ return AT; } +!Forms			{ return FORMS; } +Action			{ return ACTION; } +Active			{ return ACTIVE; }  as				{ return AS; } -height			{ return HEIGHT; } -=				{ return EQUALS; } -width			{ return WIDTH; } -start			{ return STARTFIELD; } -text			{ return TEXT; } -attributes		{ return ATTR; } -highlight		{ return SELATTR; } -label			{ return LABEL; } -default			{ return DEFAULT; } -limit			{ return LIMIT; } -selected		{ return SELECTED; } -options			{ return OPTIONS; } -action			{ return ACTION; } -function		{ return FUNC; } -up				{ return UP; } -down			{ return DOWN; } -left			{ return LEFT; } -right			{ return RIGHT; } -next			{ return NEXT; } +at				{ return AT; } +Attributes		{ return ATTR; } +AttrTable		{ return ATTRTABLE; } +CallFunc		{ return CALLFUNC; } +ColorPairs		{ return COLORPAIRS; } +Default			{ return DEFAULT; } +Display			{ return A_DISPLAY; } +Down			{ return DOWN; } +Forms			{ return FORMS; } +Function		{ return FUNCTION; } +Height			{ return HEIGHT; } +Highlight		{ return HIGHLIGHT; } +Input			{ return INPUT; } +InputFile		{ return INPUTFILE; } +Label			{ return LABEL; } +Left			{ return LEFT; } +Limit			{ return LIMIT; } +Menu			{ return MENU; } +Ncurses			{ return NCURSES; } +Next			{ return NEXT; } +Object			{ return AN_OBJECT; } +on				{ return ON; } +OnEntry			{ return ONENTRY; } +OnExit			{ return ONEXIT; } +Options			{ return OPTIONS; } +OutputFile		{ return OUTPUTFILE; } +Right			{ return RIGHT; } +Selected		{ return SELECTED; } +Text			{ return TEXT; } +Ttyname			{ return TTYNAME; } +Type			{ return TYPE; } +Up				{ return UP; } +Use				{ return USE; } +UserDrawFunc	{ return USERDRAWFUNC; } +UserProcFunc	{ return USERPROCFUNC; } +Version			{ return VERSION; } +Width			{ return WIDTH; } +Window			{ return WINDOW; } + +Black			{ return BLACK; } +Red				{ return RED; } +Green			{ return GREEN; } +Yellow			{ return YELLOW; } +Blue			{ return BLUE; } +Magenta			{ return MAGENTA; } +Cyan			{ return CYAN; } +White			{ return WHITE; } +  ,				{ return COMMA; }  \{				{ return LBRACE; }  \}				{ return RBRACE; } -[0-9]+			{ yylval.ival = atoi(yytext); return NUMBER; } -[A-Za-z_][A-Za-z0-9_()|&]*		{ yylval.sval = yytext; return NAME; } -\"[^"]* { -			if (yytext[yyleng-1] == '\\') { -				yymore(); -			} else { -				input(); -				yylval.sval = yytext+1; +;				{ return SEMICOLON; } + +{NUM}+			{ yylval.ival = atoi(yytext); return NUMBER; } + +[A-Za-z_][A-Za-z0-9_.]*		{ yylval.sval = strdup(yytext); +							  free(yytext); +							  return NAME; +							 } + +\"[^"]+\"   {  +				yytext[strlen(yytext)-1] = '\0'; +				yylval.sval = strdup(yytext + 1); +				free(yytext);  				return STRING;  			} -		} +  \n				{ lineno++; }  #.*				{ /* Ignored (comment) */; }  [ \t\f]*		{ /* Ignored (white space) */; } + diff --git a/lib/libforms/parser.y b/lib/libforms/parser.y index 401e991b12d1..31093e91697d 100644 --- a/lib/libforms/parser.y +++ b/lib/libforms/parser.y @@ -37,73 +37,29 @@  #include <stdlib.h>  #include <string.h>  #include <stdio.h> +#include <ncurses.h>  #include <forms.h>  #include <err.h>  #include "internal.h" -char *cpstr(char *); -  extern int yyleng;  int lineno = 1; -int charno = 1; -int off; - -char *fieldname; -char *defname; -char *formname; -char *startname; -char *colortable; -int formattr; -char *text; -char *label; -char *function; -char *up, *down, *left, *right, *next; -int height, width; -int y, x; -int width; -int limit; -int attr; -int selattr; -int type; -int lbl_flag; -int selected, no_options=0; - -extern FILE *outf; -extern hash_table *global_bindings; - -struct MenuList { -	char *option; -	struct MenuList *next; -}; - -struct MenuList *cur_menu; -struct MenuList *menu_list; -struct MenuList *menu; - -struct pair_node { -	char *foreground; -	char *background; -	struct pair_node *next; -}; -struct pair_node *pair_list; -struct pair_node *cur_pair; -struct pair_node *pair; - -struct color_table { -	char *tablename; -	struct pair_node *pairs; -	struct color_table *next; -}; - -struct color_table *color_table; -struct color_table *cur_table; -struct color_table *color_tables; - -struct Form *form; -struct Field *field_inst_list; -struct Field *field; -struct Field *cur_field; + +OBJECT *parent; +extern hash_table *cbind; + + +/* Some variables for holding temporary values as we parse objects */ + +OBJECT *object, *tmpobj; +DISPLAY *display; + +int tmp, len; +char *tmpstr, *objname, *dispname, *useobj; +TUPLE *tmptuple; +TupleType t_type; +  %}  %union { @@ -111,9 +67,49 @@ struct Field *cur_field;  	char *sval;  } -%token <ival> FORM -%token <ival> COLORTABLE -%token <ival> COLOR +%token <ival> ACTION +%token <ival> ACTIVE +%token <ival> AS +%token <ival> AT +%token <ival> ATTR +%token <ival> ATTRTABLE +%token <ival> CALLFUNC +%token <ival> COLORPAIRS +%token <ival> DEFAULT +%token <ival> A_DISPLAY +%token <ival> DOWN +%token <ival> FORMS +%token <ival> FUNCTION +%token <ival> HANDLER +%token <ival> HEIGHT +%token <ival> INPUT +%token <ival> INPUTFILE +%token <ival> LABEL +%token <ival> LEFT +%token <ival> LIMIT +%token <ival> MENU +%token <ival> NCURSES +%token <ival> NEXT +%token <ival> AN_OBJECT +%token <ival> ON +%token <ival> ONENTRY +%token <ival> ONEXIT +%token <ival> OPTIONS +%token <ival> OUTPUTFILE +%token <ival> RIGHT +%token <ival> HIGHLIGHT +%token <ival> SELECTED +%token <ival> TEXT +%token <ival> TTYNAME +%token <ival> TYPE +%token <ival> UP +%token <ival> USE +%token <ival> USERDRAWFUNC +%token <ival> USERPROCFUNC +%token <ival> VERSION +%token <ival> WIDTH +%token <ival> WINDOW +  %token <ival> BLACK  %token <ival> RED  %token <ival> GREEN @@ -122,308 +118,605 @@ struct Field *cur_field;  %token <ival> MAGENTA  %token <ival> CYAN  %token <ival> WHITE -%token <ival> PAIR -%token <sval> NAME -%token <sval> STRING -%token <ival> AT -%token <ival> AS -%token <ival> HEIGHT -%token <ival> EQUALS -%token <ival> NUMBER -%token <ival> WIDTH -%token <ival> STARTFIELD +  %token <ival> COMMA +%token <ival> SEMICOLON  %token <ival> LBRACE  %token <ival> RBRACE -%token <ival> TEXT -%token <ival> ATTR -%token <ival> SELATTR -%token <ival> DEFAULT -%token <ival> LABEL -%token <ival> LIMIT -%token <ival> SELECTED -%token <ival> OPTIONS -%token <ival> ACTION -%token <ival> FUNC -%token <ival> LINK -%token <ival> UP -%token <ival> DOWN -%token <ival> LEFT -%token <ival> RIGHT -%token <ival> NEXT -%token <ival> DEF -%type <sval> a_color +%token <sval> NAME +%token <ival> NUMBER +%token <sval> STRING + +%type <ival> color -%start spec +%start forms  %% +forms: FORMS VERSION NAME spec +	{ +#ifdef DEBUG +		printf("Forms language version %s\n", $3); +#endif +	} +	; +  spec: /* empty */ -	| spec fields -	| spec forms -	| spec colours +	| spec display  +	| spec window +	| spec object  	; -colours: COLOR NAME  +display: A_DISPLAY NAME  		{ -			color_table = malloc(sizeof (struct color_table)); -			if (!color_table) { -				fprintf(stderr, "Couldn't allocate memory for a color table\n"); -				exit (1); -			} -			color_table->tablename = cpstr($2); +			dispname = $2; +			display = malloc(sizeof (DISPLAY)); +			if (!display) +				errx(-1, +					"Failed to allocate memory for display (%d)", lineno); +		} +	LBRACE HEIGHT NUMBER  +		{ +			display->virt_height = $6;  		} -	LBRACE color_pairs RBRACE +	WIDTH NUMBER   		{ -			color_table->pairs = pair_list; -			cur_pair = 0; -			form_bind_tuple(global_bindings, color_table->tablename, FT_COLTAB, color_table); +			display->virt_width = $9; +		} +	disp_type disp_attr_table RBRACE +		{ +			if (!display) +				errx(-1, "Failed to open display (%d)", lineno); +			bind_tuple(root_table, dispname, TT_DISPLAY, (FUNCP)display); +			dispname = 0;  		}  	; -color_pairs: /* empty */ -	| color_pairs pair +disp_type: /* empty */ +		{ +			display->type = DT_ANY; +			display->device = 0; +			display = default_open(display); +		} +	| TYPE NCURSES device_ncurses +		{ display->type = DT_NCURSES; }  	; -pair: PAIR EQUALS a_color +device_ncurses: /* empty */  		{ -			pair = malloc(sizeof (struct pair_node)); -			if (!pair) { -				fprintf(stderr, "Couldn't allocate memory for a color pair\n"); -				exit(1); -			} -			pair->foreground = cpstr($3); +			/* Use ncurses drivers but on a default tty */ +			display->device.ncurses = 0; +			display = ncurses_open(display);  		} -	COMMA a_color +	| LBRACE device_ncurses_tty   		{ -			pair->background = cpstr($6); -			if (!cur_pair) { -				pair_list = pair; -				cur_pair = pair; -			} else { -				cur_pair->next = pair; -				cur_pair = pair; -			} +			display = ncurses_open(display); +		} +	  device_ncurses_colors RBRACE +	; + +device_ncurses_tty: /* empty */ +		{ +			/* Use ncurses drivers but on a default tty */ +			display->device.ncurses = 0; +		} +	| TTYNAME STRING INPUTFILE STRING OUTPUTFILE STRING +		{ +			display->device.ncurses = (NCURSDEV *)malloc(sizeof (NCURSDEV)); +			if (!display->device.ncurses) +				errx(-1, "Failed to allocate memory for ncurses device (%d)", lineno); +			display->device.ncurses->ttyname = $2; +			display->device.ncurses->input = $4; +			display->device.ncurses->output = $6;  		}  	; -a_color: BLACK -		{ $$ = "COLOR_BLACK"; } +device_ncurses_colors: /* empty */ +	| COLORPAIRS LBRACE color_pairs RBRACE +	; + +color_pairs: /* empty */ +	| color_pairs color_pair +	; + +color_pair: NUMBER color color +	{ +		if (display) +			init_pair($1, $2, $3); +	} +	; + +color: BLACK +		{ $$ = COLOR_BLACK; }  	| RED -		{ $$ = "COLOR_RED"; } -	| GREEN -		{ $$ = "COLOR_GREEN"; } +		{ $$ = COLOR_RED; } +	| GREEN	 +		{ $$ = COLOR_GREEN; }  	| YELLOW -		{ $$ = "COLOR_YELLOW"; } +		{ $$ = COLOR_YELLOW; }  	| BLUE -		{ $$ = "COLOR_BLUE"; } +		{ $$ = COLOR_BLUE; }  	| MAGENTA -		{ $$ = "COLOR_MAGENTA"; } +		{ $$ = COLOR_MAGENTA; }  	| CYAN -		{ $$ = "COLOR_CYAN"; } +		{ $$ = COLOR_CYAN; }  	| WHITE -		{ $$ = "COLOR_WHITE"; } +		{ $$ = COLOR_WHITE; } +	;		 + +disp_attr_table: /* empty */ +		{ display->bind = 0; } +	| ATTRTABLE  +		{ +			display->bind = hash_create(0); +			if (!display->bind) +				errx(-1, "Failed to allocate memory for display bindings (%d)", lineno); +		} +	LBRACE disp_attrs RBRACE  	; -forms:  FORM NAME  -		 { formname = cpstr($2); } -	AT coord  +disp_attrs: /* empty */ +	| disp_attrs disp_attr +	; + +disp_attr: NAME NUMBER +		{ bind_tuple(display->bind, $1, TT_ATTR, (FUNCP)$2); } +	; + +window: WINDOW NAME ON NAME AT NUMBER COMMA NUMBER LBRACE +		{ +			objname = $2; +			dispname = $4; +			object = malloc(sizeof (OBJECT)); +			if (!object) +				errx(-1, "Failed to allocate memory for window (%d)", lineno); + +			object->y = $6; +			object->x = $8; +			object->status = O_VISIBLE; +			object->bind = hash_create(0); +			if (!object->bind) +				errx(-1, "Failed to allocate memory for window's bindings (%d)", lineno); +		} + object_params  		{ -			form = malloc(sizeof (struct Form)); -			if (!form) { -				fprintf(stderr,"Failed to allocate memory for form\n"); -				exit(1); +			tmptuple = tuple_search(object, dispname, TT_DISPLAY); +			if (!tmptuple) +				errx(-1, "Couldn't find binding for display (%d)", lineno); +			free(dispname); +			object->display = (struct Display *)tmptuple->addr; + +			switch (object->display->type) { +				case DT_NCURSES: +				default: +					object->window.ncurses = malloc(sizeof (NCURSES_WINDOW));	 +					if (!object->window.ncurses) +						errx(-1, "Failed to allocate memory for ncurses window, (%d)", lineno); +					ncurses_open_window(object); +					break;  			} -			form->bindings = hash_create(0); -			if (!form->bindings) -				errx(1, "Failed to allocate hash table for form"); -			form->y = y; -			form->x = x; +			object->parent = 0; +			if (!object->height) +				object->height = display->height; +			if (!object->width) +				object->width = display->width; +			bind_tuple(root_table, objname, TT_OBJ_INST, (FUNCP)object); +			parent = object; +			cbind = parent->bind;  		} -	LBRACE formspec RBRACE +	object RBRACE  		{ -			form->startfield = startname; -			form->colortable = colortable; -			form->height = height; -			form->width = width; -			form->attr = formattr; -			form_bind_tuple(global_bindings, formname, FT_FORM, form); +			parent = 0; +			cbind = root_table;  		}  	; -formspec: height width startfield colortable formattr fieldlocs +objects: /* empty */ +	| objects object  	; -startfield:	/* empty */ -		{	startname = 0;  -			printf("Warning: No start field specified for form %s\n", formname); +object: NAME +		 {  +			objname = $1; +			object = malloc(sizeof (OBJECT)); +			if (!object) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); + +			object->bind = hash_create(0); +			if (!object->bind) +				errx(-1, "Failed to allocate memory for ", +						 "object's bindings (%d)", lineno); +		} +	at LBRACE use_copy +		{ +			if (useobj) { +				/* Need to declare parent to see previous scope levels */ +				object->parent = parent; +				if (use_defined_object(object, useobj) == ST_NOBIND) +					errx(-1, "Object, %s, not found in scope (%d)", +						 useobj, lineno); +			} +		} +	object_params +		{ +			/* +			 * If this is a function object convert it from +			 * a definition to an instance (see 'at' below). +			 */ +			if (object->type == OT_FUNCTION) +				t_type = TT_OBJ_INST; + +			/* +			 * If this is an instance object and it doesn't +			 * have a parent then there's a syntax error since +			 * instances can only be specified inside windows. +			 */ +			if (parent) +				inherit_properties(object, parent); +			else if (t_type != TT_OBJ_DEF) +				errx(-1, "Object, %s, has no parent (%d)", objname, lineno); + +			/* Propagate defobj up through nested compounds */ +			if (t_type == TT_OBJ_INST && +				parent && parent->type == OT_COMPOUND && +				!parent->object.compound->defobj) +				parent->object.compound->defobj = +					strdup(objname); + +			/* Add object and go down to next object */ +			bind_tuple(cbind, objname, t_type, (FUNCP)object); +			parent = object; +			cbind = object->bind; +		} +	objects RBRACE +		{ +			parent = object->parent; +			if (parent) +				cbind = parent->bind; +			else +				cbind = root_table; +			object = parent;  		} -	| STARTFIELD EQUALS NAME -		{ startname = cpstr($3); }  	; -colortable: /*empty */ -		{ colortable = 0; } -	| COLORTABLE EQUALS NAME -		{ colortable = cpstr($3); } +at: /* empty */ +		{ +			/* +			 * If there's no 'at' part specified then this is +			 * either a definition rather than an instance of +			 * an object or it's a function. Set it to a definition, +			 * we deal with the function case above. +			 */ +			t_type = TT_OBJ_DEF; +			object->y = 0; +			object->x = 0; +		} +	| AT NUMBER COMMA NUMBER +		{ +			t_type = TT_OBJ_INST; +			object->y = $2; +			object->x = $4; +		}  	; -formattr: /* empty */ -		{ formattr = 0; } -	| ATTR EQUALS NUMBER -		{ formattr = $3; } +use_copy: /* empty */ +		{ useobj = 0; } +	| USE NAME  +		{ useobj = $2; }  	; -fieldlocs:	/* empty */ -	| fieldlocs field_at +object_params: user_draw_func user_proc_func height width attributes highlight on_entry on_exit links object_type  	; -field_at: NAME  -		 { fieldname = cpstr($1); } -	field_def AT coord -		{  -			field = malloc(sizeof (struct Field)); -			if (!field) { -				fprintf(stderr,"Failed to allocate memory for form field\n"); -				exit(1); -			} -			if (!defname) -				field->defname = fieldname; -			else -				field->defname = defname; -			field->y = y; -			field->x = x; -		} -	links +object_type: /* empty */  		{ -			field->fup = up; -			field->fdown = down; -			field->fleft = left; -			field->fright = right; -			field->fnext = next; -			up = 0; -			down = 0; -			left = 0; -			right = 0; -			next = 0; -			form_bind_tuple(form->bindings, fieldname, FT_FIELD_INST, field); +			/* If we haven't inherited a type assume it's a compound */ +			if (!object->type) { +				object->type = OT_COMPOUND; +				object->object.compound = malloc(sizeof (COMPOUND_OBJECT)); +				if (!object->object.compound) +					errx(-1, "Failed to allocate memory for object, (%d)\n", +						 lineno); +				object->object.compound->defobj = 0; +			}  		} +	| object_action +	| object_compound +	| object_function +	| object_input +	| object_menu +	| object_text  	; -fields: NAME  -		{ defname = cpstr($1); } -	field_spec -		{ define_field(defname); } +links: /* empty */ +	| links  conns  	; -field_def: /* empty */ -		{ defname = 0; } -	| LBRACE NAME  -		{ defname = cpstr($2); } -	  RBRACE -	| field_spec -		{ defname = fieldname; define_field(defname); } +conns: UP NAME +		{  +			if (object->lup) +				free(object->lup); +			object->lup = $2; +		} +	| DOWN NAME +		{  +			if (object->ldown) +				free(object->ldown); +			object->ldown = $2; +		} +	| LEFT NAME +		{  +			if (object->lleft) +				free(object->lleft); +			object->lleft = $2; +		} +	| RIGHT NAME +		{  +			if (object->lright) +				free(object->lright); +			object->lright = $2; +		} +	| NEXT NAME +		{  +			if (object->lnext) +				free(object->lnext); +			object->lnext = $2; +		}  	; -field_spec: LBRACE height width attr selattr type RBRACE -	; +/* + * Parse the action object type. + */ -links: /* empty */ -	| links COMMA conns +object_action: ACTION NAME LABEL STRING +	{ +		object->type = OT_ACTION; +		object->object.action = malloc(sizeof (ACTION_OBJECT)); +		if (!object->object.action) +			errx(-1, "Failed to allocate memory for object, (%d)\n", lineno); +		object->object.action->action = $2; +		object->object.action->text = $4; +		if (!object->width) +			object->width = calc_string_width(object->object.text->text); +		if (!object->height) +			calc_object_height(object, object->object.text->text); +	}  	; -conns: UP EQUALS NAME -		{ up = cpstr($3); } -	| DOWN EQUALS NAME -		{ down = cpstr($3); } -	| LEFT EQUALS NAME -		{ left = cpstr($3); } -	| RIGHT EQUALS NAME -		{ right = cpstr($3); } -	| NEXT EQUALS NAME -		{ next = cpstr($3); } -	; +/* + * Parse the compound object type. + */ -type: textfield -	| inputfield -	| menufield -	| actionfield +object_compound: ACTIVE NAME +	{ +		object->type = OT_COMPOUND; +		object->object.compound = malloc(sizeof (COMPOUND_OBJECT)); +		if (!object->object.compound) +			errx(-1, "Failed to allocate memory for object, (%d)\n", lineno); +		object->object.compound->defobj = $2; +	}  	; -textfield:	TEXT EQUALS STRING -			{ type = FF_TEXT; text = cpstr($3); } +/* + * Parse the function object type + */ + +object_function: CALLFUNC NAME  +		{ +			object->type = OT_FUNCTION; +			object->object.function = malloc(sizeof (FUNCTION_OBJECT)); +			if (!object->object.function) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); +			object->object.function->fn = $2; +		}  	; -inputfield:	inputspec -			{ type = FF_INPUT; } +/* + * Parse the input object type + */ + +object_input: INPUT +		{ +			object->type = OT_INPUT; +			object->object.input = malloc(sizeof (INPUT_OBJECT)); +			if (!object->object.input) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); +		} +	input_params limit +		{ +			/* Force height to 1 regardless */ +			object->height = 1; +			if (!object->width && !object->object.input->limit) { +				if (!object->object.input->label) +					errx(-1, "Unable to determine size of input object (%d)", +						lineno); +				object->width = calc_string_width(object->object.input->label); +				object->object.input->limit = object->width; +			} else if (!object->width) +				object->width = object->object.input->limit; +			else if (!object->object.input->limit) +				object->object.input->limit = object->width; +			if (object->object.input->limit < object->width) +				object->width = object->object.input->limit; + +			object->object.input->input =  +				malloc(object->object.input->limit + 1); +			if (!object->object.input->input) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); + +			/* +			 * If it's a label then clear the input string +			 * otherwise copy the default there. +			 */ + +			if (object->object.input->lbl_flag) +				object->object.input->input[0] = '\0'; +			else if (object->object.input->label) { +				tmp = strlen(object->object.input->label); +				strncpy(object->object.input->input, +					object->object.input->label, +					tmp); +				object->object.input->input[tmp] = 0; +			} +		}  	; -inputspec:	LABEL EQUALS STRING limit -			{ lbl_flag = 1; label = cpstr($3); } -	| DEFAULT EQUALS STRING limit -			{ lbl_flag = 0; label = cpstr($3); } +input_params: /* empty */  +		{ +			object->object.input->lbl_flag = 0; +			object->object.input->label = 0; +		} +	| STRING +		{ +			object->object.input->lbl_flag = 0; +			object->object.input->label = $1; +		} +	| DEFAULT STRING +		{ +			object->object.input->lbl_flag = 0; +			object->object.input->label = $2; +		} +	| LABEL STRING +		{ +			object->object.input->lbl_flag = 1; +			object->object.input->label = $2; +		}  	;  limit: /* empty */ -	| LIMIT EQUALS NUMBER -			{ limit = $3; } +		{ object->object.input->limit = 0; } +	| LIMIT NUMBER  +		{ object->object.input->limit = $2; } +	; -menufield: SELECTED EQUALS NUMBER OPTIONS EQUALS menuoptions -			{ type = FF_MENU; selected = $3; } +/* + * Parse the menu object type + */ + +object_menu: OPTIONS LBRACE  +		{ +			object->type = OT_MENU; +			object->object.menu = malloc(sizeof (MENU_OBJECT)); +			if (!object->object.menu) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); +			object->object.menu->no_options = 0; +			object->object.menu->options = 0; +			len = 0; +		} +	menuoptions  +		{ +			object->height = 1; +			if (!object->width) +				object->width = len; +		} +	RBRACE option_selected  	;  menuoptions: menuoption -	| menuoptions COMMA menuoption +	| menuoptions  menuoption  	;  menuoption: STRING -			{	 -				menu = malloc(sizeof(struct MenuList)); -				if (!menu) { -						err(1, "Couldn't allocate memory for menu option\n"); -				} -				menu->option = cpstr($1); -				if (!cur_menu) {   -					menu_list = menu; -					cur_menu = menu; -				} else { -					cur_menu->next = menu;  -					cur_menu = menu; -				} +			{ +				tmpstr = $1; +				object->object.menu->no_options =  +					add_menu_option(object->object.menu, tmpstr); +				if (!object->object.menu->no_options) +					errx(-1, "Failed to allocate memory for option (%d)", lineno); +				tmp = calc_string_width(tmpstr); +				if (tmp > len) +					len = tmp; +				free(tmpstr);  			} -; +	; + +option_selected: /* empty */ +		{ object->object.menu->selected = 0; } +	| SELECTED NUMBER  +		{ object->object.menu->selected = $2; } +	; + +/* + * Parse the text object type + */ + +object_text: TEXT STRING  +		{ +			object->type = OT_TEXT; +			object->object.text = malloc(sizeof (TEXT_OBJECT)); +			if (!object->object.text) +				errx(-1, "Failed to allocate memory for object (%d)", lineno); +			object->object.text->text = $2; +			if (!object->width) +				object->width = calc_string_width(object->object.text->text); +			if (!object->height) +				calc_object_height(object, object->object.text->text); +		} +	; + +user_draw_func: /* empty */ +	| USERDRAWFUNC NAME  +		{ +			if (object->UserDrawFunc) +				free(object->UserDrawFunc); +			object->UserDrawFunc = $2; +		} +	; -actionfield: ACTION EQUALS STRING FUNC EQUALS NAME -			{ type = FF_ACTION; text = cpstr($3); function = cpstr($6); } +user_proc_func: /* empty */ +	| USERPROCFUNC NAME  +		{ +			if (object->UserProcFunc) +				free(object->UserProcFunc); +			object->UserProcFunc = $2; +		}  	;  height: /* empty */ -		{ height = 0; } -	| HEIGHT EQUALS NUMBER -		{ height = $3; } +	| HEIGHT NUMBER  +		{ object->height = $2; }  	;  width: /* empty */ -			{ width = 0; } -	| WIDTH EQUALS NUMBER -			{ width = $3; } +	| WIDTH NUMBER  +			{ object->width = $2; }  	; -attr: /* empty */ -			{ attr = 0; } -	| ATTR EQUALS NUMBER -			{ attr = $3; } +attributes: /* empty */ +	| ATTR STRING  +		{ +			if (object->attributes) +				free(object->attributes); +			object->attributes = $2; +		}  	; -selattr: /* empty */ -			{ selattr = 0; } -	| SELATTR EQUALS NUMBER -			{ selattr = $3; } +highlight: /* empty */ +	| HIGHLIGHT STRING  +		{ +			if (object->highlight) +				free(object->highlight); +			object->highlight = $2; +		} +	; + +on_entry:	/* empty */ +	| ONENTRY NAME  +		{ +			if (object->OnEntry) +				free(object->OnEntry); +			object->OnEntry = $2; +		}  	; -coord: NUMBER COMMA NUMBER -		{ y = $1; x = $3; } +on_exit:	/* empty */ +	| ONEXIT NAME  +		{ +			if (object->OnExit) +				free(object->OnExit); +			object->OnExit = $2; +		}  	;  %% @@ -431,101 +724,5 @@ coord: NUMBER COMMA NUMBER  void  yyerror (char *error)  { -	fprintf(stderr, "%s at line %d\n",error, lineno); -	exit(1); -} - -char * -cpstr(char *ostr) -{ -	char *nstr; - -	nstr = malloc(strlen(ostr)+1); -	if (!nstr) { -		fprintf(stderr, "Couldn't allocate memory for string\n"); -		exit(1); -	} -	strcpy(nstr, ostr); -	return (nstr); -} - -void -define_field(char *defname) -{ -	struct Field *field; -	struct MenuList *menu_options; -	int no_options; - -	field = malloc(sizeof (struct Field)); -	if (!field) { -		fprintf(stderr,"Failed to allocate memory for form field\n"); -		exit(1); -	} -	field->defname = defname; -	field->type = type; -	field->height = height; -	field->width = width; -	field->attr = attr; -	field->selattr = selattr; -	switch (type) { -		case FF_TEXT: -			field->field.text = malloc(sizeof (struct TextField)); -			if (!field->field.text) { -				fprintf(stderr, -						"Failed to allocate memory for text field\n"); -				exit (1); -			} -			field->field.text->text = text; -			break; -		case FF_INPUT: -			field->field.input = malloc(sizeof (struct InputField)); -			if (!field->field.input) { -				fprintf(stderr, -						"Failed to allocate memory for input field\n"); -				exit (1); -			} -			field->field.input->lbl_flag = lbl_flag; -			field->field.input->label = label; -			field->field.input->limit = limit; -			break; -		case FF_MENU: -			printf("field type %s = %d\n", defname,field->type); -			field->field.menu = malloc(sizeof (struct MenuField)); -			if (!field->field.menu) { -				fprintf(stderr, -						"Failed to allocate memory for menu field\n"); -				exit (1); -			} -			field->field.menu->selected = selected; -			menu_options = menu_list; -			field->field.menu->no_options = 0; -			field->field.menu->options = 0; -			for (; menu_options; menu_options = menu_options->next) { -				no_options = add_menu_option(field->field.menu, -											 menu_options->option); -				if (!no_options) -					err(1, "Couldn't add menu option"); -			} -			field->field.menu->no_options = no_options; -			cur_menu = 0; -			break; -		case FF_ACTION: -			field->field.action = malloc(sizeof (struct ActionField)); -			if (!field->field.action) { -				fprintf(stderr, -						"Failed to allocate memory for action field\n"); -				exit (1); -			} -			field->field.action->text = text; -			field->field.action->fn = (void *) function; -			break; -		default: -			break; -	} -	form_bind_tuple(global_bindings, defname, FT_FIELD_DEF, field); -	width=0; -	height = 0; -	attr=0; -	selattr=0; -	limit=0; +	errx(-1, "%s at line %d\n", error, lineno);  }  | 
