%{ /*- * Copyright (c) 1995 * Paul Richards. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Paul Richards. * 4. The name Paul Richards may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include char *cpstr(char *); extern int yyleng; int lineno = 1; int charno = 1; int off; char *fieldname; char *defname; char *formname; char *startname; char *colortable; char *formattr; char *text; char *label; char *function; char *up, *down, *left, *right, *next; int height, width; int y, x; int width; int limit; char *attr; char *selattr; int type; int lbl_flag; int selected, no_options=0; extern FILE *outf; struct field_list { char *fieldname; char *defname; char *attr; char *selattr; char *up; char *down; char *left; char *right; char *next; struct field field; struct field_list *next_field; }; struct field_list *cur_field_def; struct field_list *field_defs; struct field_list *field; struct field_list *cur_form_field; struct field_list *form_field_list; struct form_list { char *formname; struct form form; struct form_list *next; struct field_list *fields; char *startfield; char *formattr; char *colortable; }; struct form_list *cur_form; struct form_list *form_list; struct form_list *form; struct menu_list { char *option; struct menu_list *next; }; struct menu_list *cur_menu; struct menu_list *menu_list; struct menu_list *menu; struct color_list { char *foreground; char *background; struct color_list *next; }; struct color_list *pair; struct color_list *cur_pair; struct color_list *color_list; struct color_table { char *tablename; struct color_list *pairs; struct color_table *next; }; struct color_table *color_table; struct color_table *cur_table; struct color_table *color_tables; %} %union { int ival; char *sval; } %token FORM %token COLORTABLE %token COLOR %token BLACK %token RED %token GREEN %token YELLOW %token BLUE %token MAGENTA %token CYAN %token WHITE %token PAIR %token NAME %token STRING %token AT %token AS %token HEIGHT %token EQUALS %token NUMBER %token WIDTH %token STARTFIELD %token COMMA %token LBRACE %token RBRACE %token TEXT %token ATTR %token SELATTR %token DEFAULT %token LABEL %token LIMIT %token SELECTED %token OPTIONS %token ACTION %token FUNC %token LINK %token UP %token DOWN %token LEFT %token RIGHT %token NEXT %token DEF %type a_color %start spec %% spec: /* empty */ | spec fields | spec forms | spec colours ; colours: COLOR 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); } LBRACE color_pairs RBRACE { color_table->pairs = color_list; cur_pair = 0; if (!cur_table) { color_tables = color_table; cur_table = color_table; } else { cur_table->next = color_table; cur_table = color_table; } } ; color_pairs: /* empty */ | color_pairs pair ; pair: PAIR EQUALS a_color { pair = malloc(sizeof (struct color_list)); if (!pair) { fprintf(stderr, "Couldn't allocate memory for a color pair\n"); exit(1); } pair->foreground = cpstr($3); } COMMA a_color { pair->background = cpstr($6); if (!cur_pair) { color_list = pair; cur_pair = pair; } else { cur_pair->next = pair; cur_pair = pair; } } ; a_color: BLACK { $$ = "COLOR_BLACK"; } | RED { $$ = "COLOR_RED"; } | GREEN { $$ = "COLOR_GREEN"; } | YELLOW { $$ = "COLOR_YELLOW"; } | BLUE { $$ = "COLOR_BLUE"; } | MAGENTA { $$ = "COLOR_MAGENTA"; } | CYAN { $$ = "COLOR_CYAN"; } | WHITE { $$ = "COLOR_WHITE"; } ; forms: FORM NAME { formname = cpstr($2); } AT coord { form = malloc(sizeof (struct form_list)); if (!form) { fprintf(stderr,"Failed to allocate memory for form\n"); exit(1); } form->form.y = y; form->form.x = x; } LBRACE formspec RBRACE { form->startfield = startname; form->formname = formname; form->colortable = colortable; form->form.height = height; form->form.width = width; form->formattr = formattr; form->fields = form_field_list; cur_form_field = 0; if (!cur_form) { form_list = form; cur_form = form; } else { cur_form->next = form; cur_form = form; } } ; formspec: height width startfield colortable formattr fieldlocs ; startfield: /* empty */ { startname = 0; printf("Warning: No start field specified for form %s\n", formname); } | STARTFIELD EQUALS NAME { startname = cpstr($3); } ; colortable: /*empty */ { colortable = 0; } | COLORTABLE EQUALS NAME { colortable = cpstr($3); } ; formattr: /* empty */ { formattr = 0; } | ATTR EQUALS NAME { formattr = cpstr($3); } ; fieldlocs: /* empty */ | fieldlocs field_at ; field_at: NAME { fieldname = cpstr($1); } field_def AT coord { field = malloc(sizeof (struct field_list)); if (!field) { fprintf(stderr,"Failed to allocate memory for form field\n"); exit(1); } field->fieldname = fieldname; if (!defname) field->defname = fieldname; else field->defname = defname; field->field.y = y; field->field.x = x; } links { field->up = up; field->down = down; field->left = left; field->right = right; field->next = next; up = 0; down = 0; left = 0; right = 0; next = 0; if (!cur_form_field) { form_field_list = field; cur_form_field = field; } else { cur_form_field->next_field = field; cur_form_field = field; } } ; fields: NAME { defname = cpstr($1); } field_spec { define_field(defname, 0); } ; field_def: /* empty */ { defname = 0; } | LBRACE NAME { defname = cpstr($2); } RBRACE | field_spec { defname = fieldname; define_field(defname, 0); } ; field_spec: LBRACE height width attr selattr type RBRACE ; links: /* empty */ | links COMMA conns ; 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); } ; type: textfield | inputfield | menufield | actionfield ; textfield: TEXT EQUALS STRING { type = F_TEXT; text = cpstr($3); } ; inputfield: inputspec { type = F_INPUT; } ; inputspec: LABEL EQUALS STRING limit { lbl_flag = 1; label = cpstr($3); } | DEFAULT EQUALS STRING limit { lbl_flag = 0; label = cpstr($3); } ; limit: /* empty */ | LIMIT EQUALS NUMBER { limit = $3; } menufield: SELECTED EQUALS NUMBER OPTIONS EQUALS menuoptions { type = F_MENU; selected = $3; } ; menuoptions: menuoption | menuoptions COMMA menuoption ; menuoption: STRING { menu = malloc(sizeof(struct menu_list)); if (!menu) { fprintf(stderr, "Couldn't allocate memory for menu option\n"); exit (1); } menu->option = cpstr($1); ++no_options; if (!cur_menu) { menu_list = menu; cur_menu = menu; } else { cur_menu->next = menu; cur_menu = menu; } } ; actionfield: ACTION EQUALS STRING FUNC EQUALS NAME { type = F_ACTION; text = cpstr($3); function = cpstr($6); } ; height: /* empty */ { height = 0; } | HEIGHT EQUALS NUMBER { height = $3; } ; width: /* empty */ { width = 0; } | WIDTH EQUALS NUMBER { width = $3; } ; attr: /* empty */ { attr = 0; } | ATTR EQUALS NAME { attr = cpstr($3); } ; selattr: /* empty */ { selattr = 0; } | SELATTR EQUALS NAME { selattr = cpstr($3); } ; coord: NUMBER COMMA NUMBER { y = $1; x = $3; } ; %% yyerror (char *error) { fprintf(stderr, "%s at line %d\n",error, lineno); exit(1); } yywrap() { return(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); } output_field(struct field_list *fields, char *fieldname, FILE *outf) { struct menu_list *menu; int i, lim, len; switch(fields->field.type) { case F_TEXT: if (!fieldname) { if (!fields->field.width) fields->field.width = strlen(fields->field.field.text->text); if (!fields->field.height) calc_field_height(&fields->field, fields->field.field.text->text); fprintf(outf, "struct text_field %s = {\"%s\"};\n", fields->defname, fields->field.field.text->text); } break; case F_INPUT: /* Force height to one regardless */ fields->field.height = 1; if (!fields->field.width && !fields->field.field.input->limit) { fields->field.width = strlen(fields->field.field.input->label); fields->field.field.input->limit = fields->field.width; } else if (!fields->field.width) fields->field.width = fields->field.field.input->limit; else if (!fields->field.field.input->limit) fields->field.field.input->limit = fields->field.width; if (fields->field.field.input->limit < fields->field.width) fields->field.width = fields->field.field.input->limit; fprintf(outf, "struct input_field %s = {%d, \"%s\", 0, %d};\n", (fieldname)?fieldname:fields->defname, (fields->field.field.input->lbl_flag ? 1 : 0), fields->field.field.input->label, fields->field.field.input->limit); break; case F_MENU: /* Force height to one regardless */ fields->field.height = 1; if (!fieldname) { fprintf(outf, "char *%s_options[] = {", fields->defname); menu = (struct menu_list *)fields->field.field.menu->options; lim = 0; for (i=0; i < fields->field.field.menu->no_options - 1; i++) { fprintf(outf, "\"%s\", ", menu->option); len = strlen(menu->option); if (len > lim) lim = len; menu = menu->next; } if (!fields->field.width) fields->field.width = lim; fprintf(outf, "\"%s\"};\n", menu->option); } fprintf(outf, "struct menu_field %s = {%d, %d, %s_options};\n", (fieldname)?fieldname:fields->defname, fields->field.field.menu->no_options, fields->field.field.menu->selected, fields->defname); break; case F_ACTION: if (!fields->field.width) fields->field.width = strlen(fields->field.field.action->text); if (!fields->field.height) calc_field_height(&fields->field, fields->field.field.action->text); fprintf(outf, "struct action_field %s = {\"%s\", &%s};\n", (fieldname)?fieldname:fields->defname, fields->field.field.action->text, fields->field.field.action->fn); break; default: break; } } output_forms(FILE *outf) { struct form_list *forms; struct field_list *fields; /* Output the general field definitions */ for (fields = field_defs; fields; fields=fields->next_field) output_field(fields, 0, outf); for(forms=form_list; forms; forms = forms->next) { parse_form(forms, outf); } } output_coltab(struct color_table *coltab, FILE *outf) { struct color_list *pairs; /* Output the color pair table */ fprintf(outf, "struct col_pair %s_coltab[] = {\n",coltab->tablename); if (color_list) { for(pairs=coltab->pairs; pairs; pairs=pairs->next) fprintf(outf, "\t{%s, %s},\n", pairs->foreground, pairs->background); } else { /* Output a default color table */ fprintf(outf, "\t{7, 0}\n};"); } fprintf(outf, "\t{-1, -1}\n};\n\n"); } parse_form(struct form_list *form, FILE *outf) { struct field_list *fields; struct field_list *defs; struct field_list *info; struct color_table *coltab; char *fieldname; int no_fields = 0; /* If there's a color table defined find it and output it */ if (form->colortable) { for (coltab = color_tables; coltab; coltab = coltab->next) if (!strcmp(form->colortable, coltab->tablename)) { output_coltab(coltab, outf); break; } if (!coltab) { fprintf(stderr, "Color table for form %s not found\n", form->formname); form->colortable = 0; } } /* * Run through the specific instances of the fields referenced by * this form, filling in the link structures and outputing a field * definition for this particular instance. */ for(fields=form->fields; fields; fields=fields->next_field) { /* Fill in link values */ fields->field.up = field_id(fields->up, form->fields); fields->field.down = field_id(fields->down, form->fields); fields->field.left = field_id(fields->left, form->fields); fields->field.right = field_id(fields->right, form->fields); fields->field.next = field_id(fields->next, form->fields); /* Search field list for definition of this field */ for(defs=field_defs; defs; defs=defs->next_field) { if (!strcmp(fields->defname, defs->defname)) break; } if (!defs) { fprintf(stderr, "%s not found in field definitions, field not output\n", fields->defname); fields->fieldname = 0; } else { fields->field.type = defs->field.type; fields->field.height = defs->field.height; fields->field.width = defs->field.width; fields->attr = defs->attr; fields->selattr = defs->selattr; if (strcmp(fields->defname, fields->fieldname)) output_field(defs, fields->fieldname, outf); } } /* Output the field table for this form */ fprintf(outf, "struct field %s_fields[] = {\n", form->formname); for(fields=form->fields; fields; fields=fields->next_field) { if (fields->fieldname) { ++no_fields; fprintf(outf, "\t{%d, %d, %d, %d, %d, %s, %s, ", fields->field.type, fields->field.y, fields->field.x, fields->field.height, fields->field.width, (fields->attr ? fields->attr : "F_DEFATTR"), (fields->selattr ? fields->selattr : "F_SELATTR")); fprintf(outf, "%d, %d, %d, %d, %d, ", fields->field.next, fields->field.up, fields->field.down, fields->field.left, fields->field.right); fprintf(outf, "(struct text_field *)&%s},\n", fields->fieldname); } } fprintf(outf, "\t{%d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}\n};\n", F_END); /* If no start field set then find first non-text field */ if (!form->startfield) for (fields = form->fields; fields; fields = fields->next_field) if (fields->field.type != F_TEXT) { form->startfield = fields->fieldname; break; } fprintf(outf, "struct form %s = {%d, %d, %d, %s_fields, %d, %d, %d, %d, %s, ", form->formname, no_fields, field_id(form->startfield, form->fields), field_id(form->startfield, form->fields), form->formname, form->form.height, form->form.width, form->form.y, form->form.x, (form->formattr ? form->formattr : "F_DEFATTR")); if (form->colortable) fprintf(outf, "%s_coltab, ", form->colortable); else fprintf(outf, "0, "); fprintf(outf, "0};\n\n"); } /* * Search a field list for a particular fieldname * and return an integer id for that field based on * it's position in the list [0..n]. Return -1 if * there's no match. */ int field_id(char *fieldname, struct field_list *field_list) { struct field_list *fields; int id=0; /* If the strings null then fail immediately */ if (!fieldname) return (-1); for (fields = field_list; fields; fields = fields->next_field, id++) { if (!strcmp(fieldname, fields->fieldname)) return (id); } fprintf(stderr, "Field %s, not found in specification\n", fieldname); return (-1); } /* Calculate a default height for a field */ 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; } /* Add a field to the pre-defined fields list */ define_field(char *defname, char *fieldname) { field = malloc(sizeof (struct field_list)); if (!field) { fprintf(stderr,"Failed to allocate memory for form field\n"); exit(1); } field->fieldname = fieldname; field->defname = defname; field->field.type = type; field->field.height = height; field->field.width = width; field->attr = attr; field->selattr = selattr; switch (type) { case F_TEXT: field->field.field.text = malloc(sizeof (struct text_field)); if (!field->field.field.text) { fprintf(stderr, "Failed to allocate memory for text field\n"); exit (1); } field->field.field.text->text = text; break; case F_INPUT: field->field.field.input = malloc(sizeof (struct input_field)); if (!field->field.field.input) { fprintf(stderr, "Failed to allocate memory for input field\n"); exit (1); } field->field.field.input->lbl_flag = lbl_flag; field->field.field.input->label = label; field->field.field.input->limit = limit; break; case F_MENU: field->field.field.menu = malloc(sizeof (struct menu_field)); if (!field->field.field.menu) { fprintf(stderr, "Failed to allocate memory for menu field\n"); exit (1); } field->field.field.menu->selected = selected; field->field.field.menu->no_options = no_options; no_options = 0; field->field.field.menu->options = (char **)menu_list; cur_menu = 0; break; case F_ACTION: field->field.field.action = malloc(sizeof (struct action_field)); if (!field->field.field.action) { fprintf(stderr, "Failed to allocate memory for action field\n"); exit (1); } field->field.field.action->text = text; field->field.field.action->fn = (void *) function; break; default: break; } if (!cur_field_def) { field_defs = field; cur_field_def = field; } else { cur_field_def->next_field = field; cur_field_def = field; } width=0; height = 0; attr=0; selattr=0; limit=0; }