<commit_before>/**
 * Copyright 2014 Truphone
 */
#include "XmppTestCommand.h"

#include <QString>
#include <QObject>
#include <QXmppClient.h>
#include <QXmppMessage.h>

#include "Connection.h"
#include "XmppResourceStore.h"

namespace truphone
{
namespace test
{
namespace cascades
{
    const QString XMPPTestCommand::CMD_NAME = "xmppTest";

    XMPPTestCommand::XMPPTestCommand(Connection * const socket,
                                     QObject* parent)
        : Command(parent),
          client(socket)
    {
    }

    XMPPTestCommand::~XMPPTestCommand()
    {
    }

    bool XMPPTestCommand::executeCommand(QStringList * const arguments)
    {
        bool ret = false;
        if (arguments->length() < 2)
        {
            this->client->write(tr("ERROR: xmppTest <resource> <field> <optional: value>") + "\r\n");
        }
        else
        {
            QXmppClient * const client =
                    XMPPResourceStore::instance()->getFromStore(arguments->first());
            arguments->removeFirst();
            if (client)
            {
                QXmppMessage lastMessageRecieved;
                const bool lastMsgOk = XMPPResourceStore::instance()->getLastMessageReceived(
                            client, lastMessageRecieved);
                if (lastMsgOk)
                {
                    bool propertyOk = true;
                    const QString property = arguments->first();
                    arguments->removeFirst();
                    QVariant value;
                    // I tried to make this use reflection.
                    // It didn't work - might use reflection on function calls later
                    if (property == "body")
                    {
                        value = lastMessageRecieved.body();
                    }
                    else if (property == "attentionRequired")
                    {
                        value = lastMessageRecieved.isAttentionRequested();
                    }
                    else if (property == "mucInvitationJid")
                    {
                        value = lastMessageRecieved.mucInvitationJid();
                    }
                    else if (property == "mucInvitationPassword")
                    {
                        value = lastMessageRecieved.mucInvitationPassword();
                    }
                    else if (property == "mucInvitationReason")
                    {
                        value = lastMessageRecieved.mucInvitationReason();
                    }
                    else if (property == "receiptId")
                    {
                        value = lastMessageRecieved.receiptId();
                    }
                    else if (property == "stamp")
                    {
                        value = lastMessageRecieved.stamp();
                    }
                    else if (property == "state")
                    {
                        value = lastMessageRecieved.state();
                    }
                    else if (property == "subject")
                    {
                        value = lastMessageRecieved.subject();
                    }
                    else if (property == "thread")
                    {
                        value = lastMessageRecieved.thread();
                    }
                    else if (property == "type")
                    {
                        value = lastMessageRecieved.type();
                    }
                    else if (property == "hasForward")
                    {
                        value = lastMessageRecieved.hasForwarded();
                    }
                    else if (property == "forwardBody")
                    {
                        value = lastMessageRecieved.forwarded().body();
                    }
                    else if (property == "hasCarbon")
                    {
                        value = lastMessageRecieved.hasMessageCarbon();
                    }
                    else if (property == "carbonBody")
                    {
                        value = lastMessageRecieved.carbonMessage().body();
                    }
                    else if (property == "markable")
                    {
                        value = lastMessageRecieved.isMarkable();
                    }
                    else if (property == "markedId")
                    {
                        value = lastMessageRecieved.markedId();
                    }
                    else if (property == "markedThread")
                    {
                        value = lastMessageRecieved.markedThread();
                    }
                    else if (property == "isReplace")
                    {
                        value = lastMessageRecieved.isReplace();
                    }
                    else if (property == "replaceId")
                    {
                        value = lastMessageRecieved.replaceId();
                    }
                    else
                    {
                        propertyOk = false;
                    }
                    if (propertyOk)
                    {
                        QVariant expectedValue;
                        if (arguments->isEmpty())
                        {
                            ret = value.isNull() or not value.isValid();
                        }
                        else
                        {
                            const QString expected = arguments->first();
                            arguments->removeFirst();
                            ret = (value.toString() == expected);
                            expectedValue = expected;
                        }
                        if (not ret)
                        {
                            QString buffer = tr("ERROR: Value is {");
                            buffer += value.toString();
                            buffer += tr("} but expected {");
                            buffer += expectedValue.toString();
                            buffer += tr("}") + "\r\n";
                            this->client->write(buffer);
                        }
                    }
                    else
                    {
                        this->client->write(tr("ERROR: Unknown property") + "\r\n");
                    }
                }
                else
                {
                    this->client->write(tr("ERROR: Couldn't find the last received message") + "\r\n");
                }
            }
            else
            {
                this->client->write(tr("ERROR: Unknown resource") + "\r\n");
            }
        }
        return ret;
    }

    void XMPPTestCommand::showHelp()
    {
        this->client->write(tr("> xmppTest <resource> <field> <optional: value>") + "\r\n");
        this->client->write(tr("Test a field in the last received message") + "\r\n");
        this->client->write(tr("If <value> is missing it'll test for null/empty") + "\r\n");
        this->client->write(tr("Supported <value> options:") + "\r\n");
        this->client->write("\t" + tr("body") + "\r\n");
        this->client->write("\t" + tr("attentionRequired") + "\r\n");
        this->client->write("\t" + tr("mucInvitationJid") + "\r\n");
        this->client->write("\t" + tr("mucInvitationPassword") + "\r\n");
        this->client->write("\t" + tr("mucInvitationReason") + "\r\n");
        this->client->write("\t" + tr("receiptId") + "\r\n");
        this->client->write("\t" + tr("stamp") + "\r\n");
        this->client->write("\t" + tr("state") + "\r\n");
        this->client->write("\t" + tr("subject") + "\r\n");
        this->client->write("\t" + tr("thread") + "\r\n");
        this->client->write("\t" + tr("type") + "\r\n");
        this->client->write("\t" + tr("hasForward") + "\r\n");
        this->client->write("\t" + tr("fordwardBody") + "\r\n");
        this->client->write("\t" + tr("hasCarbon") + "\r\n");
        this->client->write("\t" + tr("carbonBody") + "\r\n");
        this->client->write("\t" + tr("markable") + "\r\n");
        this->client->write("\t" + tr("markedId") + "\r\n");
        this->client->write("\t" + tr("markedThread") + "\r\n");
        this->client->write("\t" + tr("isReplace") + "\r\n");
        this->client->write("\t" + tr("replaceId") + "\r\n");

    }
}  // namespace cascades
}  // namespace test
}  // namespace truphone
<commit_msg>Access to the chat marker in xmppTest.<commit_after>/**
 * Copyright 2014 Truphone
 */
#include "XmppTestCommand.h"

#include <QString>
#include <QObject>
#include <QXmppClient.h>
#include <QXmppMessage.h>

#include "Connection.h"
#include "XmppResourceStore.h"

namespace truphone
{
namespace test
{
namespace cascades
{
    const QString XMPPTestCommand::CMD_NAME = "xmppTest";

    XMPPTestCommand::XMPPTestCommand(Connection * const socket,
                                     QObject* parent)
        : Command(parent),
          client(socket)
    {
    }

    XMPPTestCommand::~XMPPTestCommand()
    {
    }

    bool XMPPTestCommand::executeCommand(QStringList * const arguments)
    {
        bool ret = false;
        if (arguments->length() < 2)
        {
            this->client->write(tr("ERROR: xmppTest <resource> <field> <optional: value>") + "\r\n");
        }
        else
        {
            QXmppClient * const client =
                    XMPPResourceStore::instance()->getFromStore(arguments->first());
            arguments->removeFirst();
            if (client)
            {
                QXmppMessage lastMessageRecieved;
                const bool lastMsgOk = XMPPResourceStore::instance()->getLastMessageReceived(
                            client, lastMessageRecieved);
                if (lastMsgOk)
                {
                    bool propertyOk = true;
                    const QString property = arguments->first();
                    arguments->removeFirst();
                    QVariant value;
                    // I tried to make this use reflection.
                    // It didn't work - might use reflection on function calls later
                    if (property == "body")
                    {
                        value = lastMessageRecieved.body();
                    }
                    else if (property == "attentionRequired")
                    {
                        value = lastMessageRecieved.isAttentionRequested();
                    }
                    else if (property == "mucInvitationJid")
                    {
                        value = lastMessageRecieved.mucInvitationJid();
                    }
                    else if (property == "mucInvitationPassword")
                    {
                        value = lastMessageRecieved.mucInvitationPassword();
                    }
                    else if (property == "mucInvitationReason")
                    {
                        value = lastMessageRecieved.mucInvitationReason();
                    }
                    else if (property == "receiptId")
                    {
                        value = lastMessageRecieved.receiptId();
                    }
                    else if (property == "stamp")
                    {
                        value = lastMessageRecieved.stamp();
                    }
                    else if (property == "state")
                    {
                        value = lastMessageRecieved.state();
                    }
                    else if (property == "subject")
                    {
                        value = lastMessageRecieved.subject();
                    }
                    else if (property == "thread")
                    {
                        value = lastMessageRecieved.thread();
                    }
                    else if (property == "type")
                    {
                        value = lastMessageRecieved.type();
                    }
                    else if (property == "hasForward")
                    {
                        value = lastMessageRecieved.hasForwarded();
                    }
                    else if (property == "forwardBody")
                    {
                        value = lastMessageRecieved.forwarded().body();
                    }
                    else if (property == "hasCarbon")
                    {
                        value = lastMessageRecieved.hasMessageCarbon();
                    }
                    else if (property == "carbonBody")
                    {
                        value = lastMessageRecieved.carbonMessage().body();
                    }
                    else if (property == "markable")
                    {
                        value = lastMessageRecieved.isMarkable();
                    }
                    else if (property == "marker")
                    {
                        value = lastMessageRecieved.marker();
                    }
                    else if (property == "markedId")
                    {
                        value = lastMessageRecieved.markedId();
                    }
                    else if (property == "markedThread")
                    {
                        value = lastMessageRecieved.markedThread();
                    }
                    else if (property == "isReplace")
                    {
                        value = lastMessageRecieved.isReplace();
                    }
                    else if (property == "replaceId")
                    {
                        value = lastMessageRecieved.replaceId();
                    }
                    else
                    {
                        propertyOk = false;
                    }
                    if (propertyOk)
                    {
                        QVariant expectedValue;
                        if (arguments->isEmpty())
                        {
                            ret = value.isNull() or not value.isValid();
                        }
                        else
                        {
                            const QString expected = arguments->first();
                            arguments->removeFirst();
                            ret = (value.toString() == expected);
                            expectedValue = expected;
                        }
                        if (not ret)
                        {
                            QString buffer = tr("ERROR: Value is {");
                            buffer += value.toString();
                            buffer += tr("} but expected {");
                            buffer += expectedValue.toString();
                            buffer += tr("}") + "\r\n";
                            this->client->write(buffer);
                        }
                    }
                    else
                    {
                        this->client->write(tr("ERROR: Unknown property") + "\r\n");
                    }
                }
                else
                {
                    this->client->write(tr("ERROR: Couldn't find the last received message") + "\r\n");
                }
            }
            else
            {
                this->client->write(tr("ERROR: Unknown resource") + "\r\n");
            }
        }
        return ret;
    }

