Exemple #1
0
bool
find(Area **ap, Frame **fp, int dir, bool wrap, bool stack) {
    Rectangle r;
    Frame *f;
    Area *a;

    f = *fp;
    a = *ap;
    r = f ? f->r : a->r;

    if(dir == North || dir == South) {
        *fp = stack_find(a, f, dir, stack);
        if(*fp)
            return true;
        if(!a->floating)
            *ap = area_find(a->view, r, dir, wrap);
        if(!*ap)
            return false;
        *fp = stack_find(*ap, *fp, dir, stack);
        return true;
    }
    if(dir != East && dir != West)
        die("not reached");
    *ap = area_find(a->view, r, dir, wrap);
    if(!*ap)
        return false;
    *fp = ap[0]->sel;
    return true;
}
Exemple #2
0
const char *html_parse_stream(HtmlParseState *state, const char *stream, const char *token, size_t len) {
	//TODO: support entities
	//TODO: support more xml bullcrap, like CDATA

	#define ADVANCE_TOKEN token = stream; \
		state->stringlen = 0; \
		state->space = 0

	char c;
	char *text;

	HtmlElement *elem_tmp;
	HtmlAttrib *attrib_tmp;
	size_t i;

	if(!(state && stream && len))
		return NULL;

	for(i = 0; i < len; i++) {
		c = *stream++;
		reswitch:
		switch(state->state) {
			case STATE_CHILD:
				switch(c) {
					case '<':
						//add containing text
						if(state->stringlen) {
							if(state->stringlen > 1 || !isspace(*token)) {
								text = stringduplicate_length(token, state->stringlen);

								if(!(elem_tmp = html_new_element(HTML_TAG_NONE, NULL, NULL, NULL, NULL, NULL, text)))
									goto error;
								if(state->elem) {
									state->elem->sibling = elem_tmp;
									state->elem->sibling->count = state->elem->count + 1;
									state->elem->sibling->parent = state->elem->parent;
									state->elem = elem_tmp;
								} else {
									state->elem = stack_peek(&state->stack);
									state->elem->child = elem_tmp;
									state->elem->child->parent = state->elem;
									state->elem = elem_tmp;
								}
							}
						}
						ADVANCE_TOKEN;
						state->state = STATE_OPEN;
						//tag = 0;
						continue;
					CASE_SPACE:
						if(html_tag_is_script(state->tag)) {
							ADVANCE_TOKEN;
						} else if(!state->space) {
							state->space = 1;
							state->stringlen++;
						}
						continue;
					default:
						if(html_tag_is_script(state->tag)) {
							ADVANCE_TOKEN;
						} else {
							state->space = 0;
							state->stringlen++;
						}
						continue;
				}
			case STATE_OPEN:
				if(html_tag_is_script(state->tag)) {
					/*I hate script tags*/
					if(c != '/') {
						ADVANCE_TOKEN;
						state->state = STATE_CHILD;
						continue;
					}
				}
				switch(c) {
					CASE_SPACE:
						ADVANCE_TOKEN;
						/*testing this*/
						//state = STATE_CHILD;
						continue;

					/*Comments, doctypes, xml-stuff and other crap we don't care about*/
					case '!':
						ADVANCE_TOKEN;
						state->state = STATE_DECLARATION;
						continue;
					case '?':
						state->state = STATE_BEGIN;
						continue;

					case '/':
						ADVANCE_TOKEN;
						state->state = STATE_END;
						continue;
					default:
						state->state = STATE_BEGIN;
						continue;
				}
			case STATE_DECLARATION:
				ADVANCE_TOKEN;
				switch(c) {
					case '-':
						state->state = STATE_COMMENT_BEGIN;
						continue;
					default:
						state->state = STATE_END_CLOSE;
						continue;
				}
			case STATE_COMMENT_BEGIN:
				ADVANCE_TOKEN;
				state->state = STATE_COMMENT;
				continue;
			case STATE_COMMENT:
			case STATE_COMMENT_END1:
				ADVANCE_TOKEN;
				switch(c) {
					case '-':
						state->state++;
						continue;
					default:
						state->state = STATE_COMMENT;
						continue;
				}
			case STATE_COMMENT_END2:
				ADVANCE_TOKEN;
				switch(c) {
					case '>':
						state->state = STATE_CHILD;
						continue;
					default:
						state->state = STATE_COMMENT;
						continue;
				}
			case STATE_BEGIN:
				switch(c) {
					CASE_SPACE:
						state->tag = html_lookup_length_tag(token, (stream - 1) - token);
						state->tag_name = stringduplicate_length(token, (stream - 1) - token);
						state->state = STATE_ATTRIB;
						ADVANCE_TOKEN;
						continue;
					case '>':
						state->tag = html_lookup_length_tag(token, (stream - 1) - token);
						state->tag_name = stringduplicate_length(token, (stream - 1) - token);
						state->state = STATE_CLOSE;
						ADVANCE_TOKEN;
						goto reswitch;
					case '/':
						state->tag = html_lookup_length_tag(token, (stream - 1) - token);
						state->tag_name = stringduplicate_length(token, (stream - 1) - token);
						state->state = STATE_SELFCLOSE;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
			case STATE_ATTRIB:
				switch(c) {
					CASE_SPACE:
						ADVANCE_TOKEN;
						continue;
					case '/':
					case '?':
						state->state = STATE_SELFCLOSE;
						ADVANCE_TOKEN;
						continue;
					case '>':
						state->state = STATE_CLOSE;
						ADVANCE_TOKEN;
						goto reswitch;
					default:
						state->state = STATE_ATTRIB_KEY;
						continue;
				}
			case STATE_ATTRIB_KEY:
				switch(c) {
					CASE_SPACE:
						//key key
						state->attrib_key = html_lookup_length_attrib_key(token, (stream - 1) - token);
						state->attrib_key_name = stringduplicate_length(token, (stream - 1) - token);
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, NULL, 0);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_ATTRIB;
						ADVANCE_TOKEN;
						continue;
					case '>':
						state->attrib_key = html_lookup_length_attrib_key(token, (stream - 1) - token);
						state->attrib_key_name = stringduplicate_length(token, (stream - 1) - token);
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, NULL, 0);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_CLOSE;
						ADVANCE_TOKEN;
						goto reswitch;
					case '/':
						state->attrib_key = html_lookup_length_attrib_key(token, (stream - 1) - token);
						state->attrib_key_name = stringduplicate_length(token, (stream - 1) - token);
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, NULL, 0);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_SELFCLOSE;
						ADVANCE_TOKEN;
						continue;
					case '=':
						state->attrib_key = html_lookup_length_attrib_key(token, (stream - 1) - token);
						state->attrib_key_name = stringduplicate_length(token, (stream - 1) - token);
						state->state = STATE_ATTRIB_VALUE;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
			case STATE_ATTRIB_VALUE:
				switch(c) {
					CASE_SPACE:
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, token, (stream - 1) - token);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_ATTRIB;
						ADVANCE_TOKEN;
						continue;
					case '>':
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, token, (stream - 1) - token);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_CLOSE;
						ADVANCE_TOKEN;
						goto reswitch;
					case '\'':
						state->state = STATE_ATTRIB_QUOTE_SINGLE;
						ADVANCE_TOKEN;
						continue;
					case '"':
						state->state = STATE_ATTRIB_QUOTE_DOUBLE;
						ADVANCE_TOKEN;
						continue;
					case '/':
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, token, (stream - 1) - token);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_SELFCLOSE;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
			case STATE_ATTRIB_QUOTE_SINGLE:
				switch(c) {
					case '\'':
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, token, (stream - 1) - token);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_ATTRIB;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
				break;
			// TODO: This is very redundant to the code above, try to optimize later
			case STATE_ATTRIB_QUOTE_DOUBLE:
				switch(c) {
					case '"':
						attrib_tmp = html_new_element_attrib(state->attrib_key, state->attrib_key_name, token, (stream - 1) - token);
						attrib_append(&state->attrib, attrib_tmp);
						attrib_tmp = NULL;

						state->state = STATE_ATTRIB;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
				break;
			case STATE_CLOSE:
				switch(c) {
					case '>':
						ADVANCE_TOKEN;
						if(html_tag_is_script(state->tag)) {
							state->state = STATE_CHILD;
							continue;
						}
						//add to stack
						if(!(elem_tmp = html_new_element(state->tag, state->tag_name, state->attrib, NULL, NULL, NULL, NULL)))
							goto error;
						if(state->elem) {
							state->elem->sibling = elem_tmp;
							state->elem->sibling->count = state->elem->count + 1;
							state->elem->sibling->parent = state->elem->parent;
							state->elem = elem_tmp;
						} else {
							state->elem = stack_peek(&state->stack);
							state->elem->child = elem_tmp;
							state->elem->child->parent = state->elem;
							state->elem = elem_tmp;
						}

						if(!html_tag_is_selfclose(state->tag)) {
							stack_push(&state->stack, state->elem);
							state->elem = NULL;
						}
						state->tag = 0;
						state->tag_name = 0;
						state->attrib = 0;
						state->attrib_key_name = 0;

						state->state = STATE_CHILD;
						continue;
					default:
						ADVANCE_TOKEN;
						continue;
				}
			case STATE_SELFCLOSE:
				switch(c) {
					case '>':
						ADVANCE_TOKEN;
						if(html_tag_is_script(state->tag)) {
							state->state = STATE_CHILD;
							continue;
						}
						//add to stack
						if(!(elem_tmp = html_new_element(state->tag, state->tag_name, state->attrib, NULL, NULL, NULL, NULL)))
							goto error;
						if(state->elem) {
							state->elem->sibling = elem_tmp;
							state->elem->sibling->count = state->elem->count + 1;
							state->elem->sibling->parent = state->elem->parent;
							state->elem = elem_tmp;
						} else {
							state->elem = stack_peek(&state->stack);
							state->elem->child = elem_tmp;
							state->elem->child->parent = state->elem;
							state->elem = elem_tmp;
						}
						state->tag = 0;
						state->attrib = 0;
						state->attrib_key_name = 0;

						state->state = STATE_CHILD;
						continue;
					default:
						ADVANCE_TOKEN;
						continue;
				}
			case STATE_END:
				switch(c) {
					CASE_SPACE:
						//find tag to close
						if(html_tag_is_script(state->tag)) {
							if((stream - 1) - token > strlen(html_tag[state->tag]))
								state->state = STATE_CHILD;
							else if(html_lookup_length_tag(token, (stream - 1) - token) == state->tag) {
								state->tag = 0;
								state->state = STATE_END_CLOSE;
							} else
								state->state = STATE_CHILD;
							ADVANCE_TOKEN;
							continue;
						}
						if((state->tag = html_lookup_length_tag(token, (stream - 1) - token)) < 0)
							state->tag = state->elem->tag;

						ADVANCE_TOKEN;
						if(!stack_find(&state->stack, findtag, &state->tag)) {
							state->state = STATE_CHILD;
							continue;
						}

						do {
							/*check for null, broken pages*/
							elem_tmp = stack_pop(&state->stack);
						} while(elem_tmp->tag != state->tag);

						state->elem = elem_tmp;

						state->state = STATE_END_CLOSE;
						continue;
					case '>':
						//find tag to close
						if(html_tag_is_script(state->tag)) {
							if((stream - 1) - token > strlen(html_tag[state->tag]))
								state->state = STATE_CHILD;
							else if(html_lookup_length_tag(token, (stream - 1) - token) == state->tag) {
								state->tag = 0;
								state->state = STATE_CHILD;
							} else
								state->state = STATE_CHILD;
							ADVANCE_TOKEN;
							continue;
						}
						if((state->tag = html_lookup_length_tag(token, (stream - 1) - token)) < 0)
							state->tag = state->elem->tag;

						ADVANCE_TOKEN;
						if(!stack_find(&state->stack, findtag, &state->tag)) {
							state->state = STATE_CHILD;
							continue;
						}
						do {
							/*check for null, broken pages*/
							elem_tmp = stack_pop(&state->stack);
						} while(elem_tmp->tag != state->tag);

						state->elem = elem_tmp;
						state->tag = 0;
						state->attrib = 0;
						state->attrib_key_name = 0;

						state->state = STATE_CHILD;
						continue;
					default:
						continue;
				}
			case STATE_END_CLOSE:
				switch(c) {
					case '>':
						state->state = STATE_CHILD;
						ADVANCE_TOKEN;
						continue;
					default:
						continue;
				}
			case STATE_ENTITY:
			case STATES:
				break;
		}
	}
	return token;

	error:
	/*Handle malloc fail somehow*/
	return NULL;

	#undef ADVANCE_TOKEN
}