Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial Commit

  • Loading branch information...
commit 877123c209b84684124be88ca8d98a49a9ca40e4 0 parents
Benjamin C Meyer authored December 06, 2007
1  .gitignore
... ...
@@ -0,0 +1 @@
  1
+Makefile
38  README
... ...
@@ -0,0 +1,38 @@
  1
+callgrind_tools is a collection of tools to help manipulate callgrind files generated by valgrind's tools
  2
+
  3
+callgrind_decompress
  4
+  Callgrind files are compressed by default.  To make it easier to read the
  5
+  callgrind files it is usefull to turn off the compression.  You can do this
  6
+  with the valgrind options "--compress-strings=no --compress-pos=no" or you
  7
+  can use this tool if you already have a compressed file.  For more
  8
+  information about the compression see the valgrind documentation.
  9
+    Example:
  10
+  ./callgrind_decompress callgrind.out.111 -o callgrind.out.111.u
  11
+
  12
+callgrind_info
  13
+  A small tool to extract information out of a callgrind file. 
  14
+    Examples:
  15
+  // list all functions in file foo.h
  16
+  ./callgrind_info callgrind.out.10 -functions foo.h
  17
+  // output the cost for function doFoo
  18
+  ./callgrind_info callgrind.out.10 -cost Bar::doFoo
  19
+  // output all fe objects in the callgrind file
  20
+  ./callgrind_info callgrind.out.10 -spec fe
  21
+ 
  22
+callgrind_coverage
  23
+  Given a callgrind file and a source file, callgrind_coverage will output
  24
+  the code coverage of the the callgrind file over the source file including
  25
+  jumps.
  26
+
  27
+More information about callgrind can be found on the valgrind website: http://valgrind.org
  28
+
  29
+========
  30
+BUILDING
  31
+========
  32
+
  33
+callgrind_tools requires rpp to build so first use git to clone its repository and then you can build.
  34
+
  35
+git clone git://repo.or.cz/rpp.git
  36
+
  37
+qmake
  38
+make
19  callgrind_coverage/callgrind_coverage.pro
... ...
@@ -0,0 +1,19 @@
  1
+######################################################################
  2
+# Automatically generated by qmake (2.01a) Fri Aug 24 13:37:36 2007
  3
+######################################################################
  4
+
  5
+TEMPLATE = app
  6
+TARGET = 
  7
+DEPENDPATH += .
  8
+INCLUDEPATH += .
  9
+
  10
+include(../rpp/src/rxx.pri)
  11
+include(../rpp/src/rpp/rpp.pri)
  12
+
  13
+mac:CONFIG -= app_bundle
  14
+
  15
+# Input
  16
+SOURCES += main.cpp callgrindfile.cpp compiler.cpp
  17
+HEADERS += callgrindfile.h compiler.h
  18
+
  19
+RESOURCES += ../rpp/example/generator.qrc
253  callgrind_coverage/callgrindfile.cpp
... ...
@@ -0,0 +1,253 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*     * Redistributions of source code must retain the above copyright
  8
+*       notice, this list of conditions and the following disclaimer.
  9
+*     * Redistributions in binary form must reproduce the above copyright
  10
+*       notice, this list of conditions and the following disclaimer in the
  11
+*       documentation and/or other materials provided with the distribution.
  12
+*     * The name of the contributors may not be used to endorse or promote products
  13
+*       derived from this software without specific prior written permission.
  14
+*
  15
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  16
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25
+*/
  26
+
  27
+#include "callgrindfile.h"
  28
+
  29
+#include <qmap.h>
  30
+#include <QMapIterator>
  31
+#include <qfile.h>
  32
+#include <qtextstream.h>
  33
+#include <qdebug.h>
  34
+#include <qstringlist.h>
  35
+#include <qregexp.h>
  36
+
  37
+CallgrindFile::CallgrindFile(const QString &file)
  38
+{
  39
+    loadFile(file);
  40
+}
  41
+
  42
+QString normalizeName(const QString &name)
  43
+{
  44
+    QString normal = name;
  45
+    if (normal.at(0) == 'c')
  46
+        normal = normal.mid(1);
  47
+    if (normal == "fi")
  48
+        normal = "fl";
  49
+    return normal;
  50
+}
  51
+
  52
+void CallgrindFile::loadFile(const QString &callgrindFile)
  53