    void XMPPTestCommand::showHelp()
    {
        this->client->write(tr("> xmppTest <resource> <field> <optional: value>") + "\r\n");
        this->client->write(tr("Test a field in the last received message") + "\r\n");
        this->client->write(tr("If <value> is missing it'll test for null/empty") + "\r\n");
        this->client->write(tr("Supported <value> options:") + "\r\n");
        this->client->write("\t" + tr("body") + "\r\n");
        this->client->write("\t" + tr("attentionRequired") + "\r\n");
        this->client->write("\t" + tr("mucInvitationJid") + "\r\n");
        this->client->write("\t" + tr("mucInvitationPassword") + "\r\n");
        this->client->write("\t" + tr("mucInvitationReason") + "\r\n");
        this->client->write("\t" + tr("receiptId") + "\r\n");
        this->client->write("\t" + tr("stamp") + "\r\n");
        this->client->write("\t" + tr("state") + "\r\n");
        this->client->write("\t" + tr("subject") + "\r\n");
        this->client->write("\t" + tr("thread") + "\r\n");
        this->client->write("\t" + tr("type") + "\r\n");
        this->client->write("\t" + tr("hasForward") + "\r\n");
        this->client->write("\t" + tr("fordwardBody") + "\r\n");
        this->client->write("\t" + tr("hasCarbon") + "\r\n");
        this->client->write("\t" + tr("carbonBody") + "\r\n");
        this->client->write("\t" + tr("markable") + "\r\n");
        this->client->write("\t" + tr("markedId") + "\r\n");
        this->client->write("\t" + tr("marker") + "\r\n");
        this->client->write("\t" + tr("markedThread") + "\r\n");
        this->client->write("\t" + tr("isReplace") + "\r\n");
        this->client->write("\t" + tr("replaceId") + "\r\n");

    }
}  // namespace cascades
}  // namespace test
}  // namespace truphone
<|endoftext|>


<commit_before>#include "fileutils.h"

const QString FileUtils::NOTES_FOLDER = "notes";
const QString FileUtils::APP_FOLDER = ".evernote";
const QString FileUtils::MY_DOCS_FOLDER = "/home/user/MyDocs";
const QString FileUtils::CONTENT_FILENAME = "content.html";

FileUtils::FileUtils(QObject *parent) :
    QObject(parent)
{
}

void FileUtils::cacheNoteContent(NoteWrapper *note, QString content){
    QDir mydocs(myDocsFolderPath());
    mydocs.mkdir(APP_FOLDER);

    QDir appDir(appFolderPath());
    appDir.mkdir(NOTES_FOLDER);

    QDir notesFolder(notesFolderPath());
    QString noteFolderName = QString::fromStdString(note->getGuid());
    notesFolder.mkdir(noteFolderName);

    QDir noteFolder(noteFolderPath(note));

    QString contentFileName = noteFolder.filePath(CONTENT_FILENAME);

    qDebug() << "content file name: " << contentFileName;

    QFile contentFile(contentFileName);

    contentFile.open(QIODevice::WriteOnly | QIODevice::Text);

    QTextStream out(&contentFile);
    out << "";
    out.flush();

    out << "";
    out << "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> ";
    out << "";
    out.flush();

    out << "";
    out.flush();

    out << content;
    out.flush();

    out << "";
    contentFile.flush();
    contentFile.close();
}

void FileUtils::cacheResourceContent(Resource r){
    QDir noteFolder(noteFolderPath(r.noteGuid));
    noteFolder.mkdir(QString::fromStdString(r.guid));

    QDir resourceFolder(resourceFolderPath(r));
    QFile contentFile(resourceFolder.filePath(QString::fromStdString(r.guid)+"."+getExtension(r)));
    contentFile.open(QIODevice::WriteOnly | QIODevice::Text);

    qDebug() << "hash: " << QString::fromStdString(r.data.bodyHash);

    contentFile.write(r.data.body.data(),r.data.size);

    contentFile.flush();
    contentFile.close();
}

QString FileUtils::myDocsFolderPath(){
    return MY_DOCS_FOLDER;
}
QString FileUtils::appFolderPath(){
    return myDocsFolderPath() + QDir::separator() + APP_FOLDER;
}
QString FileUtils::notesFolderPath(){
    return appFolderPath() + QDir::separator() + NOTES_FOLDER;
}
QString FileUtils::noteFolderPath(NoteWrapper *note){
   return noteFolderPath(note->getGuid());
}
QString FileUtils::noteFolderPath(std::string noteGuid){
 return notesFolderPath() + QDir::separator()+QString::fromStdString(noteGuid);
}

QString FileUtils::noteContentFilePath(NoteWrapper *note){
    return noteFolderPath(note) + QDir::separator() + CONTENT_FILENAME;
}

QString FileUtils::resourceFolderPath(Resource r){
    return notesFolderPath() + QDir::separator() + QString::fromStdString(r.noteGuid)+ QDir::separator() + QString::fromStdString(r.guid);
}
QString FileUtils::resourceContentFilePath(Resource r){
    return resourceFolderPath(r) + QDir::separator() + QString::fromStdString(r.guid)+"."+getExtension(r);
}

bool FileUtils::noteCached(NoteWrapper *note){
    QFile contentFile(noteContentFilePath(note));
    return contentFile.exists();
}
bool FileUtils::resourceCached(Resource r){
    QFile resourceContentFile(resourceContentFilePath(r));
    return resourceContentFile.exists();
}

QString FileUtils::getExtension(Resource r){
    if(r.mime == "audio/mpeg"){
        return "mp3";
    }else if(r.mime == "image/jpeg" || r.mime == "image/pjpeg" || r.mime == "image/jpg"){
        return "jpeg";
    }else if(r.mime == "text/plain"){
        return "txt";
    }else if(r.mime == "text/html"){
        return "html";
    }else if(r.mime == "image/png"){
        return "png";
    }else if(r.mime == "image/gif"){
        return "gif";
    }else if(r.mime == "image/bmp"){
        return "bmp";
    }else if(r.mime == "audio/wav" || r.mime == "audio/vnd.wave"){
        return "wav";
    }else if(r.mime == "audio/amr"){
        return "amr";
    }else if(r.mime == "application/pdf"){
        return "pdf";
    }else if(r.mime == "application/msword"){
        return "doc";
    }else if(r.mime == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"){
        return "docx";
    }
    return "";
}
bool FileUtils::removeDir(const QString &dirName)
{
    bool result = true;
    QDir dir(dirName);

    if (dir.exists(dirName)) {
        Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
            if (info.isDir()) {
                result = removeDir(info.absoluteFilePath());
            }
            else {
                result = QFile::remove(info.absoluteFilePath());
            }

            if (!result) {
                return result;
            }
        }
        result = dir.rmdir(dirName);
    }

    return result;
}
void FileUtils::removeNoteCache(Note note){
    removeDir(noteFolderPath(note.guid));
}
void FileUtils::removeNoteDir(){
    removeDir(notesFolderPath());
}
QString FileUtils::readNoteContent(NoteWrapper* note){
     QFile contentFile(FileUtils::noteContentFilePath(note));

    contentFile.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream in(&contentFile);
    QString result = "";

    while(!in.atEnd()){
        QString line = in.readLine();
        result += line;
    }
    contentFile.close();
    return result;
}
<commit_msg>Remove extra html and have the home path become MyDocs path.<commit_after>#include "fileutils.h"

const QString FileUtils::NOTES_FOLDER = "notes";
const QString FileUtils::APP_FOLDER = ".evernote";
const QString FileUtils::MY_DOCS_FOLDER = "/home/user/MyDocs";
const QString FileUtils::CONTENT_FILENAME = "content.html";

FileUtils::FileUtils(QObject *parent) :
    QObject(parent)
{
}

void FileUtils::cacheNoteContent(NoteWrapper *note, QString content){
    QDir mydocs(myDocsFolderPath());
    mydocs.mkdir(APP_FOLDER);

    QDir appDir(appFolderPath());
    appDir.mkdir(NOTES_FOLDER);

    QDir notesFolder(notesFolderPath());
    QString noteFolderName = QString::fromStdString(note->getGuid());
    notesFolder.mkdir(noteFolderName);

    QDir noteFolder(noteFolderPath(note));

    QString contentFileName = noteFolder.filePath(CONTENT_FILENAME);

    qDebug() << "content file name: " << contentFileName;

    QFile contentFile(contentFileName);

    contentFile.open(QIODevice::WriteOnly | QIODevice::Text);

    QTextStream out(&contentFile);

    out << content;
    out.flush();
    contentFile.flush();
    contentFile.close();
}

void FileUtils::cacheResourceContent(Resource r){
    QDir noteFolder(noteFolderPath(r.noteGuid));
    noteFolder.mkdir(QString::fromStdString(r.guid));

    QDir resourceFolder(resourceFolderPath(r));
    QFile contentFile(resourceFolder.filePath(QString::fromStdString(r.guid)+"."+getExtension(r)));
    contentFile.open(QIODevice::WriteOnly | QIODevice::Text);

    qDebug() << "hash: " << QString::fromStdString(r.data.bodyHash);

    contentFile.write(r.data.body.data(),r.data.size);

    contentFile.flush();
    contentFile.close();
}

QString FileUtils::myDocsFolderPath(){
    return QDir::homePath();
}
QString FileUtils::appFolderPath(){
    return myDocsFolderPath() + QDir::separator() + APP_FOLDER;
}
QString FileUtils::notesFolderPath(){
    return appFolderPath() + QDir::separator() + NOTES_FOLDER;
}
QString FileUtils::noteFolderPath(NoteWrapper *note){
   return noteFolderPath(note->getGuid());
}
QString FileUtils::noteFolderPath(std::string noteGuid){
 return notesFolderPath() + QDir::separator()+QString::fromStdString(noteGuid);
}

QString FileUtils::noteContentFilePath(NoteWrapper *note){
    return noteFolderPath(note) + QDir::separator() + CONTENT_FILENAME;
}

QString FileUtils::resourceFolderPath(Resource r){
    return notesFolderPath() + QDir::separator() + QString::fromStdString(r.noteGuid)+ QDir::separator() + QString::fromStdString(r.guid);
}
QString FileUtils::resourceContentFilePath(Resource r){
    return resourceFolderPath(r) + QDir::separator() + QString::fromStdString(r.guid)+"."+getExtension(r);
}

bool FileUtils::noteCached(NoteWrapper *note){
    QFile contentFile(noteContentFilePath(note));
    return contentFile.exists();
}
bool FileUtils::resourceCached(Resource r){
    QFile resourceContentFile(resourceContentFilePath(r));
    return resourceContentFile.exists();
}

