/* netrik -- The ANTRIK Internet Viewer Copyright (C) Olaf D. Buddenhagen AKA antrik, et al (see AUTHORS) Published under the GNU GPL; see LICENSE for details. */ /* * parse-struct.c -- this one takes the syntax parsing tree generated by * parse_syntax() and creates another structure called item_tree(). * * (C) 2001, 2002, 2003 antrik * 2002 Patrice Neff * * This item tree containes items as they are visible on the screen: text * blocks, blank lines, boxes aligning several other items etc. */ #include #include #include #include #include "colors.h" #include "forms.h" #include "items.h" #include "syntax.h" /* all information specific for every parse tree depth */ struct State { int visible; /* content inside this element will be displayed in output page */ enum Text_mode text_mode; /* content encountered now will be stored in this mode */ int high; /* highlighted text (additional to "text_mode") */ int list_depth; /* nesting depth of item lists */ struct Item *first_item; /* first item at this tree depth */ struct Item *last_item; /* presently last item at this tree depth */ enum Form_control link_type; /* indicates type of link/form element (-1: no link) */ char *link_value; /* initial value of form element */ int form_enabled; /* form element may be submitted */ char *select_name; /* name assigned to all options inside a element */ /* get "value" */ if(value_attr>=0) /* has "value" attribute */ cur_state->link_value=cur_el->attr[value_attr].value.str; else if(cur_el->list_next!=NULL && cur_el->list_next->content!=NULL) { /* no "value" attribute, but content */ char *content=cur_el->list_next->content; if(*content==' ') /* skip space at beginning (workaround incorrect space handling) */ ++content; cur_state->link_value=content; } else /* no "value" nor content */ cur_state->link_value=""; if(selected_attr>=0) /* initially on */ cur_state->form_enabled=1; add_text(NULL, 0); /* force new div */ add_text("?", color_map[TM_FORM]^(cur_state->high<<3)); /* (will be overwritten...) */ break; } case EL_BUTTON: { const int type_attr=find_attr(cur_el, ATTR_TYPE); const char *type= type_attr>=0 ? cur_el->attr[type_attr].value.str : NULL; if(type==NULL || !strcasecmp(type, "submit")) { /* submit button (default) */ const int value_attr=find_attr(cur_el, ATTR_VALUE); cur_state->link_type=FORM_SUBMIT; cur_state->link_value= value_attr>=0 ? cur_el->attr[value_attr].value.str :""; add_text(NULL, 0); /* force new div */ add_text("[", color_map[TM_FORM]^(cur_state->high<<3)); cur_state->text_mode=TM_LINK; } else { /* reset or push button -> no action */ add_text("(", color_map[TM_FORM]^(cur_state->high<<3)); cur_state->text_mode=TM_FORM; } break; } case EL_TEXTAREA: { const int cols_attr=find_attr(cur_el, ATTR_COLS); const int size= (cols_attr >= 0 && cur_el->attr[cols_attr].value.num > 0) ? cur_el->attr[cols_attr].value.num : 50; /* gather initial value form content (stored in subelements) */ { char *value=NULL; int value_len=0; struct Element *sub_el; for(sub_el=cur_el->list_next; sub_el->parent==cur_el; sub_el=sub_el->list_next) { /* all direct children */ if(sub_el->content) { const int new_len=value_len+strlen(sub_el->content); value=realloc(value, new_len+1); if(value==NULL) { fprintf(stderr, "Memory allocation error while parsing structure (in function parse_struct)\n"); exit(1); } strcpy(&value[value_len], sub_el->content); value_len=new_len; } /* has content */ } /* for all direct children */ cur_state->link_value=value; } cur_state->link_type=FORM_TEXTAREA; cur_state->form_enabled=1; add_text("[[", color_map[TM_FORM]^(cur_state->high<<3)); { char line_buf[size+1]; memset(line_buf, '\xa0', size); line_buf[size]=0; add_text(line_buf, color_map[TM_NORMAL]^(cur_state->high<<3)); } add_text("]]", color_map[TM_FORM]^(cur_state->high<<3)); break; } case EL_IMG: { const int alt_attr=find_attr(cur_el, ATTR_ALT); if(alt_attr>=0) { add_text("[", color_map[TM_IMG]^(cur_state->high<<3)); add_text(cur_el->attr[alt_attr].value.str, color_map[cur_state->text_mode==TM_LINK?TM_LINK:TM_IMG]^(cur_state->high<<3)); add_text("]", color_map[TM_IMG]^(cur_state->high<<3)); } else { add_text("(", color_map[TM_IMG]^(cur_state->high<<3)); if(cur_state->text_mode==TM_LINK) add_text("*", color_map[TM_LINK]^(cur_state->high<<3)); add_text(")", color_map[TM_IMG]^(cur_state->high<<3)); } break; } default: /* html, body, p, center, pre, table, dd, div, span, no, global */ break; } /* switch element type */ /* ascend to depth of next element (no ascend if next element is child of current (keep the descend), ascend once if at same level (undo the descend), ascend more than once if above current) */ for(new_el=cur_el; new_el!=cur_el->list_next->parent; new_el=new_el->parent) { /* ascend until parent of next element found */ struct State *old_state; /* state before ascending */ switch(new_el->name.type) { case EL_TR: add_text("-", color_map[TM_SYS]); /* put indicator after every table row */ break; case EL_TD: case EL_TH: { const int span_attr=find_attr(new_el, ATTR_COLSPAN); int i; if(span_attr>=0) /* has colspan */ for(i=1; iattr[span_attr].value.str); ++i) /* all but first spanned cell */ add_text("(|)", color_map[TM_SYS]); /* put indicator for cells left out due to the span */ break; } case EL_DL: --cur_state->list_depth; break; case EL_DT: add_text(":", color_map[TM_SYS]^(cur_state->high<<3)); /* put definition indicator after definiton term */ break; case EL_INS: add_text("+]", color_map[TM_SYS]^(cur_state->high<<3)); break; case EL_DEL: case EL_S: case EL_STRIKE: add_text("-]", color_map[TM_SYS]^(cur_state->high<<3)); break; case EL_FORM: add_text(">", color_map[TM_FORM]^(cur_state->high<<3)); break; case EL_SELECT: if(cur_state->select_type==FORM_MULTIOPTION) add_text("}", color_map[TM_FORM]^(cur_state->high<<3)); else add_text(")", color_map[TM_FORM]^(cur_state->high<<3)); break; case EL_BUTTON: if((signed)cur_state->link_type >= 0) /* active button (submit) */ add_text("]", color_map[TM_FORM]^(cur_state->high<<3)); else /* reset or push button */ add_text(")", color_map[TM_FORM]^(cur_state->high<<3)); break; default: /* html, body, h1-h6, p, em, i, strong, b, center, a, br, pre, table, ul, li, ol, dl, dd, hr, form, input, option, div, span, no, global */ break; } /* switch element type */ /* links */ if((signed)cur_state->link_type>=0 && (string_item!=NULL || cur_state->link_item!=NULL)) { /* has link, and valid (inside text block) -> add link */ struct String *string; /* string where link will be stored */ int link_end; /* position inside string where link ends */ int new_link; /* link number in string's link table */ if(cur_state->link_item!=NULL) /* link began inside some string -> store in this one */ string=cur_state->link_item->data.string; else { /* link began outside string -> store in current string (that's the best we can do -- normally, this is the one where link begins...) */ string=string_item->data.string; cur_state->link_start=0; /* start at string start */ } link_end=string->div[string->div_count-1].end; /* string end (normally that's the current string position; if link started in other string, truncates to end of that string) */ new_link=string->link_count; /* nested links workaround */ if(string->link_count && cur_state->link_start <= string->link[string->link_count-1].start) { /* nested links (link not first, and starts before last link) */ /* find position where link belongs (after last link starting before current) */ for(new_link=string->link_count; new_link>0; --new_link) if(cur_state->link_start > string->link[new_link-1].start) /* found */ break; link_end=string->link[new_link].start; /* truncate to beginning of next link */ } /* workaround incorrect space handling so activated links will be highlighted (more or less) correctly */ if(string->text[cur_state->link_start]==' ') { /* ' ' at link start -> move start behind the ' ' */ if(cur_state->link_start>0 && !(string->link_count && string->link[string->link_count-1].end==cur_state->link_start)) { /* can't handle links starting at string start or immediately following other links */ int start_div; /* first div of link */ /* also move div start (if not already moved by some other (nested) link...) */ for(start_div=1; start_divdiv_count; ++start_div) { /* find first div of link */ if(string->div[start_div-1].end==cur_state->link_start) { /* found */ ++string->div[start_div-1].end; break; } } ++cur_state->link_start; } /* possible */ } /* move link start past ' ' */ if(link_end > cur_state->link_start) { /* link not empty -> store */ add_text(NULL, 0); /* force new div */ /* resize link table of string */ string->link=realloc(string->link, ++string->link_count*sizeof(struct Link)); if(string->link==NULL) { fprintf(stderr, "memory allocation error while parsing structure (in function parse_struct)\n"); exit(1); } /* nested links workaround */ if(new_link < string->link_count-1) { /* not inserted as last -> move all links after new_link one position behind */ int link; for(link=string->link_count-1; link>new_link; --link) string->link[link]=string->link[link-1]; } /* store link */ string->link[new_link].start=cur_state->link_start; /* starting position saved before */ string->link[new_link].end=link_end; string->link[new_link].form=cur_state->link_type; string->link[new_link].enabled=cur_state->form_enabled; string->link[new_link].name=NULL; if(cur_state->link_value==NULL) cur_state->link_value=""; string->link[new_link].value.size=strlen(cur_state->link_value); string->link[new_link].value.data=strdup(cur_state->link_value); if(string->link[new_link].value.data==NULL) { fprintf(stderr, "memory allocation error while parsing structure (in function parse_struct)\n"); exit(1); } if(cur_state->link_type!=FORM_NO) { /* form element */ set_form(string, &string->link[new_link]); /* display initial value */ if(cur_state->id_attr >= 0) { /* has "name"/"id" -> store that (currently used by form handling for simplicity) */ string->link[new_link].name=strdup(new_el->attr[cur_state->id_attr].value.str); if(string->link[new_link].name==NULL) { fprintf(stderr, "memory allocation error while parsing structure (in function parse_struct)\n"); exit(1); } } else if(cur_state->select_name!=NULL) { /* no "name"/"id", but name inherited from