umbrello API Documentation

nativeimportbase.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *  copyright (C) 2005-2007                                                *
00009  *  Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                   *
00010  ***************************************************************************/
00011 
00012 // own header
00013 #include "nativeimportbase.h"
00014 
00015 // qt/kde includes
00016 #include <qfile.h>
00017 #include <qtextstream.h>
00018 #include <qregexp.h>
00019 #include <klocale.h>
00020 #include <kdebug.h>
00021 // app includes
00022 #include "import_utils.h"
00023 
00024 NativeImportBase::NativeImportBase(const QString &singleLineCommentIntro) {
00025     m_singleLineCommentIntro = singleLineCommentIntro;
00026     m_srcIndex = 0;
00027     m_scopeIndex = 0;  // index 0 is reserved for global scope
00028     m_klass = NULL;
00029     m_currentAccess = Uml::Visibility::Public;
00030     m_isAbstract = false;
00031     m_inComment = false;
00032 }
00033 
00034 NativeImportBase::~NativeImportBase() {
00035 }
00036 
00037 void NativeImportBase::setMultiLineComment(const QString &intro, const QString &end) {
00038     m_multiLineCommentIntro = intro;
00039     m_multiLineCommentEnd = end;
00040 }
00041 
00042 void NativeImportBase::setMultiLineAltComment(const QString &intro, const QString &end) {
00043     m_multiLineAltCommentIntro = intro;
00044     m_multiLineAltCommentEnd = end;
00045 }
00046 
00047 void NativeImportBase::skipStmt(QString until /* = ";" */) {
00048     const uint srcLength = m_source.count();
00049     while (m_srcIndex < srcLength && m_source[m_srcIndex] != until)
00050         m_srcIndex++;
00051 }
00052 
00053 bool NativeImportBase::skipToClosing(QChar opener) {
00054     QString closing;
00055     switch (opener) {
00056         case '{':
00057             closing = "}";
00058             break;
00059         case '[':
00060             closing = "]";
00061             break;
00062         case '(':
00063             closing = ")";
00064             break;
00065         case '<':
00066             closing = ">";
00067             break;
00068         default:
00069             kError() << "NativeImportBase::skipToClosing(" << opener
00070                 << "): " << "illegal input character" << endl;
00071             return false;
00072     }
00073     const QString opening(opener);
00074     skipStmt(opening);
00075     const uint srcLength = m_source.count();
00076     int nesting = 0;
00077     while (m_srcIndex < srcLength) {
00078         QString nextToken = advance();
00079         if (nextToken.isEmpty())
00080             break;
00081         if (nextToken == closing) {
00082             if (nesting <= 0)
00083                 break;
00084             nesting--;
00085         } else if (nextToken == opening) {
00086             nesting++;
00087         }
00088     }
00089     if (m_srcIndex == srcLength)
00090         return false;
00091     return true;
00092 }
00093 
00094 QString NativeImportBase::advance() {
00095     while (m_srcIndex < m_source.count() - 1) {
00096         if (m_source[++m_srcIndex].startsWith(m_singleLineCommentIntro))
00097             m_comment += m_source[m_srcIndex];
00098         else
00099             break;
00100     }
00101     if (m_srcIndex >= m_source.count() - 1 ||
00102         // if last item in m_source is a comment then it is dropped too
00103         (m_srcIndex == m_source.count() - 1 &&
00104          m_source[m_srcIndex].startsWith(m_singleLineCommentIntro))) {
00105         return QString();
00106     }
00107     return m_source[m_srcIndex];
00108 }
00109 
00110 bool NativeImportBase::preprocess(QString& line) {
00111     if (m_multiLineCommentIntro.isEmpty())
00112         return false;
00113     // Check for end of multi line comment.
00114     if (m_inComment) {
00115         int delimiterLen = 0;
00116         int pos = line.find(m_multiLineCommentEnd);
00117         if (pos == -1) {
00118             if (! m_multiLineAltCommentEnd.isEmpty())
00119                 pos = line.find(m_multiLineAltCommentEnd);
00120             if (pos == -1) {
00121                 m_comment += line + "\n";
00122                 return true;  // done
00123             }
00124             delimiterLen = m_multiLineAltCommentEnd.length();
00125         } else {
00126             delimiterLen = m_multiLineCommentEnd.length();
00127         }
00128         if (pos > 0) {
00129             QString text = line.mid(0, pos - 1);
00130             m_comment += text.stripWhiteSpace();
00131         }
00132         m_source.append(m_singleLineCommentIntro + m_comment);  // denotes comments in `m_source'
00133         m_srcIndex++;
00134         m_comment = "";
00135         m_inComment = false;
00136         pos += delimiterLen;  // pos now points behind the closed comment
00137         if (pos == (int)line.length())
00138             return true;  // done
00139         line = line.mid(pos);
00140     }
00141     // If we get here then m_inComment is false.
00142     // Check for start of multi line comment.
00143     int delimIntroLen = 0;
00144     int delimEndLen = 0;
00145     int pos = line.find(m_multiLineCommentIntro);
00146     if (pos != -1) {
00147         delimIntroLen = m_multiLineCommentIntro.length();
00148     } else if (!m_multiLineAltCommentIntro.isEmpty()) {
00149         pos = line.find(m_multiLineAltCommentIntro);
00150         if (pos != -1)
00151             delimIntroLen = m_multiLineAltCommentIntro.length();
00152     }
00153     if (pos != -1) {
00154         int endpos = line.find(m_multiLineCommentEnd);
00155         if (endpos != -1) {
00156             delimEndLen = m_multiLineCommentEnd.length();
00157         } else if (!m_multiLineAltCommentEnd.isEmpty()) {
00158             endpos = line.find(m_multiLineAltCommentEnd);
00159             if (endpos != -1)
00160                 delimEndLen = m_multiLineAltCommentEnd.length();
00161         }
00162         if (endpos == -1) {
00163             m_inComment = true;
00164             if (pos + delimIntroLen < (int)line.length()) {
00165                 QString cmnt = line.mid(pos + delimIntroLen);
00166                 m_comment += cmnt.stripWhiteSpace() + "\n";
00167             }
00168             if (pos == 0)
00169                 return true;  // done
00170             line = line.left(pos);
00171         } else {   // It's a multiline comment on a single line.
00172             if (endpos > pos + delimIntroLen)  {
00173                 QString cmnt = line.mid(pos + delimIntroLen, endpos - pos - delimIntroLen);
00174                 cmnt = cmnt.stripWhiteSpace();
00175                 if (!cmnt.isEmpty())
00176                     m_source.append(m_singleLineCommentIntro + cmnt);
00177             }
00178             endpos++;  // endpos now points at the slash of "*/"
00179             QString pre;
00180             if (pos > 0)
00181                 pre = line.left(pos);
00182             QString post;
00183             if (endpos + delimEndLen < (int)line.length())
00184                 post = line.mid(endpos + 1);
00185             line = pre + post;
00186         }
00187     }
00188     return false;  // The input was not completely consumed by preprocessing.
00189 }
00190 
00193 QStringList NativeImportBase::split(const QString& lin) {
00194     QStringList list;
00195     QString listElement;
00196     QChar stringIntro = 0;  // buffers the string introducer character
00197     bool seenSpace = false;
00198     QString line = lin.stripWhiteSpace();
00199     for (uint i = 0; i < line.length(); i++) {
00200         const QChar& c = line[i];
00201         if (stringIntro) {        // we are in a string
00202             listElement += c;
00203             if (c == stringIntro) {
00204                 if (line[i - 1] != '\\') {
00205                     list.append(listElement);
00206                     listElement = QString();
00207                     stringIntro = 0;  // we are no longer in a string
00208                 }
00209             }
00210         } else if (c == '"' || c == '\'') {
00211             if (!listElement.isEmpty()) {
00212                 list.append(listElement);
00213             }
00214             listElement = stringIntro = c;
00215             seenSpace = false;
00216         } else if (c == ' ' || c == '\t') {
00217             if (seenSpace)
00218                 continue;
00219             seenSpace = true;
00220             if (!listElement.isEmpty()) {
00221                 list.append(listElement);
00222                 listElement = QString();
00223             }
00224         } else {
00225             listElement += c;
00226             seenSpace = false;
00227         }
00228     }
00229     if (!listElement.isEmpty())
00230         list.append(listElement);
00231     return list;
00232 }
00233 
00236 void NativeImportBase::scan(QString line) {
00237     if (preprocess(line))
00238         return;
00239     // Check for single line comment.
00240     int pos = line.find(m_singleLineCommentIntro);
00241     if (pos != -1) {
00242         QString cmnt = line.mid(pos);
00243         m_source.append(cmnt);
00244         if (pos == 0)
00245             return;
00246         line = line.left(pos);
00247     }
00248     if (line.contains(QRegExp("^\\s*$")))
00249         return;
00250     QStringList words = split(line);
00251     for (QStringList::Iterator it = words.begin(); it != words.end(); ++it) {
00252         QString word = *it;
00253         if (word[0] == '"' || word[0] == '\'')
00254             m_source.append(word);  // string constants are handled by split()
00255         else
00256             fillSource(word);
00257     }
00258 }
00259 
00260 void NativeImportBase::initVars() {
00261 }
00262 
00263 void NativeImportBase::parseFile(const QString& filename) {
00264     QString nameWithoutPath = filename;
00265     nameWithoutPath.remove(QRegExp("^.*/"));
00266     if (m_parsedFiles.contains(nameWithoutPath))
00267         return;
00268     m_parsedFiles.append(nameWithoutPath);
00269     QString fname = filename;
00270     const QString msgPrefix = "NativeImportBase::parseFile(" + filename + "): ";
00271     if (filename.contains('/')) {
00272         QString path = filename;
00273         path.remove( QRegExp("/[^/]+$") );
00274         kDebug() << msgPrefix << "adding path " << path << endl;
00275         Import_Utils::addIncludePath(path);
00276     }
00277     if (! QFile::exists(filename)) {
00278         if (filename.startsWith("/")) {
00279             kError() << msgPrefix << "cannot find file" << endl;
00280             return;
00281         }
00282         bool found = false;
00283         QStringList includePaths = Import_Utils::includePathList();
00284         for (QStringList::Iterator pathIt = includePaths.begin();
00285                                    pathIt != includePaths.end(); ++pathIt) {
00286             QString path = (*pathIt);
00287             if (! path.endsWith("/")) {
00288                 path.append("/");
00289             }
00290             if (QFile::exists(path + filename)) {
00291                 fname.prepend(path);
00292                 found = true;
00293                 break;
00294             }
00295         }
00296         if (! found) {
00297             kError() << msgPrefix << "cannot find file" << endl;
00298             return;
00299         }
00300     }
00301     QFile file(fname);
00302     if (! file.open(IO_ReadOnly)) {
00303         kError() << msgPrefix << "cannot open file" << endl;
00304         return;
00305     }
00306     kDebug() << msgPrefix << "parsing." << endl;
00307     // Scan the input file into the QStringList m_source.
00308     m_source.clear();
00309     m_srcIndex = 0;
00310     initVars();
00311     QTextStream stream(&file);
00312     while (! stream.atEnd()) {
00313         QString line = stream.readLine();
00314         scan(line);
00315     }
00316     file.close();
00317     // Parse the QStringList m_source.
00318     m_klass = NULL;
00319     m_currentAccess = Uml::Visibility::Public;
00320     m_scopeIndex = 0;
00321     m_scope[0] = NULL;  // index 0 is reserved for global scope
00322     const uint srcLength = m_source.count();
00323     for (m_srcIndex = 0; m_srcIndex < srcLength; m_srcIndex++) {
00324         const QString& firstToken = m_source[m_srcIndex];
00325         //kDebug() << '"' << firstToken << '"' << endl;
00326         if (firstToken.startsWith(m_singleLineCommentIntro)) {
00327             m_comment = firstToken.mid(m_singleLineCommentIntro.length());
00328             continue;
00329         }
00330         if (! parseStmt())
00331            skipStmt();
00332         m_comment = QString();
00333     }
00334     kDebug() << msgPrefix << "end of parse." << endl;
00335 }
00336 
00337 void NativeImportBase::initialize() {
00338     m_parsedFiles.clear();
00339 }
00340 
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:58 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003