QString FileUtils::getExtension(Resource r){
    if(r.mime == "audio/mpeg"){
        return "mp3";
    }else if(r.mime == "image/jpeg" || r.mime == "image/pjpeg" || r.mime == "image/jpg"){
        return "jpeg";
    }else if(r.mime == "text/plain"){
        return "txt";
    }else if(r.mime == "text/html"){
        return "html";
    }else if(r.mime == "image/png"){
        return "png";
    }else if(r.mime == "image/gif"){
        return "gif";
    }else if(r.mime == "image/bmp"){
        return "bmp";
    }else if(r.mime == "audio/wav" || r.mime == "audio/vnd.wave"){
        return "wav";
    }else if(r.mime == "audio/amr"){
        return "amr";
    }else if(r.mime == "application/pdf"){
        return "pdf";
    }else if(r.mime == "application/msword"){
        return "doc";
    }else if(r.mime == "application/vnd.openxmlformats-officedocument.wordprocessingml.document"){
        return "docx";
    }
    return "";
}
bool FileUtils::removeDir(const QString &dirName)
{
    bool result = true;
    QDir dir(dirName);

    if (dir.exists(dirName)) {
        Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden  | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
            if (info.isDir()) {
                result = removeDir(info.absoluteFilePath());
            }
            else {
                result = QFile::remove(info.absoluteFilePath());
            }

            if (!result) {
                return result;
            }
        }
        result = dir.rmdir(dirName);
    }

    return result;
}
void FileUtils::removeNoteCache(Note note){
    removeDir(noteFolderPath(note.guid));
}
void FileUtils::removeNoteDir(){
    removeDir(notesFolderPath());
}
QString FileUtils::readNoteContent(NoteWrapper* note){
     QFile contentFile(FileUtils::noteContentFilePath(note));

    contentFile.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream in(&contentFile);
    QString result = "";

    while(!in.atEnd()){
        QString line = in.readLine();
        result += line;
    }
    contentFile.close();
    return result;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "cpu_linux.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

namespace webrtc {
CpuLinux::CpuLinux()
    : m_oldBusyTime(0),
      m_oldIdleTime(0),
      m_oldBusyTimeMulti(NULL),
      m_oldIdleTimeMulti(NULL),
      m_idleArray(NULL),
      m_busyArray(NULL),
      m_resultArray(NULL),
      m_numCores(0) {
    const int result = GetNumCores();
    if (result != -1) {
      m_numCores = result;
      m_oldBusyTimeMulti = new long long[m_numCores];
      memset(m_oldBusyTimeMulti, 0, sizeof(long long) * m_numCores);
      m_oldIdleTimeMulti = new long long[m_numCores];
      memset(m_oldIdleTimeMulti, 0, sizeof(long long) * m_numCores);
      m_idleArray = new long long[m_numCores];
      memset(m_idleArray, 0, sizeof(long long) * m_numCores);
      m_busyArray = new long long[m_numCores];
      memset(m_busyArray, 0, sizeof(long long) * m_numCores);
      m_resultArray = new WebRtc_UWord32[m_numCores];

      GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray);
    }
}

CpuLinux::~CpuLinux()
{
    delete [] m_oldBusyTimeMulti;
    delete [] m_oldIdleTimeMulti;
    delete [] m_idleArray;
    delete [] m_busyArray;
    delete [] m_resultArray;
}

WebRtc_Word32 CpuLinux::CpuUsage()
{
    WebRtc_UWord32 dummy = 0;
    WebRtc_UWord32* dummyArray = NULL;
    return CpuUsageMultiCore(dummy, dummyArray);
}

WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& numCores,
                                          WebRtc_UWord32*& coreArray)
{
    coreArray = m_resultArray;
    numCores = m_numCores;
    long long busy = 0;
    long long idle = 0;
    GetData(busy, idle, m_busyArray, m_idleArray);

    long long deltaBusy = busy - m_oldBusyTime;
    long long deltaIdle = idle - m_oldIdleTime;
    m_oldBusyTime = busy;
    m_oldIdleTime = idle;

    int retVal = -1;
    if (deltaBusy + deltaIdle == 0)
    {
        retVal = 0;
    }
    else
    {
        retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle));
    }

    if (coreArray == NULL)
    {
      return retVal;
    }

    for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
    {
        deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i];
        deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i];
        m_oldBusyTimeMulti[i] = m_busyArray[i];
        m_oldIdleTimeMulti[i] = m_idleArray[i];
        if(deltaBusy + deltaIdle == 0)
        {
            coreArray[i] = 0;
        }
        else
        {
            coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle));
        }
    }
    return retVal;
}

int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray,
                      long long*& idleArray)
{
    FILE* fp = fopen("/proc/stat", "r");
    if (!fp)
    {
        return -1;
    }

    char line[100];
    char* dummy = fgets(line, 100, fp);
    char firstWord[100];
    sscanf(line, "%s ", firstWord);
    if(strncmp(firstWord, "cpu", 3)!=0)
    {
        return -1;
    }
    char sUser[100];
    char sNice[100];
    char sSystem[100];
    char sIdle[100];
    sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem, sIdle);
    long long luser = atoll(sUser);
    long long lnice = atoll(sNice);
    long long lsystem = atoll(sSystem);
    long long lidle = atoll (sIdle);

    busy = luser + lnice + lsystem;
    idle = lidle;
    for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
    {
        dummy = fgets(line, 100, fp);
        sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem,
               sIdle);
        luser = atoll(sUser);
        lnice = atoll(sNice);
        lsystem = atoll(sSystem);
        lidle = atoll (sIdle);
        busyArray[i] = luser + lnice + lsystem;
        idleArray[i] = lidle;
    }
    fclose(fp);
    return 0;
}

int CpuLinux::GetNumCores()
{
    FILE* fp = fopen("/proc/stat", "r");
    if (!fp)
    {
        return -1;
    }
    // Skip first line
    char line[100];
    if (!fgets(line, 100, fp))
    {
        return -1;
    }
    int numCores = -1;
    char firstWord[100];
    do
    {
        numCores++;
        if (fgets(line, 100, fp))
        {
            sscanf(line, "%s ", firstWord);
        } else {
            break;
        }
    } while (strncmp(firstWord, "cpu", 3) == 0);
    fclose(fp);
    return numCores;
}
} // namespace webrtc
<commit_msg>The variable ‘dummy’ set but not used being treated as errors in Fedora. Review URL: http://webrtc-codereview.appspot.com/122004<commit_after>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "cpu_linux.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

namespace webrtc {
CpuLinux::CpuLinux()
    : m_oldBusyTime(0),
      m_oldIdleTime(0),
      m_oldBusyTimeMulti(NULL),
      m_oldIdleTimeMulti(NULL),
      m_idleArray(NULL),
      m_busyArray(NULL),
      m_resultArray(NULL),
      m_numCores(0) {
    const int result = GetNumCores();
    if (result != -1) {
      m_numCores = result;
      m_oldBusyTimeMulti = new long long[m_numCores];
      memset(m_oldBusyTimeMulti, 0, sizeof(long long) * m_numCores);
      m_oldIdleTimeMulti = new long long[m_numCores];
      memset(m_oldIdleTimeMulti, 0, sizeof(long long) * m_numCores);
      m_idleArray = new long long[m_numCores];
      memset(m_idleArray, 0, sizeof(long long) * m_numCores);
      m_busyArray = new long long[m_numCores];
      memset(m_busyArray, 0, sizeof(long long) * m_numCores);
      m_resultArray = new WebRtc_UWord32[m_numCores];

      GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray);
    }
}

CpuLinux::~CpuLinux()
{
    delete [] m_oldBusyTimeMulti;
    delete [] m_oldIdleTimeMulti;
    delete [] m_idleArray;
    delete [] m_busyArray;
    delete [] m_resultArray;
}

WebRtc_Word32 CpuLinux::CpuUsage()
{
    WebRtc_UWord32 dummy = 0;
    WebRtc_UWord32* dummyArray = NULL;
    return CpuUsageMultiCore(dummy, dummyArray);
}

WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& numCores,
                                          WebRtc_UWord32*& coreArray)
{
    coreArray = m_resultArray;
    numCores = m_numCores;
    long long busy = 0;
    long long idle = 0;
    if (GetData(busy, idle, m_busyArray, m_idleArray) != 0)
        return -1;

    long long deltaBusy = busy - m_oldBusyTime;
    long long deltaIdle = idle - m_oldIdleTime;
    m_oldBusyTime = busy;
    m_oldIdleTime = idle;

    int retVal = -1;
    if (deltaBusy + deltaIdle == 0)
    {
        retVal = 0;
    }
    else
    {
        retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle));
    }

    if (coreArray == NULL)
    {
      return retVal;
    }

    for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
    {
        deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i];
        deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i];
        m_oldBusyTimeMulti[i] = m_busyArray[i];
        m_oldIdleTimeMulti[i] = m_idleArray[i];
        if(deltaBusy + deltaIdle == 0)
        {
            coreArray[i] = 0;
        }
        else
        {
            coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle));
        }
    }
    return retVal;
}

int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray,
                      long long*& idleArray)
{
    FILE* fp = fopen("/proc/stat", "r");
    if (!fp)
    {
        return -1;
    }

    char line[100];
    if (fgets(line, 100, fp) == NULL) {
        fclose(fp);
        return -1;
    }
    char firstWord[100];
    if (sscanf(line, "%s ", firstWord) != 1) {
        fclose(fp);
        return -1;
    }
    if (strncmp(firstWord, "cpu", 3) != 0) {
        fclose(fp);
        return -1;
    }
    char sUser[100];
    char sNice[100];
    char sSystem[100];
    char sIdle[100];
    if (sscanf(line, "%s %s %s %s %s ",
               firstWord, sUser, sNice, sSystem, sIdle) != 5) {
        fclose(fp);
        return -1;
    }
    long long luser = atoll(sUser);
    long long lnice = atoll(sNice);
    long long lsystem = atoll(sSystem);
    long long lidle = atoll (sIdle);

    busy = luser + lnice + lsystem;
    idle = lidle;
    for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
    {
        if (fgets(line, 100, fp) == NULL) {
            fclose(fp);
            return -1;
        }
        if (sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem,
                   sIdle) != 5) {
            fclose(fp);
            return -1;
        }
        luser = atoll(sUser);
        lnice = atoll(sNice);
        lsystem = atoll(sSystem);
        lidle = atoll (sIdle);
        busyArray[i] = luser + lnice + lsystem;
        idleArray[i] = lidle;
    }
    fclose(fp);
    return 0;
}

int CpuLinux::GetNumCores()
{
    FILE* fp = fopen("/proc/stat", "r");
    if (!fp)
    {
        return -1;
    }
    // Skip first line
    char line[100];
    if (!fgets(line, 100, fp))
    {
        return -1;
    }
    int numCores = -1;
    char firstWord[100];
    do
    {
        numCores++;
        if (fgets(line, 100, fp))
        {
            if (sscanf(line, "%s ", firstWord) != 1) {
                firstWord[0] = '\0';
            }
        } else {
            break;
        }
    } while (strncmp(firstWord, "cpu", 3) == 0);
    fclose(fp);
    return numCores;
}
} // namespace webrtc
<|endoftext|>


