/*************************************************************************** parser.cpp - description ------------------- begin : Sun Sep 1 2002 copyright : (C) 2002, 2003 by Andras Mantia ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * ***************************************************************************/ //qt includes #include #include #include #include #include #include #include #include #include #include #include #include //standard library includes #include #include //#include //app includes #include "parser.h" #include "saparser.h" #include "parsercommon.h" #include "node.h" #include "tag.h" #include "resource.h" #include "quantaview.h" #include "quantacommon.h" #include "document.h" #include "qextfileinfo.h" #include "kafkacommon.h" #include "undoredo.h" #include "dtds.h" #include "structtreetag.h" #include "viewmanager.h" //kde includes #include #include #include #include #include #include #include #include #include extern GroupElementMapList globalGroupMap; static const TQChar space(' '); extern int NN; extern TQMap nodes; Parser::Parser() { m_node = 0L; write = 0L; oldMaxLines = 0; m_parsingEnabled = true; m_parsingNeeded = true; m_parseIncludedFiles = true; m_saParser = new SAParser(); connect(m_saParser, TQT_SIGNAL(rebuildStructureTree(bool)), TQT_SIGNAL(rebuildStructureTree(bool))); connect(m_saParser, TQT_SIGNAL(cleanGroups()), TQT_SLOT(cleanGroups())); ParserCommon::includeWatch = new KDirWatch(); connect(ParserCommon::includeWatch, TQT_SIGNAL(dirty(const TQString&)), TQT_SLOT(slotIncludedFileChanged(const TQString&))); } Parser::~Parser() { delete m_saParser; } /** Parse a string, using as start position sLine, sCol. */ Node *Parser::parseArea(int startLine, int startCol, int endLine, int endCol, Node **lastNode, Node *a_node) { //first parse as an XML document TQString textLine; textLine.fill(space, startCol); int line = startLine; int col = 0; int tagStartLine = 0; int tagEndLine, tagEndCol; int tagStartPos, specialStartPos; int lastLineLength; // if (endCol == 0) if (endLine > maxLines) { if (endLine > 0) endLine--; lastLineLength = write->editIf->lineLength(endLine) - 1; endCol = lastLineLength + 1; } else lastLineLength = write->editIf->lineLength(endLine) - 1; int specialAreaCount = m_dtd->specialAreas.count(); bool nodeFound = false; bool goUp; Node *rootNode = 0L; Node *parentNode = a_node; Node *currentNode = a_node; if (currentNode && (currentNode->tag->type != Tag::XmlTag || currentNode->tag->single)) parentNode = currentNode->tqparent; Tag *tag = 0L; TQTag *qTag = 0L; textLine.append(write->text(startLine, startCol, startLine, write->editIf->lineLength(startLine))); if (line == endLine) { if (endCol > 0) textLine.truncate(endCol + 1); else textLine = ""; } if (m_dtd->family == Xml) { while (line <= endLine) { nodeFound = false; goUp = false; //find the first "<" and the first special area start definition in this line tagStartPos = textLine.find('<', col); specialStartPos = specialAreaCount ? textLine.find(m_dtd->specialAreaStartRx, col): -1; //if the special area start definition is before the first "<" it means //that we have found a special area if ( specialStartPos != -1 && (specialStartPos <= tagStartPos || tagStartPos == -1) ) { currentNode = ParserCommon::createTextNode(write, currentNode, line, specialStartPos, parentNode); if (!rootNode) rootNode = currentNode; TQString foundText = m_dtd->specialAreaStartRx.cap(); //create a toplevel node for the special area AreaStruct area(line, specialStartPos, line, specialStartPos + foundText.length() - 1); Node *node = ParserCommon::createScriptTagNode(write, area, foundText, m_dtd, parentNode, currentNode); if (node->tqparent && node->prev == node->tqparent) //some strange cases, but it's possible, eg.: { node->prev->next = 0L; node->prev = 0L; } if (node->tag->name.lower().startsWith("comment")) node->tag->type = Tag::Comment; if (!rootNode) rootNode = node; area.eLine = endLine; area.eCol = endCol; currentNode = m_saParser->parseArea(area, foundText, "", node, false, true); line = m_saParser->lastParsedLine(); textLine = ParserCommon::getLine(write, line, endLine, endCol); col = m_saParser->lastParsedColumn() + 1; continue; } else //if we have found an XML tag start ("<") if ( tagStartPos != -1 /*&& (tagStartPos < specialStartPos || specialStartPos == -1) */) { int openNum = 1; tagStartLine = line; tagEndLine = endLine; tagEndCol = lastLineLength; int sCol = tagStartPos + 1; int firstStartCol = lastLineLength + 1; int firstStartLine = endLine; bool firstOpenFound = false; bool insideSingleQuotes = false; bool insideDoubleQuotes = false; //find the matching ">" in the document while (line <= endLine && openNum > 0 && !firstOpenFound) { textLine = ParserCommon::getLine(write, line, endLine, endCol); uint textLineLen = textLine.length(); for (uint i = sCol; i < textLineLen; i++) { if (i == 0 || (i > 0 && textLine[i-1] != '\\')) { if (textLine[i] == '\'' && !insideDoubleQuotes) insideSingleQuotes = !insideSingleQuotes; if (textLine[i] == '"' && !insideSingleQuotes) insideDoubleQuotes = !insideDoubleQuotes; } if (!insideSingleQuotes && !insideDoubleQuotes) { if (textLine[i] == '<') { openNum++; if (!firstOpenFound && (i < textLineLen -1 && (textLine[i + 1] == '/' || textLine[i + 1].isLetter()) || i == textLineLen -1) ) { firstStartCol = i; firstStartLine = line; firstOpenFound = true; break; } } else if (textLine[i] == '>') openNum--; } if (openNum == 0) { tagEndCol = i; tagEndLine = line; break; } } sCol = 0; if (openNum != 0) line++; } //the matching closing tag was not found if (openNum != 0) { tagEndLine = firstStartLine; tagEndCol = firstStartCol - 1; if (tagEndCol < 0) { tagEndLine--; if (tagEndLine < 0) tagEndLine = 0; tagEndCol = write->editIf->lineLength(tagEndLine); } line = tagEndLine; textLine = ParserCommon::getLine(write, line, endLine, endCol); } col = tagEndCol; nodeFound = true; //build an xml tag node here AreaStruct area(tagStartLine, tagStartPos, tagEndLine, tagEndCol); tag = new Tag(area, write, m_dtd, true); TQString tagStr = tag->tagStr(); tag->type = Tag::XmlTag; tag->validXMLTag = (openNum == 0); tag->single = QuantaCommon::isSingleTag(m_dtd->name, tag->name); if (tag->isClosingTag()) { tag->type = Tag::XmlTagEnd; tag->single = true; } if (tagStr.right(2) == "/>" || tag->name.isEmpty()) { tag->single = true; if (tag->name.length() > 1 && tag->name.endsWith("/")) tag->name.truncate(tag->name.length() - 1); } //the tag we found indicates the beginning of a special area, like