+{
  54
+    QFile file(callgrindFile);
  55
+    if (!file.open(QFile::ReadOnly))
  56
+        return;
  57
+    m_file = callgrindFile;
  58
+    names.clear();
  59
+    functionCosts.clear();
  60
+
  61
+    QTextStream stream(&file);
  62
+    QString line;
  63
+    QMap<int, QString> FilenameMap;
  64
+    QString currentKey;
  65
+
  66
+    QRegExp nameCompression("^([a-z]*)=\\(([0-9]*)\\) (.*)");
  67
+    QRegExp parentNameCompression("^([a-z]*)=\\(([0-9]*)\\)");
  68
+    int lastName = -2;
  69
+
  70
+    int lineNumber = -1;
  71
+    QString lastLine;
  72
+
  73
+    int currentFnLine = 0;
  74
+    int id = -1;
  75
+    int lastFileId = 0;
  76
+    do {
  77
+        lastLine = line;
  78
+        line = stream.readLine();
  79
+        lineNumber++;
  80
+
  81
+        if (line.isEmpty())
  82
+            continue;
  83
+        if(line.contains(QRegExp("^[a-z]*:.*")))
  84
+            continue;
  85
+
  86
+        if (line.contains(nameCompression)) {
  87
+            QStringList cap = nameCompression.capturedTexts();
  88
+            if (!cap.value(1).isEmpty()) {
  89
+                block c;
  90
+                c.id = cap.value(2).toInt();
  91
+                c.name = cap.value(3);
  92
+                c.type = normalizeName(cap.value(1));
  93
+                if (lastLine.contains(parentNameCompression)) {
  94
+                    cap = parentNameCompression.capturedTexts();
  95
+                    c.parentType = normalizeName(cap.value(1));
  96
+                    c.parentId = cap.value(2).toInt();
  97
+                } else {
  98
+                    c.parentType = "fl";
  99
+                    c.parentId = lastFileId;
  100
+                }
  101
+                //qDebug() << "inserting" << c.name << line << c.parentType << c.parentId << lastName << lineNumber;
  102
+                names.append(c);
  103
+                lastName = lineNumber;
  104
+            }
  105
+        }
  106
+
  107
+        if (line.startsWith("fl=")) {
  108
+            line.contains(parentNameCompression);
  109
+            QStringList cap = parentNameCompression.capturedTexts();
  110
+            lastFileId = cap.value(2).toInt();
  111
+            if (lastFileId < 0)
  112
+                qDebug() << line;
  113
+            continue;
  114
+        }
  115
+
  116
+        if (line.startsWith("fn=")) {
  117
+            line.contains(parentNameCompression);
  118
+            QStringList cap = parentNameCompression.capturedTexts();
  119
+            id = cap.value(2).toInt();
  120
+            //qDebug() << "got fn" << line << id;
  121
+            continue;
  122
+        }
  123
+
  124
+        if (id != -1) {
  125
+            // actual lines!
  126
+            if (line[0] == '*')
  127
+                continue;
  128
+            QString first = line.split(" ").value(0);
  129
+            if (first[0] == '+')
  130
+                currentFnLine += first.mid(1).toInt();
  131
+            else if (first[0] == '-')
  132
+                currentFnLine -= first.mid(1).toInt();
  133
+            else
  134
+                if (first.contains(QRegExp("^[0-9]*$")))
  135
+                    currentFnLine = first.toInt();
  136
+
  137
+            if (!functionCosts[id].lines.contains(currentFnLine))
  138
+                functionCosts[id].lines.append(currentFnLine);
  139
+            //qDebug() << id << currentFnLine << line << first;
  140
+
  141
+            if (line.startsWith("jump=")) {
  142
+                jump j;
  143
+                QRegExp jmp("^jump=([0-9]*) (.*)");
  144
+                line.contains(jmp);
  145
+                QStringList cap = jmp.capturedTexts();
  146
+                line.contains(jmp);
  147
+                j.toCount = cap.value(1).toInt();
  148
+                QString to = cap.value(2);
  149
+                if (to[0] == '+')
  150
+                    j.to = currentFnLine + to.mid(1).toInt();
  151
+                else if (to[0] == '-')
  152
+                    j.to = currentFnLine - to.mid(1).toInt();
  153
+                else
  154
+                    j.to = currentFnLine;
  155
+                j.from = currentFnLine;
  156
+                j.fromCount = -1;
  157
+                //  qDebug() << j.fromCount << j.toCount << j.to << line;
  158
+                functionCosts[id].jumps.append(j);
  159
+            }
  160
+
  161
+            if (line.startsWith("jcnd=")) {
  162
+                jump j;
  163
+                QRegExp jmp("^jcnd=([0-9]*)/([0-9]*) (.*)");
  164
+                line.contains(jmp);
  165
+                QStringList cap = jmp.capturedTexts();
  166
+                line.contains(jmp);
  167
+                j.fromCount = cap.value(2).toInt();
  168
+                j.toCount = cap.value(1).toInt();
  169
+                j.fromCount = j.fromCount - j.toCount;
  170
+                QString to = cap.value(3);
  171
+                if (to[0] == '+')
  172
+                    j.to = currentFnLine + to.mid(1).toInt();
  173
+                else if (to[0] == '-')
  174
+                    j.to = currentFnLine - to.mid(1).toInt();
  175
+                else
  176
+                    j.to = currentFnLine;
  177
+                j.from = currentFnLine;
  178
+                //  qDebug() << j.fromCount << j.toCount << j.to << line;
  179
+                functionCosts[id].jumps.append(j);
  180
+            }
  181
+
  182
+        }
  183
+        continue;
  184
+    } while (!line.isNull());
  185
+}
  186
+
  187
+QList<int> CallgrindFile::linesTouched(const QString &file)
  188