<commit_before>/**
 * C S O U N D   V S T
 *
 * A VST plugin version of Csound, with Python scripting.
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifdef _MSC_VER
#pragma warning (disable:4786)
#endif
#include "Node.hpp"

namespace csound
{
  Node::Node()
  {
    localCoordinates.resize(Event::ELEMENT_COUNT, Event::ELEMENT_COUNT);
    localCoordinates = createTransform();
  }

  Node::~Node()
  {
  }

  ublas::matrix<double> Node::createTransform()
  {
    ublas::matrix<double> matrix = ublas::identity_matrix<double>(Event::ELEMENT_COUNT, Event::ELEMENT_COUNT);
    return matrix;
  }

  ublas::matrix<double> Node::getLocalCoordinates() const
  {
    return localCoordinates;
  }

  ublas::matrix<double> Node::traverse(const ublas::matrix<double> &globalCoordinates, Score &score)
  {
    // Obtain the composite transformation of coordinate system
    // by post-concatenating the local transformation of coordinate system
    // with the global, or enclosing, transformation of coordinate system.
    ublas::matrix<double> compositeCoordinates = ublas::prod(getLocalCoordinates(), globalCoordinates);
    // Make a bookmark for the current end of the score.
    size_t beginAt = score.size();
    // Descend into each of the child nodes.
    for(std::vector<Node*>::iterator i = children.begin(); i != children.end(); ++i)
      {
        (*i)->traverse(compositeCoordinates, score);
      }
    // Make a bookmark for the new end of the score,
    // thus enclosing all Events that may have been produced or transformed
    // by all the child nodes.
    size_t endAt = score.size();
    // Take the score and optionally transform Events between the bookmarks,
    // or append new Events.
    produceOrTransform(score, beginAt, endAt, compositeCoordinates);
    // Return the composite transformation of coordinate system.
    return compositeCoordinates;
  }

  void Node::clear()
  {
    Node *node = 0;
    for(std::vector<Node*>::iterator i = children.begin(); i != children.end(); ++i)
      {
        node = *i;
        node->clear();
      }
    children.clear();
  }

  void Node::produceOrTransform(Score &score, size_t beginAt, size_t endAt, const ublas::matrix<double> &globalCoordinates)
  {
  }

  double &Node::element(size_t row, size_t column)
  {
    return localCoordinates(row, column);
  }

  void Node::setElement(size_t row, size_t column, double value)
  {
    localCoordinates(row, column) = value;
  }

  void Node::addChild(Node *node)
  {
    children.push_back(node);
  }
}
<commit_msg>Fixed bug in Node::traverse where composite transform was not actually applied to child events.<commit_after>/**
 * C S O U N D   V S T
 *
 * A VST plugin version of Csound, with Python scripting.
 *
 * L I C E N S E
 *
 * This software is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifdef _MSC_VER
#pragma warning (disable:4786)
#endif
#include "Node.hpp"

namespace csound
{
  Node::Node()
  {
    localCoordinates.resize(Event::ELEMENT_COUNT, Event::ELEMENT_COUNT);
    localCoordinates = createTransform();
  }

  Node::~Node()
  {
  }

  ublas::matrix<double> Node::createTransform()
  {
    ublas::matrix<double> matrix = ublas::identity_matrix<double>(Event::ELEMENT_COUNT, Event::ELEMENT_COUNT);
    return matrix;
  }

  ublas::matrix<double> Node::getLocalCoordinates() const
  {
    return localCoordinates;
  }

  ublas::matrix<double> Node::traverse(const ublas::matrix<double> &globalCoordinates, Score &score)
  {
    // Obtain the composite transformation of coordinate system
    // by post-concatenating the local transformation of coordinate system
    // with the global, or enclosing, transformation of coordinate system.
    ublas::matrix<double> compositeCoordinates = ublas::prod(getLocalCoordinates(), globalCoordinates);
    // Make a bookmark for the current end of the score.
    size_t beginAt = score.size();
    // Descend into each of the child nodes.
    for(std::vector<Node*>::iterator i = children.begin(); i != children.end(); ++i)
      {
        (*i)->traverse(compositeCoordinates, score);
      }
    // Make a bookmark for the new end of the score,
    // thus enclosing all Events that may have been produced or transformed
    // by all the child nodes.
    size_t endAt = score.size();
    // Take the score and optionally transform Events between the bookmarks,
    // or append new Events.
    produceOrTransform(score, beginAt, endAt, compositeCoordinates);
    size_t finalEndAt = score.size();
    // Apply the global transformation of coordinate system to all child events,
    // including events produced by this node.
    for (size_t i = beginAt; i < finalEndAt; i++) {
      score[i] = ublas::prod(compositeCoordinates, score[i]);
    }
    // Return the composite transformation of coordinate system.
    return compositeCoordinates;
  }

  void Node::clear()
  {
    Node *node = 0;
    for(std::vector<Node*>::iterator i = children.begin(); i != children.end(); ++i)
      {
        node = *i;
        node->clear();
      }
    children.clear();
  }

  void Node::produceOrTransform(Score &score, size_t beginAt, size_t endAt, const ublas::matrix<double> &globalCoordinates)
  {
  }

  double &Node::element(size_t row, size_t column)
  {
    return localCoordinates(row, column);
  }

  void Node::setElement(size_t row, size_t column, double value)
  {
    localCoordinates(row, column) = value;
  }

  void Node::addChild(Node *node)
  {
    children.push_back(node);
  }
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include "XMLDriver.h"
#include "Nebula.h"
#include <sstream>
#include <fstream>
#include <math.h>

int XMLDriver::deployment_description(
    const VirtualMachine *  vm,
    const string&           file_name) const
{
    ofstream    file;
    string      xml;

    file.open(file_name.c_str(), ios::out);

    if (file.fail() == true)
    {
        vm->log("VMM", Log::ERROR, "Could not open XML deployment file.");
        return -1;
    }

    file << vm->template_to_xml(xml);

    file.close();

    return 0;
}
<commit_msg>bug #2025: Generate full template for XML driver (cherry picked from commit b79838f5498810c69e38c7a3fce29d7cb3189ae1)<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include "XMLDriver.h"
#include "Nebula.h"
#include <sstream>
#include <fstream>
#include <math.h>

int XMLDriver::deployment_description(
    const VirtualMachine *  vm,
    const string&           file_name) const
{
    ofstream    file;
    string      xml;

    file.open(file_name.c_str(), ios::out);

    if (file.fail() == true)
    {
        vm->log("VMM", Log::ERROR, "Could not open XML deployment file.");
        return -1;
    }

    file << vm->to_xml(xml);

    file.close();

    return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/

#include <algorithm>

#include <tightdb/column_backlink.hpp>
#include <tightdb/column_link.hpp>
#include <tightdb/table.hpp>

using namespace std;
using namespace tightdb;

void ColumnBackLink::add_backlink(size_t row_ndx, size_t origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);

    // A backlink list of size 1 is stored as a single non-ref column value.
    if (value == 0) {
        int_fast64_t value_2 = 1 + 2 * int_fast64_t(origin_row_ndx);
        Column::set(row_ndx, value_2); // Throws
        return;
    }

    ref_type ref;
    // When increasing the size of the backlink list from 1 to 2, we need to
    // convert from the single non-ref column value representation, to a B+-tree
    // representation.
    if (value % 2 != 0) {
        // Create new column to hold backlinks
        size_t size = 1;
        int_fast64_t value_2 = value / 2;
        ref = Column::create(Array::type_Normal, size, value_2, get_alloc()); // Throws
        Column::set(row_ndx, int_fast64_t(ref)); // Throws
    }
    else {
        ref = to_ref(value);
    }
    Column col(ref, this, row_ndx, get_alloc()); // Throws
    col.add(int_fast64_t(origin_row_ndx)); // Throws
}

size_t ColumnBackLink::get_backlink_count(size_t row_ndx) const TIGHTDB_NOEXCEPT
{
    int_fast64_t value = Column::get(row_ndx);

    if (value == 0)
        return 0;

    if (value % 2 != 0)
        return 1;

    // get list size
    ref_type ref = to_ref(value);
    return ColumnBase::get_size_from_ref(ref, get_alloc());
}

size_t ColumnBackLink::get_backlink(size_t row_ndx, size_t backlink_ndx) const TIGHTDB_NOEXCEPT
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    size_t origin_row_ndx;
    if (value % 2 != 0) {
        TIGHTDB_ASSERT(backlink_ndx == 0);
        origin_row_ndx = to_size_t(value / 2);
    }
    else {
        ref_type ref = to_ref(value);
        TIGHTDB_ASSERT(backlink_ndx < ColumnBase::get_size_from_ref(ref, get_alloc()));
        // FIXME: Optimize with direct access (that is, avoid creation of a
        // Column instance, since that implies dynamic allocation).
        Column col(ref, 0, 0, get_alloc());
        int_fast64_t value_2 = col.get(backlink_ndx);
        origin_row_ndx = to_size_t(value_2);
    }
    return origin_row_ndx;
}

void ColumnBackLink::remove_backlink(size_t row_ndx, size_t origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    // If there is only a single backlink, it can be stored as
    // a tagged value
    if (value % 2 != 0) {
        TIGHTDB_ASSERT(to_size_t(value/2) == origin_row_ndx);
        Column::set(row_ndx, 0);
        return;
    }

    // if there is a list of backlinks we have to find
    // the right one and remove it.
    ref_type ref = to_ref(value);
    Column col(ref, this, row_ndx, get_alloc());
    int_fast64_t value_2 = int_fast64_t(origin_row_ndx);
    size_t backlink_ndx = col.find_first(value_2);
    TIGHTDB_ASSERT(backlink_ndx != not_found);
    size_t num_links = col.size();
    bool is_last = backlink_ndx+1 == num_links;
    col.erase(backlink_ndx, is_last);
    --num_links;

    // If there is only one backlink left we can inline it as tagged value
    if (num_links == 1) {
        int_fast64_t value_3 = col.get(0);
        col.destroy();

        int_fast64_t value_4 = 1 + 2 * value_3;
        Column::set(row_ndx, value_4);
    }
}

void ColumnBackLink::update_backlink(size_t row_ndx, size_t old_origin_row_ndx,
                                     size_t new_origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    if (value % 2 != 0) {
        TIGHTDB_ASSERT(to_size_t(value/2) == old_origin_row_ndx);
        int_fast64_t value_2 = 1 + 2 * int_fast64_t(new_origin_row_ndx);
        Column::set(row_ndx, value_2);
        return;
    }

    // Find match in backlink list and replace
    ref_type ref = to_ref(value);
    Column col(ref, this, row_ndx, get_alloc());
    int_fast64_t value_2 = int_fast64_t(old_origin_row_ndx);
    size_t backlink_ndx = col.find_first(value_2);
    TIGHTDB_ASSERT(backlink_ndx != not_found);
    int_fast64_t value_3 = int_fast64_t(new_origin_row_ndx);
    col.set(backlink_ndx, value_3);
}

void ColumnBackLink::nullify_links(size_t row_ndx, bool do_destroy)
{
    // Nullify all links pointing to the row being deleted
    int_fast64_t value = Column::get(row_ndx);
    if (value != 0) {
        if (value % 2 != 0) {
            size_t origin_row_ndx = to_size_t(value / 2);
            m_origin_column->do_nullify_link(origin_row_ndx, row_ndx); // Throws
        }
        else {
            // nullify entire list of links
            ref_type ref = to_ref(value);
            Column col(ref, 0, 0, get_alloc()); // Throws

            size_t n = col.size();
            for (size_t i = 0; i < n; ++i) {
                int_fast64_t value_2 = col.get(i);
                size_t origin_row_ndx = to_size_t(value_2);
                m_origin_column->do_nullify_link(origin_row_ndx, row_ndx); // Throws
            }

            if (do_destroy)
                col.destroy();
        }
    }
}

void ColumnBackLink::move_last_over(size_t target_row_ndx, size_t last_row_ndx)
{
    TIGHTDB_ASSERT(target_row_ndx < last_row_ndx);
    TIGHTDB_ASSERT(last_row_ndx + 1 == size());

    // Nullify all links pointing to the row being deleted
    bool do_destroy = true;
    nullify_links(target_row_ndx, do_destroy); // Throws

    // Update all links to the last row to point to the new row instead
    int_fast64_t value = Column::get(last_row_ndx);
    if (value != 0) {
        if (value % 2 != 0) {
            size_t origin_row_ndx = to_size_t(value / 2);
            m_origin_column->do_update_link(origin_row_ndx, last_row_ndx, target_row_ndx); // Throws
        }
        else {
            // update entire list of links
            ref_type ref = to_ref(value);
            Column col(ref, 0, 0, get_alloc()); // Throws

            size_t n = col.size();
            for (size_t i = 0; i < n; ++i) {
                int_fast64_t value_2 = col.get(i);
                size_t origin_row_ndx = to_size_t(value_2);
                m_origin_column->do_update_link(origin_row_ndx, last_row_ndx, target_row_ndx); // Throws
            }
        }
    }

    // Do the actual move
    Column::set(target_row_ndx, value); // Throws
    bool is_last = true;
    Column::erase(last_row_ndx, is_last); // Throws
}

void ColumnBackLink::erase(std::size_t row_ndx, bool is_last)
{
    TIGHTDB_ASSERT(is_last);
    bool do_destroy = true;
    nullify_links(row_ndx, do_destroy); // Throws
    Column::erase(row_ndx, is_last); // Throws
}

void ColumnBackLink::clear()
{
    size_t n = size();
    for (size_t i = 0; i < n; ++i) {
        // Column::clear() handles the destruction of subtrees
        bool do_destroy = false;
        nullify_links(i, do_destroy); // Throws
    }
    Column::clear(); // Throws
    // FIXME: This one is needed because Column::clear() forgets about
    // the leaf type. A better solution should probably be found.
    m_array->set_type(Array::type_HasRefs);
}

void ColumnBackLink::update_child_ref(size_t child_ndx, ref_type new_ref)
{
    Column::set(child_ndx, new_ref); // Throws
}

ref_type ColumnBackLink::get_child_ref(size_t child_ndx) const TIGHTDB_NOEXCEPT
{
    return Column::get_as_ref(child_ndx);
}

#ifdef TIGHTDB_DEBUG

namespace {

size_t verify_leaf(MemRef mem, Allocator& alloc)
{
    Array leaf(alloc);
    leaf.init_from_mem(mem);
    leaf.Verify();
    TIGHTDB_ASSERT(leaf.has_refs());
    return leaf.size();
}

} // anonymous namespace

void ColumnBackLink::Verify() const
{
    if (root_is_leaf()) {
        m_array->Verify();
        TIGHTDB_ASSERT(m_array->has_refs());
        return;
    }

    m_array->verify_bptree(&verify_leaf);
}

void ColumnBackLink::Verify(const Table& table, size_t col_ndx) const
{
    Column::Verify(table, col_ndx);

    // Check that the origin column specifies the right target
    TIGHTDB_ASSERT(&m_origin_column->get_target_table() == &table);
    TIGHTDB_ASSERT(&m_origin_column->get_backlink_column() == this);

    // Check that m_origin_table is the table specified by the spec
    size_t origin_table_ndx = m_origin_table->get_index_in_parent();
    typedef _impl::TableFriend tf;
    const Spec& spec = tf::get_spec(table);
    TIGHTDB_ASSERT(origin_table_ndx == spec.get_opposite_link_table_ndx(col_ndx));
}

void ColumnBackLink::get_backlinks(vector<VerifyPair>& pairs)
{
    VerifyPair pair;
    size_t n = size();
    for (size_t i = 0; i < n ; ++i) {
        pair.target_row_ndx = i;
        size_t m = get_backlink_count(i);
        for (size_t j = 0; j < m; ++j) {
            pair.origin_row_ndx = get_backlink(i,j);
            pairs.push_back(pair);
        }
    }
    sort(pairs.begin(), pairs.end());
}

pair<ref_type, size_t> ColumnBackLink::get_to_dot_parent(size_t ndx_in_parent) const
{
    pair<MemRef, size_t> p = m_array->get_bptree_leaf(ndx_in_parent);
    return make_pair(p.first.m_ref, p.second);
}

#endif // TIGHTDB_DEBUG
<commit_msg>Fix for: Fixed leak in ColumnBackLink::erase()<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/

#include <algorithm>

#include <tightdb/column_backlink.hpp>
#include <tightdb/column_link.hpp>
#include <tightdb/table.hpp>

using namespace std;
using namespace tightdb;

void ColumnBackLink::add_backlink(size_t row_ndx, size_t origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);

    // A backlink list of size 1 is stored as a single non-ref column value.
    if (value == 0) {
        int_fast64_t value_2 = 1 + 2 * int_fast64_t(origin_row_ndx);
        Column::set(row_ndx, value_2); // Throws
        return;
    }

    ref_type ref;
    // When increasing the size of the backlink list from 1 to 2, we need to
    // convert from the single non-ref column value representation, to a B+-tree
    // representation.
    if (value % 2 != 0) {
        // Create new column to hold backlinks
        size_t size = 1;
        int_fast64_t value_2 = value / 2;
        ref = Column::create(Array::type_Normal, size, value_2, get_alloc()); // Throws
        Column::set(row_ndx, int_fast64_t(ref)); // Throws
    }
    else {
        ref = to_ref(value);
    }
    Column col(ref, this, row_ndx, get_alloc()); // Throws
    col.add(int_fast64_t(origin_row_ndx)); // Throws
}

size_t ColumnBackLink::get_backlink_count(size_t row_ndx) const TIGHTDB_NOEXCEPT
{
    int_fast64_t value = Column::get(row_ndx);

    if (value == 0)
        return 0;

    if (value % 2 != 0)
        return 1;

    // get list size
    ref_type ref = to_ref(value);
    return ColumnBase::get_size_from_ref(ref, get_alloc());
}

size_t ColumnBackLink::get_backlink(size_t row_ndx, size_t backlink_ndx) const TIGHTDB_NOEXCEPT
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    size_t origin_row_ndx;
    if (value % 2 != 0) {
        TIGHTDB_ASSERT(backlink_ndx == 0);
        origin_row_ndx = to_size_t(value / 2);
    }
    else {
        ref_type ref = to_ref(value);
        TIGHTDB_ASSERT(backlink_ndx < ColumnBase::get_size_from_ref(ref, get_alloc()));
        // FIXME: Optimize with direct access (that is, avoid creation of a
        // Column instance, since that implies dynamic allocation).
        Column col(ref, 0, 0, get_alloc());
        int_fast64_t value_2 = col.get(backlink_ndx);
        origin_row_ndx = to_size_t(value_2);
    }
    return origin_row_ndx;
}

void ColumnBackLink::remove_backlink(size_t row_ndx, size_t origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    // If there is only a single backlink, it can be stored as
    // a tagged value
    if (value % 2 != 0) {
        TIGHTDB_ASSERT(to_size_t(value/2) == origin_row_ndx);
        Column::set(row_ndx, 0);
        return;
    }

    // if there is a list of backlinks we have to find
    // the right one and remove it.
    ref_type ref = to_ref(value);
    Column col(ref, this, row_ndx, get_alloc());
    int_fast64_t value_2 = int_fast64_t(origin_row_ndx);
    size_t backlink_ndx = col.find_first(value_2);
    TIGHTDB_ASSERT(backlink_ndx != not_found);
    size_t num_links = col.size();
    bool is_last = backlink_ndx+1 == num_links;
    col.erase(backlink_ndx, is_last);
    --num_links;

    // If there is only one backlink left we can inline it as tagged value
    if (num_links == 1) {
        int_fast64_t value_3 = col.get(0);
        col.destroy();

        int_fast64_t value_4 = 1 + 2 * value_3;
        Column::set(row_ndx, value_4);
    }
}

void ColumnBackLink::update_backlink(size_t row_ndx, size_t old_origin_row_ndx,
                                     size_t new_origin_row_ndx)
{
    int_fast64_t value = Column::get(row_ndx);
    TIGHTDB_ASSERT(value != 0);

    if (value % 2 != 0) {
        TIGHTDB_ASSERT(to_size_t(value/2) == old_origin_row_ndx);
        int_fast64_t value_2 = 1 + 2 * int_fast64_t(new_origin_row_ndx);
        Column::set(row_ndx, value_2);
        return;
    }

    // Find match in backlink list and replace
    ref_type ref = to_ref(value);
    Column col(ref, this, row_ndx, get_alloc());
    int_fast64_t value_2 = int_fast64_t(old_origin_row_ndx);
    size_t backlink_ndx = col.find_first(value_2);
    TIGHTDB_ASSERT(backlink_ndx != not_found);
    int_fast64_t value_3 = int_fast64_t(new_origin_row_ndx);
    col.set(backlink_ndx, value_3);
}

void ColumnBackLink::nullify_links(size_t row_ndx, bool do_destroy)
{
    // Nullify all links pointing to the row being deleted
    int_fast64_t value = Column::get(row_ndx);
    if (value != 0) {
        if (value % 2 != 0) {
            size_t origin_row_ndx = to_size_t(value / 2);
            m_origin_column->do_nullify_link(origin_row_ndx, row_ndx); // Throws
        }
        else {
            // nullify entire list of links
            ref_type ref = to_ref(value);
            Column col(ref, 0, 0, get_alloc()); // Throws

            size_t n = col.size();
            for (size_t i = 0; i < n; ++i) {
                int_fast64_t value_2 = col.get(i);
                size_t origin_row_ndx = to_size_t(value_2);
                m_origin_column->do_nullify_link(origin_row_ndx, row_ndx); // Throws
            }

            if (do_destroy)
                col.destroy();
        }
    }
}

void ColumnBackLink::move_last_over(size_t target_row_ndx, size_t last_row_ndx)
{
    TIGHTDB_ASSERT(target_row_ndx < last_row_ndx);
    TIGHTDB_ASSERT(last_row_ndx + 1 == size());

    // Nullify all links pointing to the row being deleted
    bool do_destroy = true;
    nullify_links(target_row_ndx, do_destroy); // Throws

    // Update all links to the last row to point to the new row instead
    int_fast64_t value = Column::get(last_row_ndx);
    if (value != 0) {
        if (value % 2 != 0) {
            size_t origin_row_ndx = to_size_t(value / 2);
            m_origin_column->do_update_link(origin_row_ndx, last_row_ndx, target_row_ndx); // Throws
        }
        else {
            // update entire list of links
            ref_type ref = to_ref(value);
            Column col(ref, 0, 0, get_alloc()); // Throws

            size_t n = col.size();
            for (size_t i = 0; i < n; ++i) {
                int_fast64_t value_2 = col.get(i);
                size_t origin_row_ndx = to_size_t(value_2);
                m_origin_column->do_update_link(origin_row_ndx, last_row_ndx, target_row_ndx); // Throws
            }
        }
    }

    // Do the actual move
    Column::set(target_row_ndx, value); // Throws
    bool is_last = true;
    Column::erase(last_row_ndx, is_last); // Throws
}

void ColumnBackLink::erase(size_t row_ndx, bool is_last)
{
    TIGHTDB_ASSERT(is_last);
    bool do_destroy = true;
    nullify_links(row_ndx, do_destroy); // Throws
    Column::erase(row_ndx, is_last); // Throws
}

void ColumnBackLink::clear()
{
    size_t n = size();
    for (size_t i = 0; i < n; ++i) {
        // Column::clear() handles the destruction of subtrees
        bool do_destroy = false;
        nullify_links(i, do_destroy); // Throws
    }
    Column::clear(); // Throws
    // FIXME: This one is needed because Column::clear() forgets about
    // the leaf type. A better solution should probably be found.
    m_array->set_type(Array::type_HasRefs);
}

void ColumnBackLink::update_child_ref(size_t child_ndx, ref_type new_ref)
{
    Column::set(child_ndx, new_ref); // Throws
}

ref_type ColumnBackLink::get_child_ref(size_t child_ndx) const TIGHTDB_NOEXCEPT
{
    return Column::get_as_ref(child_ndx);
}

#ifdef TIGHTDB_DEBUG

namespace {

size_t verify_leaf(MemRef mem, Allocator& alloc)
{
    Array leaf(alloc);
    leaf.init_from_mem(mem);
    leaf.Verify();
    TIGHTDB_ASSERT(leaf.has_refs());
    return leaf.size();
}

} // anonymous namespace

void ColumnBackLink::Verify() const
{
    if (root_is_leaf()) {
        m_array->Verify();
        TIGHTDB_ASSERT(m_array->has_refs());
        return;
    }

    m_array->verify_bptree(&verify_leaf);
}

void ColumnBackLink::Verify(const Table& table, size_t col_ndx) const
{
    Column::Verify(table, col_ndx);

    // Check that the origin column specifies the right target
    TIGHTDB_ASSERT(&m_origin_column->get_target_table() == &table);
    TIGHTDB_ASSERT(&m_origin_column->get_backlink_column() == this);

    // Check that m_origin_table is the table specified by the spec
    size_t origin_table_ndx = m_origin_table->get_index_in_parent();
    typedef _impl::TableFriend tf;
    const Spec& spec = tf::get_spec(table);
    TIGHTDB_ASSERT(origin_table_ndx == spec.get_opposite_link_table_ndx(col_ndx));
}

void ColumnBackLink::get_backlinks(vector<VerifyPair>& pairs)
{
    VerifyPair pair;
    size_t n = size();
    for (size_t i = 0; i < n ; ++i) {
        pair.target_row_ndx = i;
        size_t m = get_backlink_count(i);
        for (size_t j = 0; j < m; ++j) {
            pair.origin_row_ndx = get_backlink(i,j);
            pairs.push_back(pair);
        }
    }
    sort(pairs.begin(), pairs.end());
}

pair<ref_type, size_t> ColumnBackLink::get_to_dot_parent(size_t ndx_in_parent) const
{
    pair<MemRef, size_t> p = m_array->get_bptree_leaf(ndx_in_parent);
    return make_pair(p.first.m_ref, p.second);
}

#endif // TIGHTDB_DEBUG
<|endoftext|>


<commit_before>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "x86callstack.h"

#ifdef WIN32
	#include <Windows.h>
	#include <DbgHelp.h>
#else
	#include <cxxabi.h>
	#include <execinfo.h>
#endif

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

static const int kMaxSymbolNameLength = 256;

X86StackFrame::X86StackFrame(void *frmAddr, void *retAddr, const std::string &name)
	: frmAddr_(frmAddr), retAddr_(retAddr), name_(name)
{
}

std::string X86StackFrame::GetString() const {
	std::stringstream stream;

	stream << std::hex << std::setw(8) << std::setfill('0') << retAddr_;
	if (!name_.empty()) {
	       stream << " in " << name_ << " ()";
	} else {
		stream << " in ?? ()";
	}

	return stream.str();
}

static inline void *GetReturnAddress(void *frmAddr) {
	return *reinterpret_cast<void**>(reinterpret_cast<char*>(frmAddr) + 4);
}

static inline void *GetNextFrame(void *frmAddr) {
	return *reinterpret_cast<void**>(frmAddr);
}

X86CallStack::X86CallStack()
	: frames_()
{
	#ifdef WIN32
		PVOID trace[62];
		WORD nframes = CaptureStackBackTrace(0, 62, trace, NULL);

		SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO*>(
				std::calloc(sizeof(*symbol) + kMaxSymbolNameLength, 1));

		symbol->SizeOfStruct = sizeof(*symbol);
		symbol->MaxNameLen = kMaxSymbolNameLength;

		SymInitialize(GetCurrentProcess(), NULL, TRUE);

		for (WORD i = 1; i < nframes; i++) {
			SymFromAddr(GetCurrentProcess(), reinterpret_cast<DWORD64>(trace[i]), NULL, symbol);
			frames_.push_back(X86StackFrame(0, trace[i], symbol->Name));
		}

		std::free(symbol);
	#else
		void *trace[100];

		std::size_t size = backtrace(trace, 100);
		char **strings = backtrace_symbols(trace, size);

		for (std::size_t i = 1; i < size; i++) {
			std::string string(strings[i]);

			std::string::size_type lp = string.find('(');
			std::string::size_type rp = string.find_first_of(")+-");

			std::string name;
			if (lp != std::string::npos && rp != std::string::npos) {
				name.assign(string.begin() + lp + 1, string.begin() + rp);
			}

			if (!name.empty()) {
				char *demangled_name = abi::__cxa_demangle(name.c_str(), 0, 0, 0);
				if (demangled_name != 0) {
					name.assign(demangled_name);
				}
			}

			frames_.push_back(X86StackFrame(0, trace[i], name));
		}

		std::free(strings);
	#endif
}<commit_msg>x86callstack: Back to inline assembly<commit_after>// Copyright (c) 2011-2012, Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "os.h"
#include "x86callstack.h"

#ifdef WIN32
	#include <Windows.h>
	#include <DbgHelp.h>
#else
	#include <cxxabi.h>
	#include <execinfo.h>
#endif

#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>

static const int kMaxSymbolNameLength = 256;

X86StackFrame::X86StackFrame(void *frmAddr, void *retAddr, const std::string &name)
	: frmAddr_(frmAddr), retAddr_(retAddr), name_(name)
{
}

std::string X86StackFrame::GetString() const {
	std::stringstream stream;

	stream << std::hex << std::setw(8) << std::setfill('0') << retAddr_;
	if (!name_.empty()) {
	       stream << " in " << name_ << " ()";
	} else {
		stream << " in ?? ()";
	}

	return stream.str();
}

static inline void *GetReturnAddress(void *frmAddr) {
	return *reinterpret_cast<void**>(reinterpret_cast<char*>(frmAddr) + 4);
}

static inline void *GetNextFrame(void *frmAddr) {
	return *reinterpret_cast<void**>(frmAddr);
}

X86CallStack::X86CallStack()
	: frames_()
{
	void *frmAddr;
	void *retAddr;

	void *stackTop = 0;
	void *stackBot = 0;

	#if defined _MSC_VER
		__asm {
			mov dword ptr [frmAddr], ebp
			mov eax, fs:[0x04]
			mov dword ptr [stackTop], eax
			mov eax, fs:[0x08]
			mov dword ptr [stackBot], eax
		}
	#elif defined __GNUC__
		__asm__ __volatile__(
			"movl %%ebp, %0;" : "=r"(frmAddr) : : );
	#endif

	do {
		if ((frmAddr == 0)
			|| (frmAddr >= stackTop && stackTop != 0)
		    || (frmAddr < stackBot && stackBot != 0)) {
			break;
		}
		retAddr = GetReturnAddress(frmAddr);
		if (retAddr == 0) {
			break;
		}
		frmAddr = GetNextFrame(frmAddr);
		frames_.push_back(X86StackFrame(frmAddr, retAddr, os::GetSymbolName(retAddr)));
	} while (true);
}<|endoftext|>


<commit_before>//
// ulib - a collection of useful classes
// Copyright (C) 2004,2005,2006,2007,2008,2017 Michael Fink
//
/// \file ResourceData.cpp resource data class
//
#include "stdafx.h"
#include <ulib/win32/ResourceData.hpp>

using Win32::ResourceData;

ResourceData::ResourceData(LPCTSTR resourceName, LPCTSTR resourceType, HINSTANCE instanceHandle)
   :m_resourceName(resourceName),
   m_resourceType(resourceType),
   m_global(nullptr),
   m_size(0),
   m_instanceHandle(instanceHandle)
{
}

bool ResourceData::IsAvailable() const
{
   HRSRC resource = FindResource(m_instanceHandle, m_resourceName, m_resourceType);
   return resource != nullptr;
}

bool ResourceData::AsRawData(std::vector<BYTE>& rawData)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return false;

   rawData.resize(size);

   memcpy(&rawData[0], data, size);

   CloseResource();
   return true;
}

CString ResourceData::AsString(bool storedAsUnicode)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return CString();

   // convert to string
   CString text;

   if (storedAsUnicode)
      text = CString(static_cast<LPCWSTR>(data)), size / sizeof(WCHAR);
   else
      text = CString(static_cast<LPCSTR>(data)), size / sizeof(CHAR);

   CloseResource();

   return text;
}

bool ResourceData::AsFile(LPCTSTR filename)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return false;

   // save as file
   {
      HANDLE fileHandle = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
      if (fileHandle == nullptr)
         return false;

      DWORD dwBytesWritten = 0;
      WriteFile(fileHandle, data, size, &dwBytesWritten, nullptr);
      ATLASSERT(size == dwBytesWritten);

      CloseHandle(fileHandle);
   }

   CloseResource();
   return true;
}

LPVOID ResourceData::GetResource(DWORD& size)
{
   HRSRC resource = FindResource(m_instanceHandle, m_resourceName, m_resourceType);
   if (resource == nullptr)
      return nullptr;

   size = SizeofResource(m_instanceHandle, resource);
   if (size == 0)
      return nullptr;

   m_global = LoadResource(m_instanceHandle, resource);
   if (m_global == nullptr)
      return nullptr;

   LPVOID data = LockResource(m_global);
   return data;
}

void ResourceData::CloseResource()
{
   if (m_global != nullptr)
   {
      // normally not needed on win32, but for completeness;
      // on WinCE these two doesn't exists
#ifndef _WIN32_WCE
      UnlockResource(m_global);
      FreeResource(m_global);
#endif
   }
}
<commit_msg>fixed SonarQube bug<commit_after>//
// ulib - a collection of useful classes
// Copyright (C) 2004,2005,2006,2007,2008,2017 Michael Fink
//
/// \file ResourceData.cpp resource data class
//
#include "stdafx.h"
#include <ulib/win32/ResourceData.hpp>

using Win32::ResourceData;

ResourceData::ResourceData(LPCTSTR resourceName, LPCTSTR resourceType, HINSTANCE instanceHandle)
   :m_resourceName(resourceName),
   m_resourceType(resourceType),
   m_global(nullptr),
   m_size(0),
   m_instanceHandle(instanceHandle)
{
}

bool ResourceData::IsAvailable() const
{
   HRSRC resource = FindResource(m_instanceHandle, m_resourceName, m_resourceType);
   return resource != nullptr;
}

bool ResourceData::AsRawData(std::vector<BYTE>& rawData)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return false;

   rawData.resize(size);

   memcpy(&rawData[0], data, size);

   CloseResource();
   return true;
}

CString ResourceData::AsString(bool storedAsUnicode)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return CString();

   // convert to string
   CString text;

   if (storedAsUnicode)
      text = CString(static_cast<LPCWSTR>(data), size / sizeof(WCHAR));
   else
      text = CString(static_cast<LPCSTR>(data), size / sizeof(CHAR));

   CloseResource();

   return text;
}

bool ResourceData::AsFile(LPCTSTR filename)
{
   DWORD size = 0;
   LPVOID data = GetResource(size);
   if (data == nullptr)
      return false;

   // save as file
   {
      HANDLE fileHandle = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
      if (fileHandle == nullptr)
         return false;

      DWORD dwBytesWritten = 0;
      WriteFile(fileHandle, data, size, &dwBytesWritten, nullptr);
      ATLASSERT(size == dwBytesWritten);

      CloseHandle(fileHandle);
   }

   CloseResource();
   return true;
}

LPVOID ResourceData::GetResource(DWORD& size)
{
   HRSRC resource = FindResource(m_instanceHandle, m_resourceName, m_resourceType);
   if (resource == nullptr)
      return nullptr;

   size = SizeofResource(m_instanceHandle, resource);
   if (size == 0)
      return nullptr;

   m_global = LoadResource(m_instanceHandle, resource);
   if (m_global == nullptr)
      return nullptr;

   LPVOID data = LockResource(m_global);
   return data;
}

void ResourceData::CloseResource()
{
   if (m_global != nullptr)
   {
      // normally not needed on win32, but for completeness;
      // on WinCE these two doesn't exists
#ifndef _WIN32_WCE
      UnlockResource(m_global);
      FreeResource(m_global);
#endif
   }
}
<|endoftext|>


<commit_before>#include "debugging.h"
#include <cstdio>
#include <cstring>
#include <mutex>
#if __ANDROID__
  #include <android/log.h>
#endif
#if _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif

#ifdef QUIETLOG
static LogSeverity Filter = LogSeverityWarn;
#else
static LogSeverity Filter = LogSeverityInfo;
#endif
static LogErrorCallback ErrorHandler;
static LogEventCallback EventHandler;
static LogExceptCallback ExceptHandler;
static bool DisableFunctionNames = false;

EXTERNC void SetLogErrorHandler(LogErrorCallback errorHandler)
{
    ErrorHandler = errorHandler;
}
EXTERNC void SetLogEventHandler(LogEventCallback eventHandler)
{
    EventHandler = eventHandler;
}
EXTERNC void SetLogExceptHandler(LogExceptCallback exceptFunc)
{
    ExceptHandler = exceptFunc;
}
EXTERNC void LogDisableFunctionNames()
{
    DisableFunctionNames = true;
}
EXTERNC void SetLogSeverityFilter(LogSeverity filter)
{
    Filter = filter;
}
EXTERNC LogSeverity GetLogSeverityFilter()
{
    return Filter;
}

static int SafeFormat(char* errBuf, int N, const char* format, va_list ap)
{
    int len = vsnprintf(errBuf, size_t(N-1)/*spare room for \n*/, format, ap);
    if (len < 0 || len >= N) { // err: didn't fit
        len = N-2; // try to recover gracefully
        errBuf[len] = '\0';
    }
    return len;
}

