📄 exmlparser.c
字号:
mprAssert(state >= 0); if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } mprFlushBuf(tokBuf); /* * Special case parsing for names and for element data. We do this for * performance so we can return to the caller the largest token possible */ if (state == EXML_ELT_DATA) { /* * Read all the data up to the start of the closing element "<" or the * start of a sub-element. */#if UNUSED while (isspace(c)) { if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } }#endif if (c == '<') { if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } if (c == '/') { return TOKEN_LS_SLASH; } putLastChar(xp, c); return TOKEN_LS; } do { if (mprPutCharToBuf(tokBuf, c) < 0) { return TOKEN_TOO_BIG; } if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } } while (c != '<'); /* * Put back the last look-ahead character */ putLastChar(xp, c); /* * If all white space, then zero the token buffer */ for (cp = tokBuf->start; *cp; cp++) { if (!isspace(*cp)) { return TOKEN_TEXT; } } mprFlushBuf(tokBuf); return TOKEN_TEXT; } while (1) { switch (c) { case ' ': case '\n': case '\t': case '\r': break; case '<': if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } if (c == '/') { return TOKEN_LS_SLASH; } putLastChar(xp, c); return TOKEN_LS; case '=': return TOKEN_EQ; case '>': return TOKEN_GR; case '/': if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } if (c == '>') { return TOKEN_SLASH_GR; } return TOKEN_ERR; case '\"': case '\'': xp->quoteChar = c; /* Fall through */ default: /* * We handle element names, attribute names and attribute values * here. We do NOT handle data between elements here. Read the * token. Stop on white space or a closing element ">" */ if (xp->quoteChar) { if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } while (c != xp->quoteChar) { if (mprPutCharToBuf(tokBuf, c) < 0) { return TOKEN_TOO_BIG; } if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } } xp->quoteChar = 0; } else { while (!isspace(c) && c != '>' && c != '/' && c != '=') { if (mprPutCharToBuf(tokBuf, c) < 0) { return TOKEN_TOO_BIG; } if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } } putLastChar(xp, c); } if (mprGetBufLength(tokBuf) <= 0) { return TOKEN_ERR; } mprAddNullToBuf(tokBuf); if (state == EXML_AFTER_LS) { /* * If we are just inside an element "<", then analyze what we * have to see if we have an element name, instruction or * comment. Tokbuf will hold "?" for instructions or "!--" * for comments. */ if (mprLookAtNextCharInBuf(tokBuf) == '?') { /* Just ignore processing instructions */ rc = scanFor(xp, "?>"); if (rc < 0) { return TOKEN_TOO_BIG; } else if (rc == 0) { return TOKEN_ERR; } return TOKEN_INSTRUCTIONS; } else if (mprLookAtNextCharInBuf(tokBuf) == '!') { /* * First discard the comment leadin "!--" and eat leading * white space. */ if (strcmp((char*) tokBuf->start, "![CDATA[") == 0) { mprFlushBuf(tokBuf);#if UNUSED c = mprLookAtNextCharInBuf(inBuf); while (isspace(c)) { if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } c = mprLookAtNextCharInBuf(inBuf); }#endif rc = scanFor(xp, "]]>"); if (rc < 0) { return TOKEN_TOO_BIG; } else if (rc == 0) { return TOKEN_ERR; } return TOKEN_CDATA; } else { mprFlushBuf(tokBuf);#if UNUSED c = mprLookAtNextCharInBuf(inBuf); while (isspace(c)) { if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } c = mprLookAtNextCharInBuf(inBuf); }#endif rc = scanFor(xp, "-->"); if (rc < 0) { return TOKEN_TOO_BIG; } else if (rc == 0) { return TOKEN_ERR; } return TOKEN_COMMENT; } } } trimToken(xp); return TOKEN_TEXT; } if ((c = getNextChar(xp)) < 0) { return TOKEN_EOF; } } /* Should never get here */ mprAssert(0); return TOKEN_ERR;}/******************************************************************************//* * Scan for a pattern. Eat and discard input up to the pattern. Return 1 if * the pattern was found, return 0 if not found. Return < 0 on errors. */static int scanFor(Exml *xp, char *str){ MprBuf *tokBuf; char *cp; int c; mprAssert(str); tokBuf = xp->tokBuf; while (1) { for (cp = str; *cp; cp++) { if ((c = getNextChar(xp)) < 0) { return 0; } if (tokBuf) { if (mprPutCharToBuf(tokBuf, c) < 0) { return -1; } } if (c != *cp) { break; } } if (*cp == '\0') { /* * Remove the pattern from the tokBuf */ if (tokBuf) { mprAdjustBufEnd(tokBuf, -(int) strlen(str)); trimToken(xp); } return 1; } }}/******************************************************************************//* * Get another character. We read and buffer blocks of data if we need more * data to parse. */static int getNextChar(Exml *xp){ MprBuf *inBuf; char c; int l; inBuf = xp->inBuf; if (mprGetBufLength(inBuf) <= 0) { /* * Flush to reset the servp/endp pointers to the start of the buffer * so we can do a maximal read */ mprFlushBuf(inBuf); l = (xp->readFn)(xp, xp->inputArg, mprGetBufStart(inBuf), mprGetBufLinearSpace(inBuf)); if (l <= 0) { return -1; } mprAdjustBufEnd(inBuf, l); } c = mprGetCharFromBuf(inBuf); if (c == '\n') { xp->lineNumber++; } return c;}/******************************************************************************//* * Put back a character in the input buffer */static int putLastChar(Exml *xp, int c){ if (mprInsertCharToBuf(xp->inBuf, (char) c) < 0) { mprAssert(0); return -1; } if (c == '\n') { xp->lineNumber--; } return 0;}/******************************************************************************//* * Output a parse message */ static void error(Exml *xp, char *fmt, ...){ va_list args; char *buf; mprAssert(fmt); va_start(args, fmt); mprAllocVsprintf(MPR_LOC_ARGS(xp), &buf, MPR_MAX_STRING, fmt, args); va_end(args); /* * MOB need to add the failing line text and a pointer to which column */ mprFree(xp->errMsg); mprAllocSprintf(MPR_LOC_ARGS(xp), &xp->errMsg, MPR_MAX_STRING, "XML error: %s\nAt line %d\n", buf, xp->lineNumber); mprFree(buf);}/******************************************************************************//* * Remove trailing whitespace in a token and ensure it is terminated with * a NULL for easy parsing */static void trimToken(Exml *xp){ while (isspace(mprLookAtLastCharInBuf(xp->tokBuf))) { mprAdjustBufEnd(xp->tokBuf, -1); } mprAddNullToBuf(xp->tokBuf);}/******************************************************************************/const char *exmlGetErrorMsg(Exml *xp){ if (xp->errMsg == 0) { return ""; } return xp->errMsg;}/******************************************************************************/int exmlGetLineNumber(Exml *xp){ return xp->lineNumber;}/******************************************************************************/#elsevoid exmlParserDummy() {}#endif /* BLD_FEATURE_EXML *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim:tw=78 * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -