| 3962 | */ |
| 3963 | |
| 3964 | static int |
| 3965 | htmlParseEndTag(htmlParserCtxtPtr ctxt) |
| 3966 | { |
| 3967 | const xmlChar *name; |
| 3968 | const xmlChar *oldname; |
| 3969 | int i, ret; |
| 3970 | |
| 3971 | if ((CUR != '<') || (NXT(1) != '/')) { |
| 3972 | htmlParseErr(ctxt, XML_ERR_LTSLASH_REQUIRED, |
| 3973 | "htmlParseEndTag: '</' not found\n", NULL, NULL); |
| 3974 | return (0); |
| 3975 | } |
| 3976 | SKIP(2); |
| 3977 | |
| 3978 | name = htmlParseHTMLName(ctxt); |
| 3979 | if (name == NULL) |
| 3980 | return (0); |
| 3981 | /* |
| 3982 | * We should definitely be at the ending "S? '>'" part |
| 3983 | */ |
| 3984 | SKIP_BLANKS; |
| 3985 | if (CUR != '>') { |
| 3986 | htmlParseErr(ctxt, XML_ERR_GT_REQUIRED, |
| 3987 | "End tag : expected '>'\n", NULL, NULL); |
| 3988 | /* Skip to next '>' */ |
| 3989 | while ((PARSER_STOPPED(ctxt) == 0) && |
| 3990 | (CUR != 0) && (CUR != '>')) |
| 3991 | NEXT; |
| 3992 | } |
| 3993 | if (CUR == '>') |
| 3994 | NEXT; |
| 3995 | |
| 3996 | /* |
| 3997 | * if we ignored misplaced tags in htmlParseStartTag don't pop them |
| 3998 | * out now. |
| 3999 | */ |
| 4000 | if ((ctxt->depth > 0) && |
| 4001 | (xmlStrEqual(name, BAD_CAST "html") || |
| 4002 | xmlStrEqual(name, BAD_CAST "body") || |
| 4003 | xmlStrEqual(name, BAD_CAST "head"))) { |
| 4004 | ctxt->depth--; |
| 4005 | return (0); |
| 4006 | } |
| 4007 | |
| 4008 | /* |
| 4009 | * If the name read is not one of the element in the parsing stack |
| 4010 | * then return, it's just an error. |
| 4011 | */ |
| 4012 | for (i = (ctxt->nameNr - 1); i >= 0; i--) { |
| 4013 | if (xmlStrEqual(name, ctxt->nameTab[i])) |
| 4014 | break; |
| 4015 | } |
| 4016 | if (i < 0) { |
| 4017 | htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH, |
| 4018 | "Unexpected end tag : %s\n", name, NULL); |
| 4019 | return (0); |
| 4020 | } |
| 4021 |
no test coverage detected