#if __linux__
// split at $ and remove /long/path/ leaving just "filename.cpp:123 func() $ message"
static void ShortFilePathMessage(char*& ptr, int& len)
{
    if (char* middle = strchr(ptr, '$')) {
        for (; middle > ptr; --middle) {
            if (*middle == '/' || *middle == '\\') {
                ++middle;
                break;
            }
        }
        len = int((ptr + len) - middle);
        ptr = middle;
        ptr[len] = '\0';
    }
}
#endif

// this ensures default output newline is atomic with the rest of the error string
#define AllocaPrintlineBuf(err, len) \
    auto* buf = (char*)alloca((len) + 2); \
    memcpy(buf, err, size_t(len)); \
    buf[len] = '\n'; \
    buf[(len)+1] = '\0';

EXTERNC void LogWriteToDefaultOutput(const char* tag, LogSeverity severity, const char* err, int len)
{
    using namespace std;
    #if __ANDROID__
        auto priority = severity == LogSeverityInfo ? ANDROID_LOG_INFO :
                        severity == LogSeverityWarn ? ANDROID_LOG_WARN :
                                                      ANDROID_LOG_ERROR;
        __android_log_write(priority, tag, err);
    #elif _WIN32
        static HANDLE winstd = GetStdHandle(STD_OUTPUT_HANDLE);
        static HANDLE winerr = GetStdHandle(STD_ERROR_HANDLE);
        static const WORD colormap[] = {
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // white - Info
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // bright yellow - Warning
            FOREGROUND_RED | FOREGROUND_INTENSITY, // bright red - Error
        };
        HANDLE winout = severity == LogSeverityError ? winstd : winerr;
        FILE*  cout   = severity == LogSeverityError ? stderr : stdout;

        AllocaPrintlineBuf(err, len);
        static mutex consoleSync;
        {
            lock_guard<mutex> guard{ consoleSync };
            SetConsoleTextAttribute(winout, colormap[severity]);
            fwrite(buf, size_t(len + 1), 1, cout); // fwrite to sync with unix-like shells
            SetConsoleTextAttribute(winout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
        }
        fflush(cout); // flush needed for proper sync with unix-like shells
    #elif __linux
        AllocaPrintlineBuf(err, len);
        FILE* cout = severity == LogSeverityError ? stderr : stdout;
        static const char clearColor[] = "\33[0m"; // Default: clear all formatting
        static const char* colors[] = {
                "\33[0m",  // Default: white
                "\33[93m", // Warning: bright yellow
                "\33[91m", // Error  : bright red
        };
        static mutex consoleSync;
        {
            lock_guard<mutex> guard{ consoleSync };
            fwrite(colors[severity], strlen(colors[severity]), 1, cout);
            fwrite(buf, size_t(len) + 1, 1, cout);
            fwrite(clearColor, sizeof(clearColor)-1, 1, cout);
        }
        fflush(cout); // flush needed for proper sync with different shells
    #else
        AllocaPrintlineBuf(err, len);
        FILE* cout = severity == LogSeverityError ? stderr : stdout;
        fwrite(buf, size_t(len) + 1, 1, cout);
        fflush(cout); // flush needed for proper sync with unix-like shells
    #endif
    (void)tag;
}

EXTERNC void LogEventToDefaultOutput(const char* tag, const char* eventName, const char* message, int len)
{
    #if __ANDROID__
        __android_log_print(ANDROID_LOG_INFO, tag, "EVT %s: %.*s", eventName, len, message);
    #else
        printf("EVT %s: %.*s\n", eventName, len, message);
    #endif
    (void)tag;
}

EXTERNC void LogFormatv(LogSeverity severity, const char* format, va_list ap)
{
    if (severity < Filter)
        return;

    char errBuf[4096];
    int len = SafeFormat(errBuf, sizeof(errBuf), format, ap);

    if (ErrorHandler)
    {
        char* ptr = errBuf;
        #ifdef __linux__
          ShortFilePathMessage(ptr, len);
        #endif
        ErrorHandler(severity, ptr, len);
    }
    else
    {
        LogWriteToDefaultOutput("ReCpp", severity, errBuf, len);
    }
}

#define WrappedLogFormatv(severity, format) \
    va_list ap; va_start(ap, format); \
    LogFormatv(severity, format, ap); \
    va_end(ap);
EXTERNC void _LogInfo(const char* format, ...) {
    WrappedLogFormatv(LogSeverityInfo, format);
}
EXTERNC void _LogWarning(const char* format, ...) {
    WrappedLogFormatv(LogSeverityWarn, format);
}
EXTERNC void _LogError(const char* format, ...) {
    WrappedLogFormatv(LogSeverityError, format);
}

EXTERNC void LogEvent(const char* eventName, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    if (EventHandler)
    {
        EventHandler(eventName, messageBuf, len);
    }
    else
    {
        LogEventToDefaultOutput("ReCpp", eventName, messageBuf, len);
    }
}

void _LogExcept(const char* exceptionWhat, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    // only MSVC requires stderr write; other platforms do it in assert
#if _MSC_VER
    fprintf(stderr, "%.*s: %s\n", len, messageBuf, exceptionWhat);
#else
    (void)len;
#endif

    if (ExceptHandler != nullptr)
    {
        ExceptHandler(messageBuf, exceptionWhat);
    }
}

EXTERNC const char* _FmtString(const char* format, ...)
{
    static thread_local char errBuf[4096];
    va_list ap; va_start(ap, format);
    SafeFormat(errBuf, sizeof(errBuf), format, ap);
    va_end(ap);
    return errBuf;
}

EXTERNC const char* _LogFilename(const char* longFilePath)
{
    if (longFilePath == nullptr) return "(null)";
    const char* eptr = longFilePath + strlen(longFilePath);
    for (int n = 1; longFilePath < eptr; --eptr)
        if (*eptr == '/' || *eptr == '\\')
            if (--n <= 0) return ++eptr;
    return eptr;
}

EXTERNC const char* _LogFuncname(const char* longFuncName)
{
    if (DisableFunctionNames) return "";
    if (longFuncName == nullptr) return "(null)";

    static thread_local char buf[64];
    static const int max = 36;

    // always skip the first ::
    const char* ptr = strchr(longFuncName, ':');
    if (ptr != nullptr) {
        if (*++ptr == ':') ++ptr;
    }
    else ptr = longFuncName;

    char ch;
    int len = 0;
    for (; len < max && (ch = *ptr) != '\0'; ++ptr) {
        if (ch == '<') {
            if (memcmp(ptr, "<<lambda", 8) == 0) { // MSVC std::invoke<<lambda_....>&>
                memcpy(&buf[len], "<lambda>", 8);
                len += 8;
                break;
            }
            if (memcmp(ptr, "<lambda", 7) == 0) {
                memcpy(&buf[len], "lambda", 6);
                len += 6;
                break;
            }
        }
        buf[len++] = ch;
    }
    if (buf[len-1] == ']')
        --len; // remove Objective-C method ending bracket
    buf[len] = '\0';
    return buf;
}

void Log(LogSeverity severity, rpp::strview message)
{
    if (severity < Filter)
        return;

    auto file = (severity == LogSeverityError) ? stderr : stdout;
    fwrite(message.str, (size_t)message.len, 1, file);
    fwrite("\n", 1, 1, file);

    if (ErrorHandler != nullptr)
    {
        ErrorHandler(severity, message.str, message.len);
    }
}
<commit_msg>Tiny improvement to function name filtering<commit_after>#include "debugging.h"
#include <cstdio>
#include <cstring>
#include <mutex>
#if __ANDROID__
  #include <android/log.h>
#endif
#if _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#endif

#ifdef QUIETLOG
static LogSeverity Filter = LogSeverityWarn;
#else
static LogSeverity Filter = LogSeverityInfo;
#endif
static LogErrorCallback ErrorHandler;
static LogEventCallback EventHandler;
static LogExceptCallback ExceptHandler;
static bool DisableFunctionNames = false;

EXTERNC void SetLogErrorHandler(LogErrorCallback errorHandler)
{
    ErrorHandler = errorHandler;
}
EXTERNC void SetLogEventHandler(LogEventCallback eventHandler)
{
    EventHandler = eventHandler;
}
EXTERNC void SetLogExceptHandler(LogExceptCallback exceptFunc)
{
    ExceptHandler = exceptFunc;
}
EXTERNC void LogDisableFunctionNames()
{
    DisableFunctionNames = true;
}
EXTERNC void SetLogSeverityFilter(LogSeverity filter)
{
    Filter = filter;
}
EXTERNC LogSeverity GetLogSeverityFilter()
{
    return Filter;
}

static int SafeFormat(char* errBuf, int N, const char* format, va_list ap)
{
    int len = vsnprintf(errBuf, size_t(N-1)/*spare room for \n*/, format, ap);
    if (len < 0 || len >= N) { // err: didn't fit
        len = N-2; // try to recover gracefully
        errBuf[len] = '\0';
    }
    return len;
}

#if __linux__
// split at $ and remove /long/path/ leaving just "filename.cpp:123 func() $ message"
static void ShortFilePathMessage(char*& ptr, int& len)
{
    if (char* middle = strchr(ptr, '$')) {
        for (; middle > ptr; --middle) {
            if (*middle == '/' || *middle == '\\') {
                ++middle;
                break;
            }
        }
        len = int((ptr + len) - middle);
        ptr = middle;
        ptr[len] = '\0';
    }
}
#endif

// this ensures default output newline is atomic with the rest of the error string
#define AllocaPrintlineBuf(err, len) \
    auto* buf = (char*)alloca((len) + 2); \
    memcpy(buf, err, size_t(len)); \
    buf[len] = '\n'; \
    buf[(len)+1] = '\0';

EXTERNC void LogWriteToDefaultOutput(const char* tag, LogSeverity severity, const char* err, int len)
{
    using namespace std;
    #if __ANDROID__
        auto priority = severity == LogSeverityInfo ? ANDROID_LOG_INFO :
                        severity == LogSeverityWarn ? ANDROID_LOG_WARN :
                                                      ANDROID_LOG_ERROR;
        __android_log_write(priority, tag, err);
    #elif _WIN32
        static HANDLE winstd = GetStdHandle(STD_OUTPUT_HANDLE);
        static HANDLE winerr = GetStdHandle(STD_ERROR_HANDLE);
        static const WORD colormap[] = {
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, // white - Info
            FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // bright yellow - Warning
            FOREGROUND_RED | FOREGROUND_INTENSITY, // bright red - Error
        };
        HANDLE winout = severity == LogSeverityError ? winstd : winerr;
        FILE*  cout   = severity == LogSeverityError ? stderr : stdout;

        AllocaPrintlineBuf(err, len);
        static mutex consoleSync;
        {
            lock_guard<mutex> guard{ consoleSync };
            SetConsoleTextAttribute(winout, colormap[severity]);
            fwrite(buf, size_t(len + 1), 1, cout); // fwrite to sync with unix-like shells
            SetConsoleTextAttribute(winout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
        }
        fflush(cout); // flush needed for proper sync with unix-like shells
    #elif __linux
        AllocaPrintlineBuf(err, len);
        FILE* cout = severity == LogSeverityError ? stderr : stdout;
        static const char clearColor[] = "\33[0m"; // Default: clear all formatting
        static const char* colors[] = {
                "\33[0m",  // Default: white
                "\33[93m", // Warning: bright yellow
                "\33[91m", // Error  : bright red
        };
        static mutex consoleSync;
        {
            lock_guard<mutex> guard{ consoleSync };
            fwrite(colors[severity], strlen(colors[severity]), 1, cout);
            fwrite(buf, size_t(len) + 1, 1, cout);
            fwrite(clearColor, sizeof(clearColor)-1, 1, cout);
        }
        fflush(cout); // flush needed for proper sync with different shells
    #else
        AllocaPrintlineBuf(err, len);
        FILE* cout = severity == LogSeverityError ? stderr : stdout;
        fwrite(buf, size_t(len) + 1, 1, cout);
        fflush(cout); // flush needed for proper sync with unix-like shells
    #endif
    (void)tag;
}

EXTERNC void LogEventToDefaultOutput(const char* tag, const char* eventName, const char* message, int len)
{
    #if __ANDROID__
        __android_log_print(ANDROID_LOG_INFO, tag, "EVT %s: %.*s", eventName, len, message);
    #else
        printf("EVT %s: %.*s\n", eventName, len, message);
    #endif
    (void)tag;
}

EXTERNC void LogFormatv(LogSeverity severity, const char* format, va_list ap)
{
    if (severity < Filter)
        return;

    char errBuf[4096];
    int len = SafeFormat(errBuf, sizeof(errBuf), format, ap);

    if (ErrorHandler)
    {
        char* ptr = errBuf;
        #ifdef __linux__
          ShortFilePathMessage(ptr, len);
        #endif
        ErrorHandler(severity, ptr, len);
    }
    else
    {
        LogWriteToDefaultOutput("ReCpp", severity, errBuf, len);
    }
}

#define WrappedLogFormatv(severity, format) \
    va_list ap; va_start(ap, format); \
    LogFormatv(severity, format, ap); \
    va_end(ap);
EXTERNC void _LogInfo(const char* format, ...) {
    WrappedLogFormatv(LogSeverityInfo, format);
}
EXTERNC void _LogWarning(const char* format, ...) {
    WrappedLogFormatv(LogSeverityWarn, format);
}
EXTERNC void _LogError(const char* format, ...) {
    WrappedLogFormatv(LogSeverityError, format);
}

EXTERNC void LogEvent(const char* eventName, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    if (EventHandler)
    {
        EventHandler(eventName, messageBuf, len);
    }
    else
    {
        LogEventToDefaultOutput("ReCpp", eventName, messageBuf, len);
    }
}

void _LogExcept(const char* exceptionWhat, const char* format, ...)
{
#if __clang__
#if __has_feature(address_sanitizer)
    return; // ASAN reports a false positive with vsnprintf
#endif
#endif
    va_list ap; va_start(ap, format);
    char messageBuf[4096];
    int len = SafeFormat(messageBuf, sizeof(messageBuf), format, ap);
    va_end(ap);

    // only MSVC requires stderr write; other platforms do it in assert
#if _MSC_VER
    fprintf(stderr, "%.*s: %s\n", len, messageBuf, exceptionWhat);
#else
    (void)len;
#endif

    if (ExceptHandler != nullptr)
    {
        ExceptHandler(messageBuf, exceptionWhat);
    }
}

EXTERNC const char* _FmtString(const char* format, ...)
{
    static thread_local char errBuf[4096];
    va_list ap; va_start(ap, format);
    SafeFormat(errBuf, sizeof(errBuf), format, ap);
    va_end(ap);
    return errBuf;
}

EXTERNC const char* _LogFilename(const char* longFilePath)
{
    if (longFilePath == nullptr) return "(null)";
    const char* eptr = longFilePath + strlen(longFilePath);
    for (int n = 1; longFilePath < eptr; --eptr)
        if (*eptr == '/' || *eptr == '\\')
            if (--n <= 0) return ++eptr;
    return eptr;
}

static const int funcname_max = 48;

struct funcname_builder
{
    char* buffer;
    const char* ptr;
    int len = 0;

    explicit funcname_builder(char* buffer, const char* original)
        : buffer{buffer}, ptr{original-1} {}

    char read_next() { return len < funcname_max ? *++ptr : '\0'; }

    template<int N, int M> bool replace(const char (&what)[N], const char (&with)[M])
    {
        if (memcmp(ptr, what, N - 1) == 0)
        {
            memcpy(&buffer[len], with, M - 1);
            len += M - 1;
            return true;
        }
        return false;
    }
    template<int N> bool skip(const char (&what)[N])
    {
        if (memcmp(ptr, what, N - 1) == 0) {
            ptr += N - 2; // - 2 because next() will bump the pointer
            return true;
        }
        return false;
    }

    void append(char ch) { buffer[len++] = ch; }
};

EXTERNC const char* _LogFuncname(const char* longFuncName)
{
    if (DisableFunctionNames) return "";
    if (longFuncName == nullptr) return "(null)";

    // always skip the first ::
    const char* ptr = strchr(longFuncName, ':');
    if (ptr != nullptr) {
        if (*++ptr == ':') ++ptr;
    }
    else ptr = longFuncName;

    static thread_local char funcname_buf[64];

    funcname_builder fb { funcname_buf, ptr };
    while (char ch = fb.read_next())
    {
        if (ch == '<') {
            // replace invoke<<lambda_....>&> with just invoke<lambda>
            if (fb.replace("<<lambda", "<lambda>")) break; // no idea how long lambda, so stop here
            if (fb.replace("<lambda", "lambda"))    break;
        }

        // clean all std:: symbols
        if (ch == 's' && fb.skip("std::")) continue;

    #if !_MSC_VER // also skip __1:: to clean the symbols on clang
        if (ch == '_' && fb.skip("__1::")) continue;
    #else
        if (ch == ' ' && fb.skip(" __cdecl")) continue;
    #endif

        fb.append(ch);
    }

    if (fb.buffer[fb.len-1] == ']')
        --fb.len; // remove Objective-C method ending bracket
    fb.append('\0');
    return fb.buffer;
}

void Log(LogSeverity severity, rpp::strview message)
{
    if (severity < Filter)
        return;

    auto file = (severity == LogSeverityError) ? stderr : stdout;
    fwrite(message.str, (size_t)message.len, 1, file);
    fwrite("\n", 1, 1, file);

    if (ErrorHandler != nullptr)
    {
        ErrorHandler(severity, message.str, message.len);
    }
}
<|endoftext|>