You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/umbrello/umbrello/codeimport/nativeimportbase.cpp

341 lines
12 KiB

/***************************************************************************
* *
* 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. *
* *
* copyright (C) 2005-2007 *
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
***************************************************************************/
// own header
#include "nativeimportbase.h"
// qt/kde includes
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqregexp.h>
#include <tdelocale.h>
#include <kdebug.h>
// app includes
#include "import_utils.h"
NativeImportBase::NativeImportBase(const TQString &singleLineCommentIntro) {
m_singleLineCommentIntro = singleLineCommentIntro;
m_srcIndex = 0;
m_scopeIndex = 0; // index 0 is reserved for global scope
m_klass = NULL;
m_currentAccess = Uml::Visibility::Public;
m_isAbstract = false;
m_inComment = false;
}
NativeImportBase::~NativeImportBase() {
}
void NativeImportBase::setMultiLineComment(const TQString &intro, const TQString &end) {
m_multiLineCommentIntro = intro;
m_multiLineCommentEnd = end;
}
void NativeImportBase::setMultiLineAltComment(const TQString &intro, const TQString &end) {
m_multiLineAltCommentIntro = intro;
m_multiLineAltCommentEnd = end;
}
void NativeImportBase::skipStmt(TQString until /* = ";" */) {
const uint srcLength = m_source.count();
while (m_srcIndex < srcLength && m_source[m_srcIndex] != until)
m_srcIndex++;
}
bool NativeImportBase::skipToClosing(TQChar opener) {
TQString closing;
switch (opener) {
case '{':
closing = "}";
break;
case '[':
closing = "]";
break;
case '(':
closing = ")";
break;
case '<':
closing = ">";
break;
default:
kError() << "NativeImportBase::skipToClosing(" << opener
<< "): " << "illegal input character" << endl;
return false;
}
const TQString opening(opener);
skipStmt(opening);
const uint srcLength = m_source.count();
int nesting = 0;
while (m_srcIndex < srcLength) {
TQString nextToken = advance();
if (nextToken.isEmpty())
break;
if (nextToken == closing) {
if (nesting <= 0)
break;
nesting--;
} else if (nextToken == opening) {
nesting++;
}
}
if (m_srcIndex == srcLength)
return false;
return true;
}
TQString NativeImportBase::advance() {
while (m_srcIndex < m_source.count() - 1) {
if (m_source[++m_srcIndex].startsWith(m_singleLineCommentIntro))
m_comment += m_source[m_srcIndex];
else
break;
}
if (m_srcIndex >= m_source.count() - 1 ||
// if last item in m_source is a comment then it is dropped too
(m_srcIndex == m_source.count() - 1 &&
m_source[m_srcIndex].startsWith(m_singleLineCommentIntro))) {
return TQString();
}
return m_source[m_srcIndex];
}
bool NativeImportBase::preprocess(TQString& line) {
if (m_multiLineCommentIntro.isEmpty())
return false;
// Check for end of multi line comment.
if (m_inComment) {
int delimiterLen = 0;
int pos = line.find(m_multiLineCommentEnd);
if (pos == -1) {
if (! m_multiLineAltCommentEnd.isEmpty())
pos = line.find(m_multiLineAltCommentEnd);
if (pos == -1) {
m_comment += line + "\n";
return true; // done
}
delimiterLen = m_multiLineAltCommentEnd.length();
} else {
delimiterLen = m_multiLineCommentEnd.length();
}
if (pos > 0) {
TQString text = line.mid(0, pos - 1);
m_comment += text.stripWhiteSpace();
}
m_source.append(m_singleLineCommentIntro + m_comment); // denotes comments in `m_source'
m_srcIndex++;
m_comment = "";
m_inComment = false;
pos += delimiterLen; // pos now points behind the closed comment
if (pos == (int)line.length())
return true; // done
line = line.mid(pos);
}
// If we get here then m_inComment is false.
// Check for start of multi line comment.
int delimIntroLen = 0;
int delimEndLen = 0;
int pos = line.find(m_multiLineCommentIntro);
if (pos != -1) {
delimIntroLen = m_multiLineCommentIntro.length();
} else if (!m_multiLineAltCommentIntro.isEmpty()) {
pos = line.find(m_multiLineAltCommentIntro);
if (pos != -1)
delimIntroLen = m_multiLineAltCommentIntro.length();
}
if (pos != -1) {
int endpos = line.find(m_multiLineCommentEnd);
if (endpos != -1) {
delimEndLen = m_multiLineCommentEnd.length();
} else if (!m_multiLineAltCommentEnd.isEmpty()) {
endpos = line.find(m_multiLineAltCommentEnd);
if (endpos != -1)
delimEndLen = m_multiLineAltCommentEnd.length();
}
if (endpos == -1) {
m_inComment = true;
if (pos + delimIntroLen < (int)line.length()) {
TQString cmnt = line.mid(pos + delimIntroLen);
m_comment += cmnt.stripWhiteSpace() + "\n";
}
if (pos == 0)
return true; // done
line = line.left(pos);
} else { // It's a multiline comment on a single line.
if (endpos > pos + delimIntroLen) {
TQString cmnt = line.mid(pos + delimIntroLen, endpos - pos - delimIntroLen);
cmnt = cmnt.stripWhiteSpace();
if (!cmnt.isEmpty())
m_source.append(m_singleLineCommentIntro + cmnt);
}
endpos++; // endpos now points at the slash of "*/"
TQString pre;
if (pos > 0)
pre = line.left(pos);
TQString post;
if (endpos + delimEndLen < (int)line.length())
post = line.mid(endpos + 1);
line = pre + post;
}
}
return false; // The input was not completely consumed by preprocessing.
}
/// Split the line so that a string is returned as a single element of the list,
/// when not in a string then split at white space.
TQStringList NativeImportBase::split(const TQString& lin) {
TQStringList list;
TQString listElement;
TQChar stringIntro = 0; // buffers the string introducer character
bool seenSpace = false;
TQString line = lin.stripWhiteSpace();
for (uint i = 0; i < line.length(); i++) {
const TQChar& c = line[i];
if (stringIntro) { // we are in a string
listElement += c;
if (c == stringIntro) {
if (line[i - 1] != '\\') {
list.append(listElement);
listElement = TQString();
stringIntro = 0; // we are no longer in a string
}
}
} else if (c == '"' || c == '\'') {
if (!listElement.isEmpty()) {
list.append(listElement);
}
listElement = stringIntro = c;
seenSpace = false;
} else if (c == ' ' || c == '\t') {
if (seenSpace)
continue;
seenSpace = true;
if (!listElement.isEmpty()) {
list.append(listElement);
listElement = TQString();
}
} else {
listElement += c;
seenSpace = false;
}
}
if (!listElement.isEmpty())
list.append(listElement);
return list;
}
/// The lexer. Tokenizes the given string and fills `m_source'.
/// Stores possible comments in `m_comment'.
void NativeImportBase::scan(TQString line) {
if (preprocess(line))
return;
// Check for single line comment.
int pos = line.find(m_singleLineCommentIntro);
if (pos != -1) {
TQString cmnt = line.mid(pos);
m_source.append(cmnt);
if (pos == 0)
return;
line = line.left(pos);
}
if (line.contains(TQRegExp("^\\s*$")))
return;
TQStringList words = split(line);
for (TQStringList::Iterator it = words.begin(); it != words.end(); ++it) {
TQString word = *it;
if (word[0] == '"' || word[0] == '\'')
m_source.append(word); // string constants are handled by split()
else
fillSource(word);
}
}
void NativeImportBase::initVars() {
}
void NativeImportBase::parseFile(const TQString& filename) {
TQString nameWithoutPath = filename;
nameWithoutPath.remove(TQRegExp("^.*/"));
if (m_parsedFiles.contains(nameWithoutPath))
return;
m_parsedFiles.append(nameWithoutPath);
TQString fname = filename;
const TQString msgPrefix = "NativeImportBase::parseFile(" + filename + "): ";
if (filename.contains('/')) {
TQString path = filename;
path.remove( TQRegExp("/[^/]+$") );
kDebug() << msgPrefix << "adding path " << path << endl;
Import_Utils::addIncludePath(path);
}
if (! TQFile::exists(filename)) {
if (filename.startsWith("/")) {
kError() << msgPrefix << "cannot find file" << endl;
return;
}
bool found = false;
TQStringList includePaths = Import_Utils::includePathList();
for (TQStringList::Iterator pathIt = includePaths.begin();
pathIt != includePaths.end(); ++pathIt) {
TQString path = (*pathIt);
if (! path.endsWith("/")) {
path.append("/");
}
if (TQFile::exists(path + filename)) {
fname.prepend(path);
found = true;
break;
}
}
if (! found) {
kError() << msgPrefix << "cannot find file" << endl;
return;
}
}
TQFile file(fname);
if (! file.open(IO_ReadOnly)) {
kError() << msgPrefix << "cannot open file" << endl;
return;
}
kDebug() << msgPrefix << "parsing." << endl;
// Scan the input file into the TQStringList m_source.
m_source.clear();
m_srcIndex = 0;
initVars();
TQTextStream stream(&file);
while (! stream.atEnd()) {
TQString line = stream.readLine();
scan(line);
}
file.close();
// Parse the TQStringList m_source.
m_klass = NULL;
m_currentAccess = Uml::Visibility::Public;
m_scopeIndex = 0;
m_scope[0] = NULL; // index 0 is reserved for global scope
const uint srcLength = m_source.count();
for (m_srcIndex = 0; m_srcIndex < srcLength; m_srcIndex++) {
const TQString& firstToken = m_source[m_srcIndex];
//kDebug() << '"' << firstToken << '"' << endl;
if (firstToken.startsWith(m_singleLineCommentIntro)) {
m_comment = firstToken.mid(m_singleLineCommentIntro.length());
continue;
}
if (! parseStmt())
skipStmt();
m_comment = TQString();
}
kDebug() << msgPrefix << "end of parse." << endl;
}
void NativeImportBase::initialize() {
m_parsedFiles.clear();
}