/*************************************************************************** sagroupparser.cpp - description ------------------- begin : Wed Feb 11 2004 copyright : (C) 2004 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; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ //qt includes #include #include //kde includes #include #include #include //own includes #include "sagroupparser.h" #include "saparser.h" #include "document.h" #include "node.h" #include "parsercommon.h" #include "qextfileinfo.h" #include "quantacommon.h" #include "resource.h" #include "tag.h" extern GroupElementMapList globalGroupMap; SAGroupParser::SAGroupParser(SAParser *tqparent, Document *write, Node *startNode, Node *endNode, bool synchronous, bool parsingLastNode, bool paringLastGroup) { g_node = startNode; g_endNode = endNode; m_synchronous = synchronous; m_lastGroupParsed = paringLastGroup; m_parsingLastNode = parsingLastNode; m_parent = tqparent; m_write = write; m_count = 0; m_parseForGroupTimer = new TQTimer(this); connect(m_parseForGroupTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotParseForScriptGroup())); } void SAGroupParser::slotParseForScriptGroup() { #ifdef DEBUG_PARSER //kdDebug(24001) << "slotParseForScriptGroup. Synch: " << m_synchronous << endl; #endif if ((m_parent && !m_parent->parsingEnabled()) || (!baseNode && !m_synchronous)) { #ifdef DEBUG_PARSER kdDebug(24001) << "slotParseForScriptGroup aborted. Synch: " << m_synchronous << endl; #endif return; } if (g_node && g_node != g_endNode ) { if (g_node->tag && (g_node->tag->type == Tag::Text || g_node->tag->type == Tag::ScriptStructureBegin)) parseForScriptGroup(g_node); g_node = g_node->nextSibling(); if (m_synchronous) { slotParseForScriptGroup(); return; } else { #ifdef DEBUG_PARSER //kdDebug(24001) << "Calling slotParseForScriptGroup from slotParseForScriptGroup." << endl; #endif m_parseForGroupTimer->start(0, true); } } else { #ifdef DEBUG_PARSER kdDebug(24001) << "slotParseForScriptGroup done." << endl; #endif if (m_lastGroupParsed && m_parsingLastNode && !m_synchronous) { if (m_lastGroupParsed) { #ifdef DEBUG_PARSER // kdDebug(24000) << "Calling cleanGroups from SAGroupParser::slotParseForScriptGroup" << endl; kdDebug(24001) << m_count << " GroupElement created." << endl; #endif emit cleanGroups(); m_lastGroupParsed = false; } #ifdef DEBUG_PARSER kdDebug(24001) << "Emitting rebuildStructureTree from slotParseForScriptGroup." << endl; #endif emit rebuildStructureTree(true); } } } void SAGroupParser::parseForScriptGroup(Node *node) { #ifdef DEBUG_PARSER TQTime t; t.start(); #endif int bl, bc, el, ec; int pos; TQString title; TQString tmpStr; StructTreeGroup group; GroupElement *groupElement; GroupElementList* groupElementList; KURL baseURL = QExtFileInfo::path(m_write->url()); TQString str = node->tag->cleanStr; TQString tagStr = node->tag->tagStr(); const DTDStruct* dtd = node->tag->dtd(); node->tag->beginPos(bl, bc); TQValueList::ConstIterator it; for (it = dtd->structTreeGroups.begin(); it != dtd->structTreeGroups.end(); ++it) { group = *it; if (!group.hasDefinitionRx || node->tag->type == Tag::XmlTag || node->tag->type == Tag::XmlTagEnd || node->tag->type == Tag::Comment || node->tag->type == Tag::Empty || ( group.tagType != Tag::Text && node->tag->type != group.tagType) ) continue; pos = 0; group.definitionRx.setMinimal(group.isMinimalDefinitionRx); while (pos != -1) { pos = group.definitionRx.search(str, pos); if (pos != -1) //the Node is part of this group { title = tagStr.mid(pos, group.definitionRx.matchedLength()); node->tag->beginPos(bl, bc); tmpStr = tagStr.left(pos); int newLines = tmpStr.tqcontains('\n'); bl += newLines; int l = tmpStr.tqfindRev('\n'); //the last EOL bc = (l == -1) ? bc + pos : pos - l - 1; newLines = title.tqcontains('\n'); l = title.length(); el = bl + newLines; ec = (newLines > 0) ? l - title.tqfindRev('\n') : bc + l - 1; pos += l; AreaStruct area(bl, bc, el, ec); //get the list of elements which are present in this group and //have the same title. For example get the list of all group //element which are variable and the matched string was "$i" int cap1Pos = str.tqfind(group.definitionRx.cap(1)); TQString s = tagStr.mid(cap1Pos, group.definitionRx.cap(1).length()); groupElementList = & (globalGroupMap[group.name + "|" + s]); //Create a new tag which point to the exact location of the matched string. //For example when the group defined PHP variables it //points to "$i" in a node which originally contained "print $i + 1" Tag *newTag = new Tag(*node->tag); newTag->setTagPosition(area); newTag->setStr(title); newTag->name = s; groupElement = new GroupElement; groupElement->deleted = false; groupElement->tag = newTag; groupElement->node = node; groupElement->group = const_cast(&(*it)); //Find out if the current node is inside a script structure or not. //This is used to define local/global scope of the group elements. Node *tmpNode = node; while (tmpNode && tmpNode->tag->dtd() == dtd && tmpNode->tag->type != Tag::ScriptStructureBegin) { tmpNode = tmpNode->tqparent; } if (tmpNode && tmpNode->tag->type == Tag::ScriptStructureBegin) { groupElement->tqparentNode = tmpNode; } else { groupElement->tqparentNode = 0L; } groupElement->global = true; tmpNode = node->tqparent; while (tmpNode && tmpNode->tag->dtd() == dtd) { if ( tmpNode->tag->type == Tag::ScriptStructureBegin && tmpNode->tag->dtd()->localScopeKeywordsRx.search(tmpNode->tag->cleanStr) != -1) { groupElement->global = false; groupElement->tqparentNode = tmpNode; break; } tmpNode = tmpNode->tqparent; } if (group.appendToTags) { TQTag *qTag = new TQTag(); // The location of the first open bracket '(', also the end of the tag name int nameEnd = s.tqfind('('); qTag->setName(s.left(nameEnd)); qTag->className = ""; if (groupElement->tqparentNode) { for (GroupElementList::ConstIterator it2 = groupElement->tqparentNode->m_groupElements.constBegin(); it2 != groupElement->tqparentNode->m_groupElements.constEnd(); ++it2) { if ((*it2)->group->name == group.tqparentGroup) { qTag->className = (*it2)->tag->name; break; } } } // Test for variable or function Type by checking for an opening bracket "(" used by functions // and store the type in the TQTag type variable. bool isArgument=false; if (nameEnd == -1) { qTag->type="variable"; // If this tag is a class function argument, it should not belong to the class, so we need to remove it if(qTag->className.length() != 0 && tagStr.tqcontains('(') && tagStr.tqcontains(')')) { // First we want to determine the whole line the tag is on TQString tagWholeLineStr = tagStr; // Remove lines before target line while(tagWholeLineStr.length() > 0) // this stops infinit looping in case something goes wrong! { int firstNewline = tagWholeLineStr.tqfind('\n'); if(firstNewline == -1) //no new lines so we must be on the last break; TQString checkLineStr = tagWholeLineStr.mid(firstNewline+1,tagWholeLineStr.length()); if(checkLineStr.tqcontains(s)) tagWholeLineStr = checkLineStr; else break; } // Remove lines after target line - essentially same as above while(tagWholeLineStr.length() > 0) { int lastNewLine = tagWholeLineStr.tqfindRev('\n'); if(lastNewLine == -1) break; TQString checkLineStr = tagWholeLineStr.mid(0,lastNewLine); if(checkLineStr.tqcontains(s)) tagWholeLineStr = checkLineStr; else break; } // Now we are left with the current line, lets check if the variable is inside tqparentheses int lineOpenParenth=tagWholeLineStr.tqfind('('); if(lineOpenParenth != -1) { int lineCloseParenth=tagWholeLineStr.tqfind(')'); if(lineCloseParenth != -1) { int lineNameLocation=tagWholeLineStr.tqfind(s); if(lineNameLocation > lineOpenParenth || lineNameLocation < lineCloseParenth) // Write the current tag to the list isArgument=true; } } } } else { qTag->type="function"; } if(!isArgument) m_write->userTagList.tqreplace(s.lower(), qTag); } if (!group.typeRx.pattern().isEmpty() && group.typeRx.search(title) != -1) groupElement->type = group.typeRx.cap(1); #ifdef DEBUG_PARSER kdDebug(24001) << "GroupElement created: " <tag->area().bLine << " " << groupElement->tag->area().bCol << " "<< groupElement->tag->area().eLine << " "<< groupElement->tag->area().eCol << " " << groupElement->tag->tagStr() << " " << groupElement->type << endl; #endif //store the pointer to the group element list where this node was put //used to clear the corresponding entry from the group element lists //when the node is deleted (eg. $i was deleted, so it should be deleted //from the "variables | $i" group element list as well) node->m_groupElements.append(groupElement); groupElementList->append(groupElement); m_count++; //if a filename may be present in the title, extract it if (group.hasFileName && group.parseFile) { s.remove(group.fileNameRx); KURL url; QuantaCommon::setUrl(url, s.stripWhiteSpace()); url = QExtFileInfo::toAbsolute(url, baseURL); ParserCommon::includedFiles += url.path(); ParserCommon::includedFilesDTD.append(dtd); ParserCommon::includeWatch->addFile(url.path()); } } } } #ifdef DEBUG_PARSER if (t.elapsed() > 10) kdDebug(24001) << "Done: " << t.elapsed() << endl; #endif } #include "sagroupparser.moc"