+{
  189
+    QList<int> lines;
  190
+
  191
+    QString type;
  192
+    int id = 0;
  193
+
  194
+    // Find the block type/id that contains what we are looking for
  195
+    QListIterator<block> i(names);
  196
+    while (i.hasNext()) {
  197
+        block x = i.next();
  198
+        if (x.name == file) {
  199
+            type = x.type;
  200
+            id = x.id;
  201
+            break;
  202
+        }
  203
+    }
  204
+
  205
+    // Find all functions that are children of the file
  206
+    while (i.hasNext()) {
  207
+        block x = i.next();
  208
+        if ((x.type == type && x.id == id)
  209
+            || (x.parentType == type &&
  210
+                x.parentId == id))
  211
+        {
  212
+            for (int j = 0; j < functionCosts[x.id].lines.count(); ++j) {
  213
+                int line = functionCosts[x.id].lines[j];
  214
+                if (!lines.contains(line))
  215
+                    lines.append(line);
  216
+            }
  217
+        }
  218
+    }
  219
+
  220
+    return lines;
  221
+}
  222
+
  223
+QList<CallgrindFile::jump> CallgrindFile::jumps(const QString &file)
  224
+{
  225
+    QList<jump> jumps;
  226
+
  227
+    QString type;
  228
+    int id = 0;
  229
+
  230
+    // Find the block type/id that contains what we are looking for
  231
+    QListIterator<block> i(names);
  232
+    while (i.hasNext()) {
  233
+        block x = i.next();
  234
+        if (x.name == file) {
  235
+            type = x.type;
  236
+            id = x.id;
  237
+            break;
  238
+        }
  239
+    }
  240
+
  241
+    // Find all functions that are children of the file
  242
+    while (i.hasNext()) {
  243
+        block x = i.next();
  244
+        if ((x.type == type && x.id == id)
  245
+            || (x.parentType == type &&
  246
+                x.parentId == id))
  247
+        {
  248
+            jumps += functionCosts[x.id].jumps;
  249
+        }
  250
+    }
  251
+
  252
+    return jumps;
  253
+}
73  callgrind_coverage/callgrindfile.h
... ...
@@ -0,0 +1,73 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*     * Redistributions of source code must retain the above copyright
  8
+*       notice, this list of conditions and the following disclaimer.
  9
+*     * Redistributions in binary form must reproduce the above copyright
  10
+*       notice, this list of conditions and the following disclaimer in the
  11
+*       documentation and/or other materials provided with the distribution.
  12
+*     * The name of the contributors may not be used to endorse or promote products
  13
+*       derived from this software without specific prior written permission.
  14
+*
  15
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  16
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25
+*/
  26
+
  27
+#ifndef CALLGRINDFILE_H
  28
+#define CALLGRINDFILE_H
  29
+
  30
+#include <qstring.h>
  31
+#include <qlist.h>
  32
+#include <qmap.h>
  33
+
  34
+class CallgrindFile
  35
+{
  36
+public:
  37
+    struct jump {
  38
+        int from;
  39
+        int to;
  40
+        int fromCount;
  41
+        int toCount;
  42
+    };
  43
+
  44
+    CallgrindFile(const QString &file);
  45
+    void loadFile(const QString &file);
  46
+    QString file() const { return m_file; }
  47
+
  48
+    QList<int> linesTouched(const QString &file);
  49
+    QList<jump> jumps(const QString &file);
  50
+
  51
+private:
  52
+    struct block {
  53
+        // fn=(16) foo.cpp
  54
+        QString type; // fn
  55
+        int id;       // 16
  56
+        QString name; // foo.cpp
  57
+        QString parentType;
  58
+        int parentId;
  59
+    };
  60
+
  61
+    struct fn {
  62
+        QList<int> lines;
  63
+        QList<jump> jumps;
  64
+    };
  65
+
  66
+    QString m_file;
  67
+    QList<block> names;
  68
+    QMap<int /*id*/, fn> functionCosts;
  69
+};
  70
+
  71
+#endif // CALLGRINDFILE_H
  72
+
  73
+
228  callgrind_coverage/compiler.cpp
... ...
@@ -0,0 +1,228 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*     * Redistributions of source code must retain the above copyright
  8
+*       notice, this list of conditions and the following disclaimer.
  9
+*     * Redistributions in binary form must reproduce the above copyright
  10
+*       notice, this list of conditions and the following disclaimer in the
  11
+*       documentation and/or other materials provided with the distribution.
  12
+*     * The name of the contributors may not be used to endorse or promote products
  13
+*       derived from this software without specific prior written permission.
  14
+*
  15
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  16
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25
+*/
  26
+
  27
+#include "compiler.h"
  28
+
  29
+#include "pp.h"
  30
+#include "binder.h"
  31
+#include "default_visitor.h"
  32
+
  33
+#include <qfile.h>
  34
+#include <qdir.h>
  35
+#include <qdebug.h>
  36
+#include <qprocess.h>
  37
+
  38
+class Watcher: protected DefaultVisitor
  39
