diff options
Diffstat (limited to 'lib/libforms')
-rw-r--r-- | lib/libforms/Makefile | 2 | ||||
-rw-r--r-- | lib/libforms/examples/example.c | 16 | ||||
-rw-r--r-- | lib/libforms/examples/example.frm | 9 | ||||
-rw-r--r-- | lib/libforms/fields.c | 210 | ||||
-rw-r--r-- | lib/libforms/forms.c | 147 | ||||
-rw-r--r-- | lib/libforms/forms.h | 20 | ||||
-rw-r--r-- | lib/libforms/internal.h | 5 | ||||
-rw-r--r-- | lib/libforms/menu.c | 1 | ||||
-rw-r--r-- | lib/libforms/parser.y | 57 |
9 files changed, 321 insertions, 146 deletions
diff --git a/lib/libforms/Makefile b/lib/libforms/Makefile index 5fbe510..b6ce006 100644 --- a/lib/libforms/Makefile +++ b/lib/libforms/Makefile @@ -2,7 +2,7 @@ LIB = forms SRCS = forms.c parser.y lex.l menu.c fields.c -CFLAGS += -I. -I${.CURDIR} -Wall -g +CFLAGS += -I. -I${.CURDIR} -Wall -g -DHASH_STATS LDFLAGS += -ll beforeinstall: diff --git a/lib/libforms/examples/example.c b/lib/libforms/examples/example.c index f2dad1c..447d846 100644 --- a/lib/libforms/examples/example.c +++ b/lib/libforms/examples/example.c @@ -32,8 +32,11 @@ * */ #include <stdio.h> +#include "../hash.h" #include "../forms.h" +extern hash_table *global_bindings; + main() { struct Tuple *tuple; @@ -42,8 +45,6 @@ main() initscr(); - form_bind_tuple("exit_form", FT_FUNC, &exit_form); - form_bind_tuple("cancel_form", FT_FUNC, &cancel_form); if (form_load("example.frm") == FS_ERROR) exit(0);; @@ -59,7 +60,7 @@ main() cbreak(); noecho(); - tuple = form_get_tuple("example", FT_FORM); + tuple = form_get_tuple(global_bindings, "example", FT_FORM); if (!tuple) err(0, "No such form"); else @@ -67,6 +68,9 @@ main() print_status("This is the status line"); + 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) { @@ -79,11 +83,11 @@ main() if (form->status == FS_EXIT) { printf("You're entries were:\n\n"); - tuple = form_get_tuple("input1", FT_FIELD_INST); + 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("input2", FT_FIELD_INST); + 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("menu1", FT_FIELD_INST); + 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]); diff --git a/lib/libforms/examples/example.frm b/lib/libforms/examples/example.frm index d1f5349..f28b2c6 100644 --- a/lib/libforms/examples/example.frm +++ b/lib/libforms/examples/example.frm @@ -1,9 +1,14 @@ -field1 { attributes = 0 text = "This text is bold and flashy" } +Colours example_colors { + pair = red, yellow + pair = blue, white +} + +field1 { attributes = 0 text = "\standout This text is \bold bold and \blink flashy" } field2 { height = 2 width = 22 - text = "This is an input field with a default" + text = "This is an input fieldwith a default" } field3 { diff --git a/lib/libforms/fields.c b/lib/libforms/fields.c index 3656834..bafb21b 100644 --- a/lib/libforms/fields.c +++ b/lib/libforms/fields.c @@ -32,6 +32,7 @@ * */ +#include <hash.h> #include <ctype.h> #include <err.h> #include <ncurses.h> @@ -41,23 +42,43 @@ #include "internal.h" +extern hash_table *global_bindings; + +struct attr_cmd { + char *name; + int attr; +}; + +static struct attr_cmd attr_cmds[] = { + { "standout", 0x00010000}, + { "underline", 0x00020000}, + { "reverse", 0x00040000}, + { "blink", 0x00080000}, + { "bold", 0x00200000 } +}; + int done=0; int -init_field(struct Field *field) +init_field(char *key, void *data, void *arg) { - struct Tuple *tuple; - struct Field *def; + struct Tuple *tuple = (struct Tuple *)data; + struct Tuple *def_tuple; + struct Field *def, *field; int i; int len, lim; + int strwidth; - tuple = form_get_tuple(field->defname, FT_FIELD_DEF); - if (!tuple) { + field = (struct Field *)tuple->addr; + + /* Field definitions are global, at least for now */ + def_tuple = form_get_tuple(global_bindings, field->defname, FT_FIELD_DEF); + if (!def_tuple) { warnx("Field definition not found -- skipping field"); return (-1); } - def = (struct Field *)tuple->addr; + def = (struct Field *)def_tuple->addr; field->height = def->height; field->width = def->width; field->attr = def->attr; @@ -75,7 +96,7 @@ init_field(struct Field *field) /* Force height to one regardless, at least for now :-) */ field->height = 1; if (!field->width && !field->field.input->limit) { - field->width = strlen(def->field.input->label); + field->width = calc_string_width(def->field.input->label); field->field.input->limit = field->width; } else if (!field->width) field->width = field->field.input->limit; @@ -84,19 +105,20 @@ init_field(struct Field *field) if (field->field.input->limit < field->width) field->width = field->field.input->limit; - field->field.input->input = malloc(field->field.input->limit + 1); + strwidth = strlen(def->field.input->label); + field->field.input->input = malloc(strwidth + 1); if (!field->field.input->input) { warnx("Couldn't allocate memory for input field text"); return (-1); } - field->field.input->label = malloc(strlen(def->field.input->label)+1); + field->field.input->label = malloc(strwidth + 1); if (!field->field.input->label) { warnx("Couldn't allocate memory for input field label"); return (-1); } strncpy(field->field.input->label, def->field.input->label, - strlen(def->field.input->label) + 1); + strwidth + 1); field->field.input->lbl_flag = def->field.input->lbl_flag; /* @@ -107,9 +129,9 @@ init_field(struct Field *field) field->field.input->input[0] = '\0'; else if (field->field.input->label) { strncpy(field->field.input->input, - field->field.input->label, - field->field.input->limit); - field->field.input->input[field->field.input->limit] = 0; + field->field.input->label, + strwidth + 1); + field->field.input->input[strwidth] = 0; } break; case FF_TEXT: @@ -118,16 +140,17 @@ init_field(struct Field *field) warnx("Couldn't allocate memory for text field"); return (FS_ERROR); } + strwidth = strlen(def->field.text->text); if (!field->width) - field->width = strlen(def->field.text->text); - field->field.text->text = malloc(field->width + 1); + field->width = calc_string_width(def->field.text->text); + field->field.text->text = malloc(strwidth + 1); if (!field->field.text->text) { warnx("Couldn't allocate memory for text field text"); return (FS_ERROR); } else strncpy(field->field.text->text, def->field.text->text, - field->width + 1); + strwidth + 1); if (!field->height) calc_field_height(field, field->field.text->text); break; @@ -148,7 +171,7 @@ init_field(struct Field *field) warnx("Couldn't add menu option"); return (FS_ERROR); } - len = strlen(def->field.menu->options[i]); + len = calc_string_width(def->field.menu->options[i]); if (len > lim) lim = len; } @@ -162,15 +185,16 @@ init_field(struct Field *field) return (FS_ERROR); } if (!field->width) - field->width = strlen(def->field.action->text); - field->field.action->text = malloc(field->width + 1); + field->width = calc_string_width(def->field.action->text); + strwidth = strlen(def->field.action->text); + field->field.action->text = malloc(strwidth + 1); if (!field->field.action->text) { warnx("Couldn't allocate memory for text field text"); return (FS_ERROR); } else strncpy(field->field.action->text, def->field.action->text, - field->width + 1); + strwidth + 1); if (!field->height) calc_field_height(field, field->field.action->text); field->field.action->fn = def->field.action->fn; @@ -178,7 +202,7 @@ init_field(struct Field *field) default: break; } - return (0); + return (1); } void @@ -263,7 +287,7 @@ do_action(struct Form *form) ch = wgetch(form->window); if (ch == FK_ACCEPT) { - tuple = form_get_tuple(field->field.action->fn, FT_FUNC); + tuple = form_get_tuple(form->bindings, field->field.action->fn, FT_FUNC); if (!tuple) { print_status("No function bound to action"); beep(); @@ -303,6 +327,7 @@ do_menu(struct Form *form) field->field.menu->selected++; if (field->field.menu->selected >= field->field.menu->no_options) field->field.menu->selected = 0; + ch = FS_OK; break; default: ch = do_key_bind(form, ch); @@ -325,9 +350,21 @@ do_menu(struct Form *form) int do_field(struct Form *form) { + struct Tuple *tuple; struct Field *field = form->current_field; + void (* fn)(); int status; + /* Do field entry tasks */ + if (field->enter) { + tuple = form_get_tuple(form->bindings, field->enter, FT_FUNC); + + if (tuple) { + fn = tuple->addr; + (*fn)(form); + } + } + switch (field->type) { case FF_TEXT: status = FS_OK; @@ -350,14 +387,53 @@ do_field(struct Form *form) break; } + /* Do field leave tasks */ + if (field->leave) { + tuple = form_get_tuple(form->bindings, field->leave, FT_FUNC); + + if (tuple) { + fn = tuple->addr; + (*fn)(form); + } + } + return (status); } int +parse_attr(WINDOW *window, char *string) +{ + int inc = 0; + struct attr_cmd *attr; + + if (*(string) == '\\') + return (1); + + while (!isspace(*(string + inc))) { + inc++; + } + + for (attr = attr_cmds; attr->name; attr++) { + if (strncmp(attr->name, string, inc)) + continue; + else { + wattron(window, attr->attr); + break; + } + } + + /* Skip trailing space after the attribute string */ + while (isspace(*(string + inc))) + inc++; + + return (inc); +} + +int print_string(WINDOW *window, int y, int x, int height, int fwidth, char *string) { - int len; + int len, skip; int width; if (!string) @@ -371,15 +447,20 @@ print_string(WINDOW *window, int y, int x, width = fwidth; while (width--) { if (len-- > 0) { + if (*string == '\\') { + string++; + len--; + skip = parse_attr(window, string); + len -= skip; + string += skip; + } if (waddch(window, *string++) == ERR) return (ERR); - } else - if (waddch(window, ' ') == ERR) + } else if (waddch(window, ' ') == ERR) return (ERR); } if (wmove(window, ++y, x) == ERR) return (ERR); - } return (OK); } @@ -507,6 +588,83 @@ do_input(struct Form *form) } } +/* + * Calculate length of printable part of the string, + * stripping out the attribute modifiers. + */ + +int +calc_string_width(char *string) +{ + int len, width=0; + + if (!string) + return (0); + + len = strlen(string); + + while (len) { + if (*string != '\\') { + width++; + len--; + string++; + continue; + } else { + string++; + len--; + if (*string == '\\') { + string++; + width++; + len--; + continue; + } else { + while (!isspace(*string)) { + string++; + len--; + } + while (isspace(*string)) { + string ++; + len--; + } + } + } + } + + return (width); +} + +/* Calculate a default height for a field */ + +void +calc_field_height(struct Field *field, char *string) +{ + + int len; + + len = calc_string_width(string); + + if (!field->width) { + /* + * This is a failsafe, this routine shouldn't be called + * with a width of 0, the width should be determined + * first. + */ + field->height = 1; + return; + } + + if (len < field->width) { + field->height = 1; + return; + } else + field->height = len / field->width; + + if ((field->height*field->width) < len) + field->height++; + + return; +} + void exit_form(struct Form *form) { diff --git a/lib/libforms/forms.c b/lib/libforms/forms.c index a51c95e..a7207be 100644 --- a/lib/libforms/forms.c +++ b/lib/libforms/forms.c @@ -32,6 +32,7 @@ * */ +#include <hash.h> #include <stdio.h> #include <stdlib.h> #include <forms.h> @@ -42,8 +43,7 @@ extern FILE *yyin; -struct Tuple *fbind_first; -struct Tuple *fbind_last; +hash_table *global_bindings; unsigned int f_keymap[] = { KEY_UP, /* F_UP */ @@ -65,6 +65,11 @@ form_load(const char *filename) { FILE *fd; + global_bindings = hash_create(0); + + if (!global_bindings) + return (FS_ERROR); + if (!(fd = fopen(filename, "r"))) { warn("Couldn't open forms file %s", filename); return (FS_ERROR); @@ -78,17 +83,40 @@ form_load(const char *filename) return (FS_ERROR); } + hash_stats(global_bindings, 1); + return (FS_OK); } +int +find_editable(char *key, void *data, void *arg) +{ + struct Tuple *tuple = (struct Tuple *)data; + struct Field *field; + + if (tuple->type != FT_FIELD_INST) + return (1); + + field = (struct Field *)tuple->addr; + + if ((field->type == FF_INPUT) || + (field->type == FF_MENU) || + (field->type == FF_ACTION)) { + arg = field; + return (0); + } else + return (1); +} + struct Form * -form_start(const char *formname) +form_start(char *formname) { struct Tuple *tuple; struct Form *form; - struct Field *field; + struct Field *field = 0; + struct Field *start = 0; - tuple = form_get_tuple(formname, FT_FORM); + tuple = form_get_tuple(global_bindings, formname, FT_FORM); if (!tuple) { warnx("No such form"); @@ -109,22 +137,24 @@ form_start(const char *formname) return (0); } - tuple = form_get_tuple(form->startfield, FT_FIELD_INST); + /* Initialise the field instances */ + + hash_traverse(form->bindings, init_field, field); + + tuple = form_get_tuple(form->bindings, form->startfield, FT_FIELD_INST); if (!tuple) { warnx("No start field specified"); - /* XXX should search for better default start */ - form->current_field = form->fieldlist; + /* Search for an editable field */ + hash_traverse(form->bindings, &find_editable, start); + form->current_field = start; } else form->current_field = (struct Field *)tuple->addr; - form->prev_field = form->current_field; - - /* Initialise the field instances */ + if (!form->current_field) + errx(1, "No suitable start field found, aborting"); - for (field = form->fieldlist; field; field = field->next) { - init_field(field); - } + form->prev_field = form->current_field; form->status = FS_RUNNING; @@ -132,7 +162,7 @@ form_start(const char *formname) } int -form_bind_tuple(char *name, TupleType type, void *addr) +form_bind_tuple(hash_table *htable, char *name, TupleType type, void *addr) { struct Tuple *tuple; @@ -147,54 +177,71 @@ form_bind_tuple(char *name, TupleType type, void *addr) tuple->addr = addr; tuple->next = 0; - - if (!fbind_first) { - fbind_first = tuple; - fbind_last = tuple; - } else { + if (!htable) + return (FS_ERROR); + else { /* Check there isn't already a tuple of this type with this name */ - if (form_get_tuple(name, type)) { + if (form_get_tuple(htable, name, type)) { warn("Duplicate tuple name, %s, skipping", name); return (FS_ERROR); - } - fbind_last->next = tuple; - fbind_last = tuple; + } else + hash_search(htable, tuple->name, tuple, NULL); } return (0); } -struct Tuple * -form_get_tuple(const char *name, TupleType type) +int +tuple_match_any(char *key, struct Tuple *tuple, TupleType *type) { - return (form_next_tuple(name, type, fbind_first)); + if (tuple->type != *type) { + type = 0; + return (1); + } else { + type = (TupleType *)tuple; + return (0); + } } struct Tuple * -form_next_tuple(const char *name, TupleType type, struct Tuple *tuple) +form_get_tuple(hash_table *htable, char *key, TupleType type) { - for (; tuple; tuple = tuple->next) { - if (type != FT_ANY) - if (tuple->type != type) - continue; - if (name) - if (strcmp(name, tuple->name)) - continue; - return (tuple); + 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); } +} + +int +show_field(char *key, void *data, void *arg) +{ + struct Tuple *tuple = (struct Tuple *)data; + struct Field *field = (struct Field *)tuple->addr; + + display_field(arg, field); + + return (1); - return (0); } int -form_show(const char *formname) +form_show(char *formname) { struct Tuple *tuple; struct Form *form; - struct Field *field; int x, y; - tuple = form_get_tuple(formname, FT_FORM); + tuple = form_get_tuple(global_bindings, formname, FT_FORM); if (!tuple) return (FS_NOBIND); @@ -206,9 +253,7 @@ form_show(const char *formname) for (x=0; x < form->width; x++) mvwaddch(form->window, y, x, ' '); - for (field = form->fieldlist; field; field = field->next) { - display_field(form->window, field); - } + hash_traverse(form->bindings, show_field, form->window); return (FS_OK); } @@ -223,35 +268,35 @@ do_key_bind(struct Form *form, unsigned int ch) if (ch == FK_UP) { if (field->fup) { - tuple = form_get_tuple(field->fup, FT_FIELD_INST); + 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(field->fdown, FT_FIELD_INST); + 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(field->fleft, FT_FIELD_INST); + 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(field->fright, FT_FIELD_INST); + 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(field->fnext, FT_FIELD_INST); + tuple = form_get_tuple(form->bindings, field->fnext, FT_FIELD_INST); if (!tuple) print_status("Field to move to next does not exist"); } else @@ -270,12 +315,13 @@ do_key_bind(struct Form *form, unsigned int ch) } } +#ifdef DEBUG_NOT_YET void -debug_dump_bindings() +debug_dump_bindings(hash_table *htable) { struct Tuple *binds; - binds = form_get_tuple(0, FT_ANY); + 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); @@ -292,3 +338,4 @@ void debug_dump_form(struct Form *form) printf("%s, %x, next = %x\n", field->defname, (int)field, (int)field->next); } } +#endif diff --git a/lib/libforms/forms.h b/lib/libforms/forms.h index 636b55c..ae1c06d 100644 --- a/lib/libforms/forms.h +++ b/lib/libforms/forms.h @@ -80,7 +80,6 @@ struct Form { char *startfield; struct Field *current_field; struct Field *prev_field; - struct Field *fieldlist; int height; int width; int y; @@ -88,6 +87,7 @@ struct Form { int attr; char *colortable; WINDOW *window; + hash_table *bindings; }; struct TextField { @@ -117,6 +117,8 @@ struct help_link { struct Field { char *defname; + char *enter; + char *leave; int type; int y; int x; @@ -136,7 +138,6 @@ struct Field { struct InputField *input; struct MenuField *menu; }field; - struct Field *next; /* struct help_link help; */ @@ -146,18 +147,11 @@ struct Field { extern unsigned int keymap[]; /* Externally visible function declarations */ -struct Form *form_start(const char *); -struct Tuple *form_get_tuple(const char *, TupleType); -struct Tuple *form_next_tuple(const char *, TupleType, struct Tuple *); -int form_bind_tuple(char *, TupleType, void *); +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); - - -#ifdef not -int update_form(struct form *); -int initfrm(struct form *); -void endfrm(struct form *); void print_status(char *); -#endif +int add_menu_option(struct MenuField *, char *); diff --git a/lib/libforms/internal.h b/lib/libforms/internal.h index 96b099c..f91b8395 100644 --- a/lib/libforms/internal.h +++ b/lib/libforms/internal.h @@ -58,8 +58,9 @@ 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(struct Field *); - +int init_field(char *, void *, void *); +int calc_string_width(char *); +void calc_field_height(struct Field *, char *); #ifdef not static void show_form(struct form *); diff --git a/lib/libforms/menu.c b/lib/libforms/menu.c index d2beb44..9f373b4 100644 --- a/lib/libforms/menu.c +++ b/lib/libforms/menu.c @@ -32,6 +32,7 @@ * */ +#include <hash.h> #include <forms.h> #include <stdlib.h> #include <string.h> diff --git a/lib/libforms/parser.y b/lib/libforms/parser.y index 93e6008..4078797 100644 --- a/lib/libforms/parser.y +++ b/lib/libforms/parser.y @@ -32,6 +32,9 @@ * SUCH DAMAGE. * */ + +#include "hash.h" + #include <stdlib.h> #include <string.h> #include <stdio.h> @@ -68,6 +71,7 @@ int lbl_flag; int selected, no_options=0; extern FILE *outf; +extern hash_table *global_bindings; struct MenuList { char *option; @@ -175,7 +179,7 @@ colours: COLOR NAME { color_table->pairs = pair_list; cur_pair = 0; - form_bind_tuple(color_table->tablename, FT_COLTAB, color_table); + form_bind_tuple(global_bindings, color_table->tablename, FT_COLTAB, color_table); } ; @@ -232,6 +236,9 @@ forms: FORM NAME fprintf(stderr,"Failed to allocate memory for form\n"); exit(1); } + form->bindings = hash_create(0); + if (!form->bindings) + errx(1, "Failed to allocate hash table for form"); form->y = y; form->x = x; } @@ -242,9 +249,7 @@ forms: FORM NAME form->height = height; form->width = width; form->attr = formattr; - form->fieldlist = field_inst_list; - field_inst_list = 0; - form_bind_tuple(formname, FT_FORM, form); + form_bind_tuple(global_bindings, formname, FT_FORM, form); } ; @@ -298,20 +303,12 @@ field_at: NAME field->fleft = left; field->fright = right; field->fnext = next; - if (!field_inst_list) - field_inst_list = field; up = 0; down = 0; left = 0; right = 0; next = 0; - if (!cur_field) - cur_field = field; - else { - cur_field->next = field; - cur_field = field; - } - form_bind_tuple(fieldname, FT_FIELD_INST, field); + form_bind_tuple(form->bindings, fieldname, FT_FIELD_INST, field); } ; @@ -453,38 +450,6 @@ cpstr(char *ostr) return (nstr); } -/* Calculate a default height for a field */ - -void -calc_field_height(struct Field *field, char *string) -{ - - int len; - - len = strlen(string); - - if (!field->width) { - /* - * This is a failsafe, this routine shouldn't be called - * with a width of 0, the width should be determined - * first. - */ - field->height = 1; - return; - } - - if (len < field->width) { - field->height = 1; - return; - } else - field->height = len / field->width; - - if ((field->height*field->width) < len) - field->height++; - - return; -} - void define_field(char *defname) { @@ -558,7 +523,7 @@ define_field(char *defname) default: break; } - form_bind_tuple(defname, FT_FIELD_DEF, field); + form_bind_tuple(global_bindings, defname, FT_FIELD_DEF, field); width=0; height = 0; attr=0; |