src/tokeniser/tokeniser.c
hubbub_error hubbub_tokeniser_handle_close_tag_open(hubbub_tokeniser *tokeniser)
{
	hubbub_tokeniser_context *ctx = &tokeniser->context;

	size_t len;
	const uint8_t *cptr;
	parserutils_error error;
	uint8_t c;

	assert(tokeniser->context.pending == 2);
/*	assert(tokeniser->context.chars.ptr[0] == '<'); */
/*	assert(tokeniser->context.chars.ptr[1] == '/'); */

	/**\todo fragment case */

	if (tokeniser->content_model == HUBBUB_CONTENT_MODEL_RCDATA ||
			tokeniser->content_model ==
					HUBBUB_CONTENT_MODEL_CDATA) {
		uint8_t *start_tag_name =
			tokeniser->context.last_start_tag_name;
		size_t start_tag_len =
			tokeniser->context.last_start_tag_len;

		while ((error = parserutils_inputstream_peek(tokeniser->input,
					ctx->pending +
						ctx->close_tag_match.count,
					&cptr,
					&len)) == PARSERUTILS_OK) {
			c = *cptr;

			if ((start_tag_name[ctx->close_tag_match.count] & ~0x20)
					!= (c & ~0x20)) {
				break;
			}

			ctx->close_tag_match.count += len;

			if (ctx->close_tag_match.count == start_tag_len) {
				ctx->close_tag_match.match = true;
				break;
			}
		}

		if (error != PARSERUTILS_OK && error != PARSERUTILS_EOF) {
			return hubbub_error_from_parserutils_error(error);
		}

		if (ctx->close_tag_match.match == true) {
			error = parserutils_inputstream_peek(
			 		tokeniser->input,
			 		ctx->pending +
				 		ctx->close_tag_match.count,
					&cptr,
			 		&len);

			if (error != PARSERUTILS_OK && 
					error != PARSERUTILS_EOF) {
				return hubbub_error_from_parserutils_error(
						error);
			} else if (error != PARSERUTILS_EOF) {
				c = *cptr;

				if (c != '\t' && c != '\n' && c != '\f' &&
						c != ' ' && c != '>' &&
						c != '/') {
					ctx->close_tag_match.match = false;
				}
			}
		}
	}

	if (ctx->close_tag_match.match == false &&
			tokeniser->content_model !=
					HUBBUB_CONTENT_MODEL_PCDATA) {
		/* We should emit "</" here, but instead we leave it in the
		 * buffer so the data state emits it with any characters
		 * following it */
		tokeniser->state = STATE_DATA;
	} else {
		error = parserutils_inputstream_peek(tokeniser->input,
				tokeniser->context.pending, &cptr, &len);

		if (error == PARSERUTILS_EOF) {
			/** \todo parse error */

			/* Return to data state with "</" pending */
			tokeniser->state = STATE_DATA;
			return HUBBUB_OK;
		} else if (error != PARSERUTILS_OK) {
			return hubbub_error_from_parserutils_error(error);
		}

		c = *cptr;

		if ('A' <= c && c <= 'Z') {
			uint8_t lc = (c + 0x20);
			START_BUF(tokeniser->context.current_tag.name,
					&lc, len);
			tokeniser->context.current_tag.n_attributes = 0;

			tokeniser->context.current_tag_type =
					HUBBUB_TOKEN_END_TAG;

			tokeniser->context.pending += len;

			tokeniser->state = STATE_TAG_NAME;
		} else if ('a' <= c && c <= 'z') {
			START_BUF(tokeniser->context.current_tag.name,
					cptr, len);
			tokeniser->context.current_tag.n_attributes = 0;

			tokeniser->context.current_tag_type =
					HUBBUB_TOKEN_END_TAG;

			tokeniser->context.pending += len;

			tokeniser->state = STATE_TAG_NAME;
		} else if (c == '>') {
			/* Cursor still at "</", need to collect ">" */
			tokeniser->context.pending += len;

			/* Now need to advance past "</>" */
			parserutils_inputstream_advance(tokeniser->input,
					tokeniser->context.pending);
			tokeniser->context.pending = 0;

			/** \todo parse error */
			tokeniser->state = STATE_DATA;
		} else {
			/** \todo parse error */

			/* Cursor still at "</", need to advance past it */
			parserutils_inputstream_advance(tokeniser->input,
					tokeniser->context.pending);
			tokeniser->context.pending = 0;

			tokeniser->state = STATE_BOGUS_COMMENT;
		}
	}

	return HUBBUB_OK;
}
/* this state expects tokeniser->context.chars to be "</" */
/* this state never stays in this state for more than one character */
this state expects tokeniser->context.chars to be "</"
this state never stays in this state for more than one character
this state expects tokeniser - > context . chars to be " < / " this state never stays in this state for more than one character
hubbub_error hubbub_tokeniser_handle_close_tag_open(hubbub_tokeniser *tokeniser)
{
	hubbub_tokeniser_context *ctx = &tokeniser->context;
	size_t len;
	const uint8_t *cptr;
	parserutils_error error;
	uint8_t c;
	assert(tokeniser->context.pending == 2);
	if (tokeniser->content_model == HUBBUB_CONTENT_MODEL_RCDATA ||
			tokeniser->content_model ==
					HUBBUB_CONTENT_MODEL_CDATA) {
		uint8_t *start_tag_name =
			tokeniser->context.last_start_tag_name;
		size_t start_tag_len =
			tokeniser->context.last_start_tag_len;
		while ((error = parserutils_inputstream_peek(tokeniser->input,
					ctx->pending +
						ctx->close_tag_match.count,
					&cptr,
					&len)) == PARSERUTILS_OK) {
			c = *cptr;
			if ((start_tag_name[ctx->close_tag_match.count] & ~0x20)
					!= (c & ~0x20)) {
				break;
			}
			ctx->close_tag_match.count += len;
			if (ctx->close_tag_match.count == start_tag_len) {
				ctx->close_tag_match.match = true;
				break;
			}
		}
		if (error != PARSERUTILS_OK && error != PARSERUTILS_EOF) {
			return hubbub_error_from_parserutils_error(error);
		}
		if (ctx->close_tag_match.match == true) {
			error = parserutils_inputstream_peek(
			 		tokeniser->input,
			 		ctx->pending +
				 		ctx->close_tag_match.count,
					&cptr,
			 		&len);
			if (error != PARSERUTILS_OK && 
					error != PARSERUTILS_EOF) {
				return hubbub_error_from_parserutils_error(
						error);
			} else if (error != PARSERUTILS_EOF) {
				c = *cptr;
				if (c != '\t' && c != '\n' && c != '\f' &&
						c != ' ' && c != '>' &&
						c != '/') {
					ctx->close_tag_match.match = false;
				}
			}
		}
	}
	if (ctx->close_tag_match.match == false &&
			tokeniser->content_model !=
					HUBBUB_CONTENT_MODEL_PCDATA) {
		tokeniser->state = STATE_DATA;
	} else {
		error = parserutils_inputstream_peek(tokeniser->input,
				tokeniser->context.pending, &cptr, &len);
		if (error == PARSERUTILS_EOF) {
			tokeniser->state = STATE_DATA;
			return HUBBUB_OK;
		} else if (error != PARSERUTILS_OK) {
			return hubbub_error_from_parserutils_error(error);
		}
		c = *cptr;
		if ('A' <= c && c <= 'Z') {
			uint8_t lc = (c + 0x20);
			START_BUF(tokeniser->context.current_tag.name,
					&lc, len);
			tokeniser->context.current_tag.n_attributes = 0;
			tokeniser->context.current_tag_type =
					HUBBUB_TOKEN_END_TAG;
			tokeniser->context.pending += len;
			tokeniser->state = STATE_TAG_NAME;
		} else if ('a' <= c && c <= 'z') {
			START_BUF(tokeniser->context.current_tag.name,
					cptr, len);
			tokeniser->context.current_tag.n_attributes = 0;
			tokeniser->context.current_tag_type =
					HUBBUB_TOKEN_END_TAG;
			tokeniser->context.pending += len;
			tokeniser->state = STATE_TAG_NAME;
		} else if (c == '>') {
			tokeniser->context.pending += len;
			parserutils_inputstream_advance(tokeniser->input,
					tokeniser->context.pending);
			tokeniser->context.pending = 0;
			tokeniser->state = STATE_DATA;
		} else {
			parserutils_inputstream_advance(tokeniser->input,
					tokeniser->context.pending);
			tokeniser->context.pending = 0;
			tokeniser->state = STATE_BOGUS_COMMENT;
		}
	}
	return HUBBUB_OK;
}
hubbub_error hubbub_tokeniser_handle_close_tag_open ( hubbub_tokeniser * tokeniser ) { hubbub_tokeniser_context * ctx = & tokeniser -> context ; size_t len ; const uint8_t * cptr ; parserutils_error error ; uint8_t c ; assert ( tokeniser -> context . pending == 2 ) ; if ( tokeniser -> content_model == HUBBUB_CONTENT_MODEL_RCDATA || tokeniser -> content_model == HUBBUB_CONTENT_MODEL_CDATA ) { uint8_t * start_tag_name = tokeniser -> context . last_start_tag_name ; size_t start_tag_len = tokeniser -> context . last_start_tag_len ; while ( ( error = parserutils_inputstream_peek ( tokeniser -> input , ctx -> pending + ctx -> close_tag_match . count , & cptr , & len ) ) == PARSERUTILS_OK ) { c = * cptr ; if ( ( start_tag_name [ ctx -> close_tag_match . count ] & ~ 0x20 ) != ( c & ~ 0x20 ) ) { break ; } ctx -> close_tag_match . count += len ; if ( ctx -> close_tag_match . count == start_tag_len ) { ctx -> close_tag_match . match = true ; break ; } } if ( error != PARSERUTILS_OK && error != PARSERUTILS_EOF ) { return hubbub_error_from_parserutils_error ( error ) ; } if ( ctx -> close_tag_match . match == true ) { error = parserutils_inputstream_peek ( tokeniser -> input , ctx -> pending + ctx -> close_tag_match . count , & cptr , & len ) ; if ( error != PARSERUTILS_OK && error != PARSERUTILS_EOF ) { return hubbub_error_from_parserutils_error ( error ) ; } else if ( error != PARSERUTILS_EOF ) { c = * cptr ; if ( c != ' \t ' && c != ' \n ' && c != ' \f ' && c != ' ' && c != ' ' && c != ' ' ) { ctx -> close_tag_match . match = false ; } } } } if ( ctx -> close_tag_match . match == false && tokeniser -> content_model != HUBBUB_CONTENT_MODEL_PCDATA ) { tokeniser -> state = STATE_DATA ; } else { error = parserutils_inputstream_peek ( tokeniser -> input , tokeniser -> context . pending , & cptr , & len ) ; if ( error == PARSERUTILS_EOF ) { tokeniser -> state = STATE_DATA ; return HUBBUB_OK ; } else if ( error != PARSERUTILS_OK ) { return hubbub_error_from_parserutils_error ( error ) ; } c = * cptr ; if ( ' ' <= c && c <= ' ' ) { uint8_t lc = ( c + 0x20 ) ; START_BUF ( tokeniser -> context . current_tag . name , & lc , len ) ; tokeniser -> context . current_tag . n_attributes = 0 ; tokeniser -> context . current_tag_type = HUBBUB_TOKEN_END_TAG ; tokeniser -> context . pending += len ; tokeniser -> state = STATE_TAG_NAME ; } else if ( ' ' <= c && c <= ' ' ) { START_BUF ( tokeniser -> context . current_tag . name , cptr , len ) ; tokeniser -> context . current_tag . n_attributes = 0 ; tokeniser -> context . current_tag_type = HUBBUB_TOKEN_END_TAG ; tokeniser -> context . pending += len ; tokeniser -> state = STATE_TAG_NAME ; } else if ( c == ' ' ) { tokeniser -> context . pending += len ; parserutils_inputstream_advance ( tokeniser -> input , tokeniser -> context . pending ) ; tokeniser -> context . pending = 0 ; tokeniser -> state = STATE_DATA ; } else { parserutils_inputstream_advance ( tokeniser -> input , tokeniser -> context . pending ) ; tokeniser -> context . pending = 0 ; tokeniser -> state = STATE_BOGUS_COMMENT ; } } return HUBBUB_OK ; }
this state expects tokeniser->context.chars to be "</"
this state never stays in this state for more than one character
this state expects tokeniser - > context . chars to be " < / " this state never stays in this state for more than one character
/*	assert(tokeniser->context.chars.ptr[0] == '<'); */ /*	assert(tokeniser->context.chars.ptr[1] == '/'); */ /**\todo fragment case */ /* We should emit "</" here, but instead we leave it in the
		 * buffer so the data state emits it with any characters
		 * following it */ /** \todo parse error */ /* Return to data state with "</" pending */ /* Cursor still at "</", need to collect ">" */ /* Now need to advance past "</>" */ /** \todo parse error */ /** \todo parse error */ /* Cursor still at "</", need to advance past it */