+{
  40
+public:
  41
+    QList<int> lines;
  42
+    QList<int> returns;
  43
+    QList<int> jumps;
  44
+    QList<QPair<int, int> > functionCalls;
  45
+    QList<QPair<int, int> > functions;
  46
+    QString m_file;
  47
+
  48
+  Watcher(LocationManager &__location, const QString &file)
  49
+   :m_file(file),
  50
+    _M_location(__location),
  51
+    _M_token_stream(&_M_location.token_stream)
  52
+    {}
  53
+
  54
+  FileModelItem run(AST *node) {
  55
+      visit(node);
  56
+      FileModelItem result;// = _M_current_file;
  57
+      return result;
  58
+  }
  59
+
  60
+protected:
  61
+    virtual void visitIfStatement(IfStatementAST *node)
  62
+    {
  63
+       // p(node);
  64
+       DefaultVisitor::visitIfStatement(node);
  65
+    }
  66
+
  67
+    virtual void visit(AST *node)
  68
+    {
  69
+      p(node);
  70
+      DefaultVisitor::visit(node);
  71
+    }
  72
+
  73
+    int p(AST *node)
  74
+    {
  75
+        if (node) {
  76
+            if (node->kind == AST::Kind_CompoundStatement
  77
+                || node->kind == AST::Kind_StringLiteral)
  78
+                return 0;
  79
+          QString filename;
  80
+          int line = 0;
  81
+          int column = 0;
  82
+          assert (node != 0);
  83
+          _M_location.positionAt(_M_token_stream->position(node->start_token), &line, &column, &filename);
  84
+          if (filename.contains(m_file)) {
  85
+            int columnEnd, lineEnd;
  86
+            _M_location.positionAt(_M_token_stream->position(node->end_token), &lineEnd, &columnEnd, &filename);
  87
+            if (!lines.contains(line))
  88
+                lines.append(line);
  89
+            //if (line == 974 && line != lineEnd)
  90
+                //qDebug() << "break:" << line << lineEnd << column << columnEnd << node->kind << AST::Kind_FunctionDefinition;
  91
+                 const Token &start_token = _M_token_stream->token((int) node->start_token);
  92
+                  const Token &end_token = _M_token_stream->token((int) node->end_token);
  93
+                 QString elt = QString::fromUtf8(&start_token.text[start_token.position],
  94
+                                           (int) (end_token.position - start_token.position)).trimmed();
  95
+            //if (line == 974 && line != lineEnd)
  96
+            //    qDebug() <<  filename << ":" << line << lineEnd << column << columnEnd << node->kind << elt;
  97
+            if (node->kind == AST::Kind_ReturnStatement)
  98
+                if (!returns.contains(line))
  99
+                    returns.append(line);
  100
+            if (node->kind == AST::Kind_FunctionDefinition) {
  101
+                //if (!functions.contains(line))
  102
+                    functions.append(QPair<int, int>(line, -1));
  103
+            }
  104
+            if (node->kind == AST::Kind_InitDeclarator) {
  105
+                if (!functions.isEmpty()
  106
+                    && functions.last().second == -1
  107
+                    && functions.last().first != -1) {
  108
+                    functions[functions.count() - 1].second = lineEnd;
  109
+                    //qDebug() << functions[functions.count() - 1].first << functions[functions.count() - 1].second;
  110
+                }
  111
+            }
  112
+            if (node->kind == AST::Kind_FunctionCall) {
  113
+                functionCalls.append(QPair<int,int>(line, lineEnd));
  114
+            }
  115
+
  116
+          }
  117
+         return line;
  118
+      }
  119
+      return 0;
  120
+    }
  121
+
  122
+private:
  123
+
  124
+private:
  125
+  LocationManager &_M_location;
  126
+  TokenStream *_M_token_stream;
  127
+};
  128
+
  129
+static bool preprocess(const QString &sourceFile, QByteArray *out)
  130
+{
  131
+    rpp::pp_environment env;
  132
+    rpp::pp preprocess(env);
  133
+
  134
+    rpp::pp_null_output_iterator null_out;
  135
+
  136
+    const char *ppconfig = ":/trolltech/generator/parser/rpp/pp-qt-configuration";
  137
+
  138
+    QFile configFile(ppconfig);
  139
+    if (!configFile.open(QFile::ReadOnly)) {
  140
+        fprintf(stderr, "Preprocessor configuration file not found '%s'\n", ppconfig);
  141
+        return false;
  142
+    }
  143
+
  144
+    QByteArray ba = configFile.readAll();
  145
+    configFile.close();
  146
+    preprocess.operator() (ba.constData(), ba.constData() + ba.size(), null_out);
  147
+
  148
+    QString qtdir = getenv ("QTDIR");
  149
+    if (qtdir.isEmpty()) {
  150
+        fprintf(stderr, "Generator requires QTDIR to be set\n");
  151
+        return false;
  152
+    }
  153
+
  154
+    qtdir += "/include";
  155
+
  156
+    QString currentDir = QDir::current().absolutePath();
  157
+    QFileInfo sourceInfo(sourceFile);
  158
+    QDir::setCurrent(sourceInfo.absolutePath());
  159
+
  160
+    preprocess.push_include_path(".");
  161
+    preprocess.push_include_path(QDir::convertSeparators(qtdir).toStdString());
  162
+    preprocess.push_include_path(QDir::convertSeparators(qtdir + "/QtXml").toStdString());
  163
+    preprocess.push_include_path(QDir::convertSeparators(qtdir + "/QtNetwork").toStdString());
  164
+    preprocess.push_include_path(QDir::convertSeparators(qtdir + "/QtCore").toStdString());
  165
+    preprocess.push_include_path(QDir::convertSeparators(qtdir + "/QtGui").toStdString());
  166
+    preprocess.push_include_path(QDir::convertSeparators(qtdir + "/QtOpenGL").toStdString());
  167
+
  168
+    std::string result;
  169
+    result.reserve (20 * 1024); // 20K
  170
+
  171
+    result += "# 1 \"builtins\"\n";
  172
+    result += "# 1 \"";
  173
+    result += sourceFile.toStdString();
  174
+    result += "\"\n";
  175
+
  176
+    preprocess.file(sourceInfo.fileName().toStdString(), 
  177
+                        rpp::pp_output_iterator<std::string>(result));
  178
+
  179
+    *out = QString::fromStdString(result).toUtf8();
  180
+    return true;
  181
+}
  182
+
  183
+Compiler::Compiler(const QString &file) : parser(&control)
  184
+{
  185
+    loadFile(file);
  186
+}
  187
+
  188
+void Compiler::loadFile(const QString &file)
  189
+{
  190
+    QProcess process;
  191
+    QStringList arguments;
  192
+    arguments << "-E" << file;
  193
+    process.start("gcc", arguments);
  194
+    process.waitForFinished();
  195
+    contents = process.readAllStandardOutput();
  196
+
  197
+    //if (!preprocess(file, &contents))
  198
+    //    return;
  199
+    ast = parser.parse(contents, contents.size(), &__pool);
  200
+
  201
+/*
  202
+    QFile ff(".pp");
  203
+    ff.open(QFile::WriteOnly);
  204
+    ff.write(contents);
  205
+    ff.close();
  206
+    */
  207
+}
  208
+
  209
+QList<int> Compiler::linesTouched(const QString &file)
  210
+{
  211
+    Watcher watcher(parser.location(), file);
  212
+    watcher.run(ast);
  213
+    return watcher.lines;
  214
+}
  215
+
  216
+QList<int> Compiler::returns(const QString &file)
  217
+{
  218
+    Watcher watcher(parser.location(), file);
  219
+    watcher.run(ast);
  220
+    return watcher.returns;
  221
+}
  222
+
  223
+QList<QPair<int, int> > Compiler::functions(const QString &file)
  224
+{
  225
+    Watcher watcher(parser.location(), file);
  226
+    watcher.run(ast);
  227
+    return watcher.functions;
  228
+}
60  callgrind_coverage/compiler.h
... ...
@@ -0,0 +1,60 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*     * Redistributions of source code must retain the above copyright
  8
+*       notice, this list of conditions and the following disclaimer.
  9
+*     * Redistributions in binary form must reproduce the above copyright
  10
+*       notice, this list of conditions and the following disclaimer in the
  11
+*       documentation and/or other materials provided with the distribution.
  12
+*     * The name of the contributors may not be used to endorse or promote products
  13
+*       derived from this software without specific prior written permission.
  14
+*
  15
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  16
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25
+*/
  26
+
  27
+#ifndef COMPILER_H
  28
+#define COMPILER_H
  29
+
  30
+#include <qlist.h>
  31
+#include <qstring.h>
  32
+
  33
+#include <control.h>
  34
+#include <parser.h>
  35
+
  36
+class Compiler
  37
+{
  38
+public:
  39
+    Compiler(const QString &file);
  40
+    void loadFile(const QString &file);
  41
+    QString file() const { return m_file; }
  42
+
  43
+    QList<int> linesTouched(const QString &file);
  44
+    QList<int> returns(const QString &file);
  45
+    QList<QPair<int, int> > functions(const QString &file);
  46
+
  47
+private:
  48
+
  49
+    QString m_file;
  50
+
  51
+    QByteArray contents;
  52
+    Control control;
  53
+    Parser parser;
  54
+    pool __pool;
  55
+    TranslationUnitAST *ast;
  56
+};
  57
+
  58
+#endif // CALLGRINDFILE_H
  59
+
  60
+
208  callgrind_coverage/main.cpp
... ...
@@ -0,0 +1,208 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*     * Redistributions of source code must retain the above copyright
  8
+*       notice, this list of conditions and the following disclaimer.
  9
+*     * Redistributions in binary form must reproduce the above copyright
  10
+*       notice, this list of conditions and the following disclaimer in the
  11
+*       documentation and/or other materials provided with the distribution.
  12
+*     * The name of the contributors may not be used to endorse or promote products
  13
+*       derived from this software without specific prior written permission.
  14
+*
  15
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  16
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  19
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25
+*/
  26
+
  27
+#include "callgrindfile.h"
  28
+#include "compiler.h"
  29
+
  30
+#include <qdebug.h>
  31
+#include <qfile.h>
  32
+#include <qfileinfo.h>
  33
+#include <qtextstream.h>
  34
+#include <qstringlist.h>
  35
+#include <qsettings.h>
  36
+#include <qdir.h>
  37
+
  38
+QStringList readSourceFile(const QString &sourceFile)
  39
+{
  40
+    QStringList lines;
  41
+    QFile file(sourceFile);
  42
+    file.open(QFile::ReadOnly);
  43
+    QTextStream stream(&file);
  44
+    QString line;
  45
+    do {
  46
+        line = stream.readLine();
  47
+        lines.append(line);
  48
+    } while (!line.isNull());
  49
+    return lines;
  50
+}
  51
+
  52
+int main(int argc, const char **argv)
  53
+{
  54
+    if (argc < 4) {
  55
+        qWarning() << "usage:" << argv[0] << "callgrindFile sourceFile supressionFile";
  56
+        return 1;
  57
+    }
  58
+
  59
+    QString callgrindFile = argv[1];
  60
+    QString sourceFile = argv[2];
  61
+    QString suppressionsFile = argv[3];
  62
+
  63
+    if (!QFile::exists(sourceFile)) {
  64
+        qWarning() << "source file don't exists";
  65
+        return 1;
  66
+    }
  67
+    if (!QFile::exists(callgrindFile)) {
  68
+        qWarning() << "callgrind file don't exists";
  69
+        return 1;
  70
+    }
  71
+    QFileInfo file(sourceFile);
  72
+    QString sourceFileName = file.fileName();
  73
+
  74
+    CallgrindFile cf(callgrindFile);
  75
+    QList<int> touchedLines = cf.linesTouched(sourceFileName);
  76
+    QList<CallgrindFile::jump> jumps = cf.jumps(sourceFileName);
  77
+
  78
+    QDir::setCurrent(file.dir().absolutePath());
  79
+    Compiler compiler(sourceFileName);
  80
+    QList<int> compiledLines = compiler.linesTouched(sourceFileName);
  81
+    QList<int> returns = compiler.returns(sourceFileName);
  82
+    QList<QPair<int, int> > functions = compiler.functions(sourceFileName);
  83
+    QStringList sourceLines = readSourceFile(sourceFileName);
  84
+
  85
+    //QSettings suppressions(suppressionsFile, QSettings::IniFormat);
  86
+    //suppressions.setGroup("jumps");
  87
+    // keys = settings.value("jumps").toString().split(",");
  88
+
  89
+    QString skip = ".*Q_ASSERT.*";
  90
+    for (int i = jumps.count() - 1; i >= 0; --i) {
  91
+        //qDebug() << jumps[i].from << sourceLines.value(jumps[i].from - 1) << jumps[i].to;
  92
+        if (sourceLines.value(jumps[i].from - 1).contains(QRegExp(skip)))
  93
+            jumps[i].fromCount = 1;
  94
+    }
  95
+
  96
+    QList<int> skips;
  97
+    skip = ".*Q_UNUSED.*";
  98
+    for (int i = 0 ; i < sourceLines.count(); ++i) {
  99
+        if (sourceLines.value(i).contains(QRegExp(skip)))
  100
+            skips.append(i + 1);
  101
+    }
  102
+
  103
+    QTextStream out(stdout);
  104
+
  105
+    out << "Function coverage - Has each function in the program been executed?" << endl;
  106
+    int touchedFunctions = 0;
  107
+    for (int i = 0; i < functions.count(); ++i) {
  108
+        int start = functions.at(i).first;
  109
+        int end = functions.at(i).second;
  110
+        for (int j = 0; j < touchedLines.count(); ++j) {
  111
+            if (touchedLines.at(j) >= start
  112
+                && touchedLines.at(j) <= end) {
  113
+                touchedFunctions++;
  114
+                // remove extra lines from functions which are often on multiple lines
  115
+                //out << "does touch: " << sourceLines[loc - 1] << endl;
  116
+                for (int k = start; k < end - 1; ++k) {
  117
+                    //qDebug() << "removing" << k << start << end;
  118
+                    compiledLines.removeAll(k);
  119
+                }
  120
+                start = -1;
  121
+                break;
  122
+            }
  123
+            //qDebug() << touchedLines.at(j);
  124
+        }
  125
+        if (start != -1)
  126
+            out << "\tNot executed: " << sourceLines[start - 1] << endl;
  127
+    }
  128
+    out << "\tFunctions: " << touchedFunctions << "/" << functions.count()
  129
+        << " " << (int)((touchedFunctions/(double)functions.count()) * 100) << "%" << endl;
  130
+
  131
+
  132
+    out << "Statement coverage - Has each line of the source code been executed?" << endl;
  133
+    out << "\tExecuted: " << touchedLines.count() << "/" << compiledLines.count()
  134
+        << " " << (int)((touchedLines.count()/(double)compiledLines.count()) * 100) << "%" << endl;
  135
+
  136
+    out << "Condition coverage - Has each evaluation point (such as a true/false decision) been executed?" << endl;
  137
+    int touchedConditions = 0;
  138
+    for (int i = 0; i < jumps.count(); ++i) {
  139
+        if (jumps[i].fromCount != 0) touchedConditions++;
  140
+        else out << "\t" << "always false " << jumps[i].from << " " << jumps[i].to << " " << jumps[i].toCount << " " << sourceLines[jumps[i].from - 1] << endl;
  141
+        if (jumps[i].toCount != 0) touchedConditions++;
  142
+        else out << "\t" << "always true " << jumps[i].from << " " << jumps[i].fromCount << " " << jumps[i].to << " " << sourceLines[jumps[i].from - 1] << endl;
  143
+        //out << "\t" << jumps[i].from << " " << jumps[i].fromCount << " " << jumps[i].to << sourceLines[jumps[i].from - 1] << endl;
  144
+    }
  145
+    out << "\tExecuted: " << touchedConditions << "/" << jumps.count()*2
  146
+        << " " << (int)((touchedConditions/(double)(jumps.count()*2)) * 100) << "%" << endl;
  147
+
  148
+    // Path coverage - Has every possible route through a given part of the code been executed?
  149
+    // Entry/exit coverage - Has every possible call and return of the function been executed?
  150
+
  151
+    out << endl;
  152
+
  153
+    for (int i = 0; i < sourceLines.count(); ++i) {
  154
+        int lineNumber = i + 1;
  155
+        QString line = sourceLines[i];
  156
+
  157
+        bool ran = (touchedLines.contains(lineNumber));
  158
+        bool com = (compiledLines.contains(lineNumber));
  159
+        bool rtn = (returns.contains(lineNumber));
  160
+        bool jmp = false;
  161
+        bool skip = skips.contains(lineNumber);
  162
+
  163
+        for (int i = 0; i < jumps.count(); ++i) {
  164
+            //qDebug() << i << jumps[i].from << jumps[i].to << jumps[i].fromCount << jumps[i].toCount;
  165
+            if (!ran
  166
+                && rtn
  167
+                && jumps[i].from + 1 == lineNumber
  168
+                //&& (jumps[i].fromCount == 0 || jumps[i].fromCount == 1 /*TODO suppress*/)
  169
+                && jumps[i].to != jumps[i].from
  170
+                ) {
  171
+                ran = true;
  172
+                jmp = true;
  173
+            }
  174
+
  175
+            if (jumps[i].from == lineNumber
  176
+                && (jumps[i].fromCount == 0 || jumps[i].toCount == 0)) {
  177
+                if (jumps[i].fromCount == 0)
  178
+                out << lineNumber << " [j]\tf: " << line << endl;
  179
+                if (jumps[i].toCount == 0)
  180
+                out << lineNumber << " ->" << jumps[i].to << " \t" << line << endl;
  181
+            }
  182
+            if (jumps[i].from == lineNumber)
  183
+            {
  184
+                jmp = true;
  185
+                break;
  186
+            }
  187
+        }
  188
+
  189
+        lineNumber++;
  190
+
  191
+        if ((!ran && !com) || ran || skip)
  192
+            continue;
  193
+
  194
+        out << lineNumber - 1
  195
+            << " ["
  196
+            << (rtn? "R" : "")
  197
+            << (com? "c" : "")
  198
+            << (jmp? "J" : "")
  199
+            << (ran ? "t" : "")
  200
+            << (skip ? "s" : "")
  201
+            << "]\t"
  202
+            << (ran ? "t" :
  203
+                com ? "c" : "-") << ": " << line << endl;
  204
+    }
  205
+
  206
+    return 0;
  207
+}
  208
+
17  callgrind_decompress/autotest/test.c
... ...
@@ -0,0 +1,17 @@
  1
+int fun1(){
  2
+    int x = 0;
  3
+    int y = 1;
  4
+    int z = x + y;
  5
+    return z;
  6
+}
  7
+
  8
+int fun2(){
  9
+    fun1();
  10
+}
  11
+
  12
+int main() {
  13
+    fun1();
  14
+    fun2();
  15
+    return 0;
  16
+}
  17
+
5  callgrind_decompress/callgrind_decompress.pri
... ...
@@ -0,0 +1,5 @@
  1
+INCLUDEPATH += $$PWD
  2
+DEPENDPATH += $$PWD
  3
+
  4
+HEADERS += decompress.h
  5
+SOURCES += decompress.cpp
13  callgrind_decompress/callgrind_decompress.pro
... ...
@@ -0,0 +1,13 @@
  1
+TEMPLATE = app
  2
+TARGET = 
  3
+DEPENDPATH += .
  4
+INCLUDEPATH += .
  5
+
  6
+mac:CONFIG -= app_bundle
  7
+
  8
+#CONFIG += release
  9
+QT = core
  10
+
  11
+# Input
  12
+HEADERS += decompress.h
  13
+SOURCES += main.cpp decompress.cpp
134  callgrind_decompress/decompress.cpp
... ...
@@ -0,0 +1,134 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*   * Redistributions of source code must retain the above copyright
  8
+*     notice, this list of conditions and the following disclaimer.
  9
+*   * Redistributions in binary form must reproduce the above copyright
  10
+*     notice, this list of conditions and the following disclaimer in the
  11
+*     documentation and/or other materials provided with the distribution.
  12
+*   * The name of the contributors may not be used to endorse or promote
  13
+*     products derived from this software without specific prior
  14
+*     written permission.
  15
+*
  16
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  17
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  20
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+#include "decompress.h"
  29
+
  30
+#include <qstringlist.h>
  31
+#include <stdlib.h>
  32
+
  33
+#define FN 0
  34
+#define FL 1
  35
+#define OB 2
  36
+inline int normalizeType(const QStringRef &name)
  37
+{
  38
+    QStringRef normal = name;
  39
+    if (normal.at(0) == 'c')
  40
+        normal = QStringRef(name.string(), 1, name.length() - 1);
  41
+    switch(normal.at(1).toAscii()){
  42
+    case 'n':
  43
+        return FN;
  44
+    case 'l':
  45
+    case 'i':
  46
+    case 'e':
  47
+        return FL;
  48
+    case 'b':
  49
+        return OB;
  50
+    }
  51
+    Q_ASSERT(true);
  52
+    return 0;
  53
+}
  54
+
  55
+QString Decompress::process(const QString &originalLine)
  56
+{
  57
+    if (originalLine.isEmpty())
  58
+        return originalLine;
  59
+
  60
+    QString line = originalLine;
  61
+    switch(line.at(0).toAscii()){
  62
+    case 'f':
  63
+    case 'c':
  64
+    case 'o': {
  65
+        // Name compression
  66
+        int eq = line.indexOf(QLatin1Char('='));
  67
+        int par = line.indexOf(QLatin1Char(')'));
  68
+        if (eq != -1 && par != -1 && line[eq + 1] == QLatin1Char('(')) {
  69
+            QStringRef idType(&line, 0, eq);
  70
+            QString type = line.mid(eq + 2, par - eq - 2);
  71
+            int id = atoi(type.toLatin1().constData());
  72
+            QStringRef name(&line, par + 1, line.length() - par - 1);
  73
+
  74
+            block b;
  75
+            b.type = normalizeType(idType);
  76
+            b.id = id;
  77
+            bool isFunction = (line.startsWith(QLatin1String("fn=")));
  78
+            if (name.isEmpty()) {
  79
+                QList<block>::iterator i =
  80
+                    qBinaryFind(names.begin(), names.end(), b);
  81
+                Q_ASSERT_X(names.end() - i != 0,
  82
+                           "find", "Id and Type Not Found!");
  83
+                line = idType.toString() + QLatin1String("=") + i->name;
  84
+            } else {
  85
+                name = QStringRef(&line, name.position() + 1, name.length() - 1);
  86
+                b.name = name.toString();
  87
+                QList<block>::iterator i =
  88
+                    qLowerBound(names.begin(), names.end(), b);
  89
+                names.insert(i, b);
  90
+                line = idType.toString() + QLatin1String("=") + b.name;
  91
+            }
  92
+            if (isFunction) {
  93
+                currentFunctionId = b.id;
  94
+                currentLineNumber = -1;
  95
+            }
  96
+        }
  97
+    }
  98
+    default :
  99
+        // Number compression
  100
+        if (currentFunctionId != -1) {
  101
+            if (currentLineNumber < 0) {
  102
+                bool ok;
  103
+                currentLineNumber = line.mid(0, line.indexOf(QLatin1Char(' '))).toInt(&ok);
  104
+                if (!ok)
  105
+                    currentLineNumber = -1;
  106
+            } else {
  107
+                QStringList words = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
  108
+                bool changed = false;
  109
+                for (int i = 0; i < words.count(); ++i) {
  110
+                    int newLine = currentLineNumber;
  111
+                    switch(words[i][0].toAscii()){
  112
+                    case '*':
  113
+                        break;
  114
+                    case '+':
  115
+                    case '-':
  116
+                        newLine += words.at(i).toInt();
  117
+                        break;
  118
+                    default:
  119
+                        continue;
  120
+                    }
  121
+                    changed = true;
  122
+                    words[i] = QString::number(newLine);
  123
+                    // changing the line number only occurs on first column
  124
+                    if (i == 0)
  125
+                        currentLineNumber = newLine;
  126
+                }
  127
+                if (changed)
  128
+                    line = words.join(QLatin1String(" "));
  129
+            }
  130
+        }
  131
+    }
  132
+    return line;
  133
+}
  134
+
58  callgrind_decompress/decompress.h
... ...
@@ -0,0 +1,58 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.
  4
+*
  5
+* Redistribution and use in source and binary forms, with or without
  6
+* modification, are permitted provided that the following conditions are met:
  7
+*   * Redistributions of source code must retain the above copyright
  8
+*     notice, this list of conditions and the following disclaimer.
  9
+*   * Redistributions in binary form must reproduce the above copyright
  10
+*     notice, this list of conditions and the following disclaimer in the
  11
+*     documentation and/or other materials provided with the distribution.
  12
+*   * The name of the contributors may not be used to endorse or promote
  13
+*     products derived from this software without specific prior
  14
+*     written permission.
  15
+*
  16
+* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
  17
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
  20
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+*/
  27
+
  28
+#ifndef DECOMPRESS_H
  29
+#define DECOMPRESS_H
  30
+
  31
+#include <qlist.h>
  32
+#include <qstring.h>
  33
+
  34
+class Decompress {
  35
+public:
  36
+    Decompress() : currentFunctionId(-1), currentLineNumber(-1) {}
  37
+    QString process(const QString &originalLine);
  38
+
  39
+private:
  40
+    class block {
  41
+    public:
  42
+        int id;
  43
+        int type;
  44
+        QString name;
  45
+
  46
+        inline bool operator <(const block &b2) const {
  47
+            if (id == b2.id)
  48
+                return type < b2.type;
  49
+            return id < b2.id;
  50
+        }
  51
+    };
  52
+    QList<block> names;
  53
+    int currentFunctionId;
  54
+    int currentLineNumber;
  55
+};
  56
+
  57
+#endif
  58
+
84  callgrind_decompress/main.cpp
... ...
@@ -0,0 +1,84 @@
  1
+/*
  2
+* Copyright (C) 2007 Benjamin C Meyer
  3
+* All rights reserved.