<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include <stdio.h>
#include <ctype.h>
#include <f32file.h>
#include <utf.h>

#include "base/util/utils.h"
#include "base/util/stringUtils.h"
#include "base/util/StringBuffer.h"
#include "base/fscapi.h"
#include "base/SymbianLog.h"
#include "spdm/spdmutils.h"
#include "spdm/constants.h"
#include "spdm/ManagementNode.h"
#include "spdm/DeviceManagementNode.h"
#include "base/globalsdef.h"

USE_NAMESPACE

#define CONFIG_DIR      ".config"
#define SYNC4J_DIR      ".sync4j"

StringBuffer DeviceManagementNode::configPath;
StringBuffer DeviceManagementNode::configFile = "config.ini";

StringBuffer DeviceManagementNode::server("DefaultServer");
StringBuffer DeviceManagementNode::profileName("DefaultProfile");
TSmlCreatorId DeviceManagementNode::uid = -1;
StringBuffer DeviceManagementNode::cardURI("card");
StringBuffer DeviceManagementNode::calURI("cal");
StringBuffer DeviceManagementNode::imapServer("");
StringBuffer DeviceManagementNode::smtpServer("");
unsigned int DeviceManagementNode::imapPort = 143;
unsigned int DeviceManagementNode::smtpPort = 25;

DeviceManagementNode::DeviceManagementNode(const char* parent,
                                           const char *leafName)
                            : ManagementNode(parent, leafName),
                              lines(new ArrayList),
                              modified(false)
{
    initCurrentDir();
    update(true);
}

DeviceManagementNode::DeviceManagementNode(const char *node)
    : ManagementNode(node),
      lines(new ArrayList),
      modified(false)
{
    initCurrentDir();
    update(true);
}

DeviceManagementNode::DeviceManagementNode(const DeviceManagementNode &other)
    : ManagementNode(other) {

    lines = other.lines->clone();
    currentDir = other.currentDir;
    modified = other.modified;
}

DeviceManagementNode::~DeviceManagementNode() {
    if (modified) {
        update(false);
    }
    delete lines;
}

void DeviceManagementNode::update(bool read) {
    if (!read && !modified) {
        // no work to be done
        return;
    }

    StringBuffer fileName(currentDir);
    concatDirs(fileName, configFile.c_str());
    const char* fname = fileName.c_str();
    FILE* file = fopen(fname, "r");

    if (file) {
        // Open a temp file in writing mode if we must update the config
        if (!read) {
            fclose(file);
            fileName.append(".tmp");
            file = fopen(fileName, "w");
        }

        if (read) {
            // Note: don't create local buffers too big, the Symbian stack size is limited!
            char buffer[128];

            lines->clear();
            while (fgets(buffer, sizeof(buffer), file)) {
                char *eol = strchr(buffer, '\r');
                if (!eol) {
                    eol = strchr(buffer, '\n');
                }
                if (eol) {
                    *eol = 0;
                }
                line newline(buffer);
                lines->add(newline);
            }
            fclose(file);
        }
        else {
            int i = 0;

            while (true) {
                line *curr = (line *)lines->get(i);
                if (!curr) {
                    break;
                }
                fprintf(file, "%s\n", curr->getLine());

                i++;
            }
            fflush(file);
            if (!ferror(file)) {
                StringBuffer tmpConfig = configFile;
                tmpConfig += ".tmp";

                fclose(file);   // Both files must be closed for the rename.
                renameFileInCwd( tmpConfig.c_str(), configFile.c_str());
            }
            else {
                fclose(file);
            }
        }
    }
}

int DeviceManagementNode::strnicmp( const char *a, const char *b, int len ) {
    while (--len >= 0) {
        if (toupper(*a) != toupper(*b)) {
            return 1;
        }
        a++;
        b++;
    }
    return 0;
}

/*
 * Returns the value of the given property
 * the value is returned as a new char array and must be fred by the user
 *
 * @param property - the property name
 */
char* DeviceManagementNode::readPropertyValue(const char* property) {
    int i = 0;

    while (true) {
        line *curr = (line *)lines->get(i);
        if (!curr) {
            break;
        }

        const char *value = curr->getLine();
        while (*value && isspace(*value)) {
            value++;
        }
        if (!strnicmp(value, property, strlen(property))) {
            value = strchr(value, '=');
            if (value) {
                value++;
                while (*value && isspace(*value)) {
                    value++;
                }
                char *res = stringdup(value);   // FOUND :)

                // remove trailing white space: usually it is
                // added accidentally by users
                char *tmp = res + strlen(res) - 1;
                while (tmp > res) {
                    if (!isspace(*tmp)) {
                        break;
                    }
                    tmp--;
                }
                tmp[1] = 0;

                return res;
            }
        }
        i++;
    }
    // Not found, return an empty string
    return stringdup("");
}

#include "base/util/symbianUtils.h"

int DeviceManagementNode::getChildrenMaxCount() {
    int count = 0;

    RFs fileSession;
    RFile file;
    int cleanupStackSize = 0;

    StringBuffer fileSpecSb(currentDir);
    concatDirs(fileSpecSb, "*.*");

    // TODO use utility function for string conversion
    TBuf8<DIM_MANAGEMENT_PATH> buf8((const unsigned char*)fileSpecSb.c_str());
    HBufC* fileSpec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(buf8);
    ++cleanupStackSize;
    CleanupStack::PushL(fileSpec);

    //
    // Connect to the file server
    //
    fileSession.Connect();
    ++cleanupStackSize;
    CleanupClosePushL(fileSession);

    StringBuffer buf;

    //
    // Get the directories list, sorted by name
    // (Leave if an error occurs)
    //
    CDir* dirList;
    TRAPD(err, fileSession.GetDir(*fileSpec, KEntryAttDir|KEntryAttMatchExclusive,
                                  ESortByName, dirList));
    if (err != KErrNone || dirList == NULL) {
        goto finally;
    }
    ++cleanupStackSize;
    CleanupStack::PushL(dirList);

    count = dirList->Count();

finally:
    //
    // Close the connection with the file server
    // and destroy dirList
    //
    fileSession.Close();
    CleanupStack::PopAndDestroy(cleanupStackSize);
    return count;
}

char **DeviceManagementNode::getChildrenNames() {
    char **childrenName = 0;
    int cleanupStackSize = 0;
    RFs fileSession;
    RFile file;

    StringBuffer fileSpecSb(currentDir);
    concatDirs(fileSpecSb, "*.*");

    // TODO use utility function for string conversion
    TBuf8<DIM_MANAGEMENT_PATH> buf8((const unsigned char*)fileSpecSb.c_str());
    HBufC* fileSpec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(buf8);
    ++cleanupStackSize;
    CleanupStack::PushL(fileSpec);

    //
    // Connect to the file server
    //
    fileSession.Connect();
    ++cleanupStackSize;
    CleanupClosePushL(fileSession);

    //
    // Get the directories list, sorted by name
    // (Leave if an error occurs)
    //
    CDir* dirList;
    TRAPD(err, fileSession.GetDir(*fileSpec, KEntryAttDir|KEntryAttMatchExclusive,
                                  ESortByName, dirList));
    if (err != KErrNone || dirList == NULL) {
        goto finally;
    }
    ++cleanupStackSize;
    CleanupStack::PushL(dirList);

    //
    // Process each entry
    //
    childrenName = new char*[dirList->Count()];
    TInt i;
    for (i=0;i<dirList->Count();i++)
    {
        TBuf<DIM_MANAGEMENT_PATH> fileName = (*dirList)[i].iName;

#if 0
        childrenName[i] = bufToNewChar(buf8);
#else
        // TODO use string utils
        HBufC8* buf8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L(fileName);
        childrenName[i] = stringdup((const char*)buf8->Ptr(), buf8->Length());
        *(childrenName[i] + buf8->Length()) = (char)0;
        delete buf8;
#endif
    }
    fileSession.Close();

finally:
    //
    // Close the connection with the file server
    // and destroy dirList
    //
    CleanupStack::PopAndDestroy(cleanupStackSize);
    return childrenName;
}

/*
 * Sets a property value.
 *
 * @param property - the property name
 * @param value - the property value (zero terminated string)
 */
void DeviceManagementNode::setPropertyValue(const char* property, const char* newvalue) {
    int i = 0;

    while (true) {
        line *curr = (line *)lines->get(i);
        if (!curr) {
            break;
        }

        const char *start = curr->getLine();
        const char *value = start;

        while (*value && isspace(*value)) {
            value++;
        }
        if (!strnicmp(value, property, strlen(property))) {
            value = strchr(value, '=');
            if (value) {
                value++;
                while (*value && isspace(*value)) {
                    value++;
                }
                if (strcmp(value, newvalue)) {
                    // preserve indention and property name from original config
                    char *newstr = new char[(value - start) + strlen(newvalue) + 1];
                    strncpy(newstr, start, value - start);
                    strcpy(newstr + (value - start), newvalue);
                    curr->setLine(newstr);
                    delete [] newstr;
                    modified = true;
                }
                goto finally;
            }
        }
        i++;
    }

    {
        // This is a new property
        char *newstr = new char[strlen(property) + 3 + strlen(newvalue) + 1];
        sprintf(newstr, "%s = %s", property, newvalue);
        line newline(newstr);
        lines->add(newline);
        delete [] newstr;
        modified = true;
    }

finally:
    i = 0;
}

void DeviceManagementNode::setServerURI(const StringBuffer& server) {
    DeviceManagementNode::server = server;
}

const StringBuffer& DeviceManagementNode::getServerURI() {
    return server;
}

void DeviceManagementNode::setProfileName(const StringBuffer& name) {
    DeviceManagementNode::profileName = name;
}

const StringBuffer& DeviceManagementNode::getProfileName() {
    return profileName;
}

void DeviceManagementNode::setUID(TSmlCreatorId uid) {
    DeviceManagementNode::uid = uid;
}

TSmlCreatorId DeviceManagementNode::getUID() {
    return uid;
}

void DeviceManagementNode::setCardURI(const StringBuffer& cardURI) {
    DeviceManagementNode::cardURI = cardURI;
}

const StringBuffer& DeviceManagementNode::getCardURI() {
    return cardURI;
}

void DeviceManagementNode::setCalURI(const StringBuffer& calURI) {
    DeviceManagementNode::calURI = calURI;
}

const StringBuffer& DeviceManagementNode::getCalURI() {
    return calURI;
}

void DeviceManagementNode::setImapServer(const StringBuffer& imapServer) {
    DeviceManagementNode::imapServer = imapServer;
}

const StringBuffer& DeviceManagementNode::getImapServer() {
    return imapServer;
}

void DeviceManagementNode::setImapPort(unsigned int imapPort) {
    DeviceManagementNode::imapPort = imapPort;
}

unsigned int DeviceManagementNode::getImapPort() {
    return imapPort;
}

void DeviceManagementNode::setSmtpPort(unsigned int smtpPort) {
    DeviceManagementNode::smtpPort = smtpPort;
}

unsigned int DeviceManagementNode::getSmtpPort() {
    return smtpPort;
}

void DeviceManagementNode::setSmtpServer(const StringBuffer& smtpServer) {
    DeviceManagementNode::smtpServer = smtpServer;
}

const StringBuffer& DeviceManagementNode::getSmtpServer() {
    return smtpServer;
}

ArrayElement* DeviceManagementNode::clone()
{
    DeviceManagementNode* ret = new DeviceManagementNode(context, name);

    int n = children.size();

    for (int i = 0; i<n; ++i) {
        ret->addChild(*((ManagementNode*)children[i]));
    }

    return ret;
}

void DeviceManagementNode::concatDirs(StringBuffer& src1, const char* src2) {

    // If the src path terminates with \\ then there is no
    // need to add it again (this would be an illegal symbian path)
    // Unfortunately we cannot use StringBuffer directly for this check
    // there is something weird with \\ in StringBuffer (at least on symbian)
    const char* chars = src1.c_str();
    if (chars[strlen(chars)-1] != '\\') {
        src1.append("\\");
    }
    src1.append(src2);
}

void DeviceManagementNode::initCurrentDir() {

    if (configPath.empty()) {
        currentDir = ".\\";
    } else {
        currentDir = configPath;
    }
    if (context) {
        StringBuffer translatedContext = contextToPath(context);
        const char* tc = translatedContext.c_str();
        concatDirs(currentDir, tc);
    }
    if (name) {
        concatDirs(currentDir, name);
    }
}

StringBuffer DeviceManagementNode::contextToPath(const char* cont) {
    // Contextes are defined as: (string/)* and on Symbian
    // we map them to file. But Symbian uses backslashes as
    // directory separator.
    StringBuffer sb(cont);
    sb.replaceAll("/", "\\", 0);
    return sb;
}

int DeviceManagementNode::renameFileInCwd(const char* src, const char* dst) {

    RFs fileSession;
    RFile file;

    StringBuffer srcSb(currentDir);
    concatDirs(srcSb, src);
    StringBuffer dstSb(currentDir);
    concatDirs(dstSb, dst);

    RBuf srcDes, dstDes;
    srcDes.Assign(stringBufferToNewBuf(srcSb));
    dstDes.Assign(stringBufferToNewBuf(dstSb));

    // Connect to the file server
    fileSession.Connect();
    CleanupClosePushL(fileSession);

    // Replace 'config.ini' file with 'config.ini.tmp'
    TInt err = fileSession.Replace(srcDes, dstDes);

    CleanupStack::PopAndDestroy(&fileSession);

    if (err == KErrNone) {
        return 0;
    }
    else {
        LOG.error("Error (code %d) replacing file '%s'", err, dstSb.c_str());
        if (err == KErrAccessDenied) {
            LOG.error("Access denied");
        }
        return -1;
    }
}

<commit_msg>Just added a log message<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include <stdio.h>
#include <ctype.h>
#include <f32file.h>
#include <utf.h>

#include "base/util/utils.h"
#include "base/util/stringUtils.h"
#include "base/util/StringBuffer.h"
#include "base/fscapi.h"
#include "base/SymbianLog.h"
#include "spdm/spdmutils.h"
#include "spdm/constants.h"
#include "spdm/ManagementNode.h"
#include "spdm/DeviceManagementNode.h"
#include "base/globalsdef.h"

USE_NAMESPACE

#define CONFIG_DIR      ".config"
#define SYNC4J_DIR      ".sync4j"

StringBuffer DeviceManagementNode::configPath;
StringBuffer DeviceManagementNode::configFile = "config.ini";

StringBuffer DeviceManagementNode::server("DefaultServer");
StringBuffer DeviceManagementNode::profileName("DefaultProfile");
TSmlCreatorId DeviceManagementNode::uid = -1;
StringBuffer DeviceManagementNode::cardURI("card");
StringBuffer DeviceManagementNode::calURI("cal");
StringBuffer DeviceManagementNode::imapServer("");
StringBuffer DeviceManagementNode::smtpServer("");
unsigned int DeviceManagementNode::imapPort = 143;
unsigned int DeviceManagementNode::smtpPort = 25;

DeviceManagementNode::DeviceManagementNode(const char* parent,
                                           const char *leafName)
                            : ManagementNode(parent, leafName),
                              lines(new ArrayList),
                              modified(false)
{
    initCurrentDir();
    update(true);
}

DeviceManagementNode::DeviceManagementNode(const char *node)
    : ManagementNode(node),
      lines(new ArrayList),
      modified(false)
{
    initCurrentDir();
    update(true);
}

DeviceManagementNode::DeviceManagementNode(const DeviceManagementNode &other)
    : ManagementNode(other) {

    lines = other.lines->clone();
    currentDir = other.currentDir;
    modified = other.modified;
}

DeviceManagementNode::~DeviceManagementNode() {
    if (modified) {
        update(false);
    }
    delete lines;
}

void DeviceManagementNode::update(bool read) {
    if (!read && !modified) {
        // no work to be done
        return;
    }

    StringBuffer fileName(currentDir);
    concatDirs(fileName, configFile.c_str());
    const char* fname = fileName.c_str();
    FILE* file = fopen(fname, "r");

    if (file) {
        // Open a temp file in writing mode if we must update the config
        if (!read) {
            fclose(file);
            fileName.append(".tmp");
            file = fopen(fileName, "w");
        }

        if (read) {
            // Note: don't create local buffers too big, the Symbian stack size is limited!
            char buffer[128];

            lines->clear();
            while (fgets(buffer, sizeof(buffer), file)) {
                char *eol = strchr(buffer, '\r');
                if (!eol) {
                    eol = strchr(buffer, '\n');
                }
                if (eol) {
                    *eol = 0;
                }
                line newline(buffer);
                lines->add(newline);
            }
            fclose(file);
        }
        else {
            int i = 0;

            while (true) {
                line *curr = (line *)lines->get(i);
                if (!curr) {
                    break;
                }
                fprintf(file, "%s\n", curr->getLine());

                i++;
            }
            fflush(file);
            if (!ferror(file)) {
                StringBuffer tmpConfig = configFile;
                tmpConfig += ".tmp";

                fclose(file);   // Both files must be closed for the rename.
                renameFileInCwd( tmpConfig.c_str(), configFile.c_str());
            }
            else {
                fclose(file);
            }
        }
    }
}

int DeviceManagementNode::strnicmp( const char *a, const char *b, int len ) {
    while (--len >= 0) {
        if (toupper(*a) != toupper(*b)) {
            return 1;
        }
        a++;
        b++;
    }
    return 0;
}

/*
 * Returns the value of the given property
 * the value is returned as a new char array and must be fred by the user
 *
 * @param property - the property name
 */
char* DeviceManagementNode::readPropertyValue(const char* property) {
    int i = 0;

    while (true) {
        line *curr = (line *)lines->get(i);
        if (!curr) {
            break;
        }

        const char *value = curr->getLine();
        while (*value && isspace(*value)) {
            value++;
        }
        if (!strnicmp(value, property, strlen(property))) {
            value = strchr(value, '=');
            if (value) {
                value++;
                while (*value && isspace(*value)) {
                    value++;
                }
                char *res = stringdup(value);   // FOUND :)

                // remove trailing white space: usually it is
                // added accidentally by users
                char *tmp = res + strlen(res) - 1;
                while (tmp > res) {
                    if (!isspace(*tmp)) {
                        break;
                    }
                    tmp--;
                }
                tmp[1] = 0;

                return res;
            }
        }
        i++;
    }
    // Not found, return an empty string
    return stringdup("");
}

#include "base/util/symbianUtils.h"

int DeviceManagementNode::getChildrenMaxCount() {
    int count = 0;

    RFs fileSession;
    RFile file;
    int cleanupStackSize = 0;

    StringBuffer fileSpecSb(currentDir);
    concatDirs(fileSpecSb, "*.*");

    // TODO use utility function for string conversion
    TBuf8<DIM_MANAGEMENT_PATH> buf8((const unsigned char*)fileSpecSb.c_str());
    HBufC* fileSpec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(buf8);
    ++cleanupStackSize;
    CleanupStack::PushL(fileSpec);

    //
    // Connect to the file server
    //
    fileSession.Connect();
    ++cleanupStackSize;
    CleanupClosePushL(fileSession);

    StringBuffer buf;

    //
    // Get the directories list, sorted by name
    // (Leave if an error occurs)
    //
    CDir* dirList;
    TRAPD(err, fileSession.GetDir(*fileSpec, KEntryAttDir|KEntryAttMatchExclusive,
                                  ESortByName, dirList));
    if (err != KErrNone || dirList == NULL) {
        goto finally;
    }
    ++cleanupStackSize;
    CleanupStack::PushL(dirList);

    count = dirList->Count();

finally:
    //
    // Close the connection with the file server
    // and destroy dirList
    //
    fileSession.Close();
    CleanupStack::PopAndDestroy(cleanupStackSize);
    return count;
}

char **DeviceManagementNode::getChildrenNames() {
    char **childrenName = 0;
    int cleanupStackSize = 0;
    RFs fileSession;
    RFile file;

    StringBuffer fileSpecSb(currentDir);
    concatDirs(fileSpecSb, "*.*");

    // TODO use utility function for string conversion
    TBuf8<DIM_MANAGEMENT_PATH> buf8((const unsigned char*)fileSpecSb.c_str());
    HBufC* fileSpec = CnvUtfConverter::ConvertToUnicodeFromUtf8L(buf8);
    ++cleanupStackSize;
    CleanupStack::PushL(fileSpec);

    //
    // Connect to the file server
    //
    fileSession.Connect();
    ++cleanupStackSize;
    CleanupClosePushL(fileSession);

    //
    // Get the directories list, sorted by name
    // (Leave if an error occurs)
    //
    CDir* dirList;
    TRAPD(err, fileSession.GetDir(*fileSpec, KEntryAttDir|KEntryAttMatchExclusive,
                                  ESortByName, dirList));
    if (err != KErrNone || dirList == NULL) {
        goto finally;
    }
    ++cleanupStackSize;
    CleanupStack::PushL(dirList);

    //
    // Process each entry
    //
    childrenName = new char*[dirList->Count()];
    TInt i;
    for (i=0;i<dirList->Count();i++)
    {
        TBuf<DIM_MANAGEMENT_PATH> fileName = (*dirList)[i].iName;

#if 0
        childrenName[i] = bufToNewChar(buf8);
#else
        // TODO use string utils
        HBufC8* buf8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L(fileName);
        childrenName[i] = stringdup((const char*)buf8->Ptr(), buf8->Length());
        *(childrenName[i] + buf8->Length()) = (char)0;
        delete buf8;
#endif
    }
    fileSession.Close();

finally:
    //
    // Close the connection with the file server
    // and destroy dirList
    //
    CleanupStack::PopAndDestroy(cleanupStackSize);
    return childrenName;
}

/*
 * Sets a property value.
 *
 * @param property - the property name
 * @param value - the property value (zero terminated string)
 */
void DeviceManagementNode::setPropertyValue(const char* property, const char* newvalue) {
    int i = 0;

    while (true) {
        line *curr = (line *)lines->get(i);
        if (!curr) {
            break;
        }

        const char *start = curr->getLine();
        const char *value = start;

        while (*value && isspace(*value)) {
            value++;
        }
        if (!strnicmp(value, property, strlen(property))) {
            value = strchr(value, '=');
            if (value) {
                value++;
                while (*value && isspace(*value)) {
                    value++;
                }
                if (strcmp(value, newvalue)) {
                    // preserve indention and property name from original config
                    char *newstr = new char[(value - start) + strlen(newvalue) + 1];
                    strncpy(newstr, start, value - start);
                    strcpy(newstr + (value - start), newvalue);
                    curr->setLine(newstr);
                    delete [] newstr;
                    modified = true;
                }
                goto finally;
            }
        }
        i++;
    }

    {
        // This is a new property
        char *newstr = new char[strlen(property) + 3 + strlen(newvalue) + 1];
        sprintf(newstr, "%s = %s", property, newvalue);
        line newline(newstr);
        lines->add(newline);
        delete [] newstr;
        modified = true;
    }

finally:
    i = 0;
}

void DeviceManagementNode::setServerURI(const StringBuffer& server) {
    DeviceManagementNode::server = server;
}

const StringBuffer& DeviceManagementNode::getServerURI() {
    return server;
}

void DeviceManagementNode::setProfileName(const StringBuffer& name) {
    DeviceManagementNode::profileName = name;
}

const StringBuffer& DeviceManagementNode::getProfileName() {
    return profileName;
}

void DeviceManagementNode::setUID(TSmlCreatorId uid) {
    DeviceManagementNode::uid = uid;
}

TSmlCreatorId DeviceManagementNode::getUID() {
    return uid;
}

void DeviceManagementNode::setCardURI(const StringBuffer& cardURI) {
    DeviceManagementNode::cardURI = cardURI;
}

const StringBuffer& DeviceManagementNode::getCardURI() {
    return cardURI;
}

void DeviceManagementNode::setCalURI(const StringBuffer& calURI) {
    DeviceManagementNode::calURI = calURI;
}

const StringBuffer& DeviceManagementNode::getCalURI() {
    return calURI;
}

void DeviceManagementNode::setImapServer(const StringBuffer& imapServer) {
    DeviceManagementNode::imapServer = imapServer;
}

const StringBuffer& DeviceManagementNode::getImapServer() {
    return imapServer;
}

void DeviceManagementNode::setImapPort(unsigned int imapPort) {
    DeviceManagementNode::imapPort = imapPort;
}

unsigned int DeviceManagementNode::getImapPort() {
    return imapPort;
}

void DeviceManagementNode::setSmtpPort(unsigned int smtpPort) {
    DeviceManagementNode::smtpPort = smtpPort;
}

unsigned int DeviceManagementNode::getSmtpPort() {
    return smtpPort;
}

void DeviceManagementNode::setSmtpServer(const StringBuffer& smtpServer) {
    DeviceManagementNode::smtpServer = smtpServer;
}

const StringBuffer& DeviceManagementNode::getSmtpServer() {
    return smtpServer;
}

ArrayElement* DeviceManagementNode::clone()
{
    DeviceManagementNode* ret = new DeviceManagementNode(context, name);

    int n = children.size();

    for (int i = 0; i<n; ++i) {
        ret->addChild(*((ManagementNode*)children[i]));
    }

    return ret;
}

void DeviceManagementNode::concatDirs(StringBuffer& src1, const char* src2) {

    // If the src path terminates with \\ then there is no
    // need to add it again (this would be an illegal symbian path)
    // Unfortunately we cannot use StringBuffer directly for this check
    // there is something weird with \\ in StringBuffer (at least on symbian)
    const char* chars = src1.c_str();
    if (chars[strlen(chars)-1] != '\\') {
        src1.append("\\");
    }
    src1.append(src2);
}

void DeviceManagementNode::initCurrentDir() {

    if (configPath.empty()) {
        currentDir = ".\\";
    } else {
        currentDir = configPath;
    }
    if (context) {
        StringBuffer translatedContext = contextToPath(context);
        const char* tc = translatedContext.c_str();
        concatDirs(currentDir, tc);
    }
    if (name) {
        concatDirs(currentDir, name);
    }
}

StringBuffer DeviceManagementNode::contextToPath(const char* cont) {
    // Contextes are defined as: (string/)* and on Symbian
    // we map them to file. But Symbian uses backslashes as
    // directory separator.
    StringBuffer sb(cont);
    sb.replaceAll("/", "\\", 0);
    return sb;
}

int DeviceManagementNode::renameFileInCwd(const char* src, const char* dst) {

    RFs fileSession;
    RFile file;

    StringBuffer srcSb(currentDir);
    concatDirs(srcSb, src);
    StringBuffer dstSb(currentDir);
    concatDirs(dstSb, dst);

    RBuf srcDes, dstDes;
    srcDes.Assign(stringBufferToNewBuf(srcSb));
    dstDes.Assign(stringBufferToNewBuf(dstSb));

    // Connect to the file server
    fileSession.Connect();
    CleanupClosePushL(fileSession);

    // Replace 'config.ini' file with 'config.ini.tmp'
    TInt err = fileSession.Replace(srcDes, dstDes);

    CleanupStack::PopAndDestroy(&fileSession);

    if (err == KErrNone) {
        return 0;
    }
    else {
        LOG.error("Error (code %d) replacing file '%s'", err, dstSb.c_str());
        if (err == KErrAccessDenied) {
            LOG.error("Access denied");
        }
        else if (err == KErrPathNotFound) {
            LOG.error("Unable to find the specified folder");
        }
        return -1;
    }
}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __itkVoronoiDiagram2D_hxx
#define __itkVoronoiDiagram2D_hxx
#include "itkVoronoiDiagram2D.h"

#include <algorithm>
#include "vnl/vnl_sample.h"

namespace itk
{

template< typename TCoordRepType >
VoronoiDiagram2D< TCoordRepType >
::VoronoiDiagram2D()
{
  m_NumberOfSeeds = 0;
}

template< typename TCoordRepType >
VoronoiDiagram2D< TCoordRepType >
::~VoronoiDiagram2D()
{
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "Number Of Seeds: "
     << m_NumberOfSeeds << std::endl;
}

/* Set the seed points, specify the number of seeds as "num". */
template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetSeeds(int num,  SeedsIterator begin)
{
  m_Seeds.clear();
  SeedsIterator ii(begin);
  for ( int i = 0; i < num; ++i )
    {
    m_Seeds.push_back(*ii++);
    }
  m_NumberOfSeeds = num;
}

/* Set the rectangle that encloses the Voronoi Diagram. */
template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetBoundary(PointType vorsize)
{
  m_VoronoiBoundary[0] = vorsize[0];
  m_VoronoiBoundary[1] = vorsize[1];
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetOrigin(PointType vorsize)
{
  m_VoronoiBoundaryOrigin[0] = vorsize[0];
  m_VoronoiBoundaryOrigin[0] = vorsize[1];
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::GetPoint(int pId, PointType *answer)
{
  *answer = this->m_PointsContainer->ElementAt(pId);
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::GetCellId(CellIdentifier cellId, CellAutoPointer & cellPtr)
{
  cellPtr.TakeNoOwnership(m_VoronoiRegions[cellId]);
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::EdgeInfo
VoronoiDiagram2D< TCoordRepType >
::GetSeedsIDAroundEdge(VoronoiEdge *task)
{
  EdgeInfo answer;

  answer[0] = m_LineList[task->m_LineID][0];
  answer[1] = m_LineList[task->m_LineID][1];
  return ( answer );
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VoronoiEdgeIterator
VoronoiDiagram2D< TCoordRepType >
::EdgeBegin()
{
  return m_EdgeList.begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VoronoiEdgeIterator
VoronoiDiagram2D< TCoordRepType >
::EdgeEnd()
{
  return m_EdgeList.end();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::NeighborIdIterator
VoronoiDiagram2D< TCoordRepType >
::NeighborIdsBegin(int seeds)
{
  return m_CellNeighborsID[seeds].begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::NeighborIdIterator
VoronoiDiagram2D< TCoordRepType >
::NeighborIdsEnd(int seeds)
{
  return m_CellNeighborsID[seeds].end();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VertexIterator
VoronoiDiagram2D< TCoordRepType >
::VertexBegin()
{
  return this->m_PointsContainer->Begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VertexIterator
VoronoiDiagram2D< TCoordRepType >
::VertexEnd()
{
  return this->m_PointsContainer->End();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::PointType
VoronoiDiagram2D< TCoordRepType >
::GetSeed(int SeedID)
{
  PointType answer;

  answer[0] = m_Seeds[SeedID][0];
  answer[1] = m_Seeds[SeedID][1];
  return answer;
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::Reset()
{
  m_VoronoiRegions.clear();
  m_VoronoiRegions.resize(m_NumberOfSeeds);
  m_CellNeighborsID.resize(m_NumberOfSeeds);

  for ( unsigned int i = 0; i < m_NumberOfSeeds; i++ )
    {
    m_VoronoiRegions[i] = new PolygonCellType;
    m_CellNeighborsID[i].clear();
    }
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::InsertCells()
{
  genericCellPointer cellPtr;

  for ( unsigned int i = 0; i < m_NumberOfSeeds; i++ )
    {
    cellPtr.TakeOwnership(m_VoronoiRegions[i]);
    this->SetCell(i, cellPtr);
    }
}

} // end namespace itk

#endif
<commit_msg>BUG: Fix invalid assignment of second VoronoiBoundaryOrigin.<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/
#ifndef __itkVoronoiDiagram2D_hxx
#define __itkVoronoiDiagram2D_hxx
#include "itkVoronoiDiagram2D.h"

#include <algorithm>
#include "vnl/vnl_sample.h"

namespace itk
{

template< typename TCoordRepType >
VoronoiDiagram2D< TCoordRepType >
::VoronoiDiagram2D()
{
  m_NumberOfSeeds = 0;
}

template< typename TCoordRepType >
VoronoiDiagram2D< TCoordRepType >
::~VoronoiDiagram2D()
{
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);
  os << indent << "Number Of Seeds: "
     << m_NumberOfSeeds << std::endl;
}

/* Set the seed points, specify the number of seeds as "num". */
template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetSeeds(int num,  SeedsIterator begin)
{
  m_Seeds.clear();
  SeedsIterator ii(begin);
  for ( int i = 0; i < num; ++i )
    {
    m_Seeds.push_back(*ii++);
    }
  m_NumberOfSeeds = num;
}

/* Set the rectangle that encloses the Voronoi Diagram. */
template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetBoundary(PointType vorsize)
{
  m_VoronoiBoundary[0] = vorsize[0];
  m_VoronoiBoundary[1] = vorsize[1];
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::SetOrigin(PointType vorsize)
{
  m_VoronoiBoundaryOrigin[0] = vorsize[0];
  m_VoronoiBoundaryOrigin[1] = vorsize[1];
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::GetPoint(int pId, PointType *answer)
{
  *answer = this->m_PointsContainer->ElementAt(pId);
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::GetCellId(CellIdentifier cellId, CellAutoPointer & cellPtr)
{
  cellPtr.TakeNoOwnership(m_VoronoiRegions[cellId]);
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::EdgeInfo
VoronoiDiagram2D< TCoordRepType >
::GetSeedsIDAroundEdge(VoronoiEdge *task)
{
  EdgeInfo answer;

  answer[0] = m_LineList[task->m_LineID][0];
  answer[1] = m_LineList[task->m_LineID][1];
  return ( answer );
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VoronoiEdgeIterator
VoronoiDiagram2D< TCoordRepType >
::EdgeBegin()
{
  return m_EdgeList.begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VoronoiEdgeIterator
VoronoiDiagram2D< TCoordRepType >
::EdgeEnd()
{
  return m_EdgeList.end();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::NeighborIdIterator
VoronoiDiagram2D< TCoordRepType >
::NeighborIdsBegin(int seeds)
{
  return m_CellNeighborsID[seeds].begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::NeighborIdIterator
VoronoiDiagram2D< TCoordRepType >
::NeighborIdsEnd(int seeds)
{
  return m_CellNeighborsID[seeds].end();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VertexIterator
VoronoiDiagram2D< TCoordRepType >
::VertexBegin()
{
  return this->m_PointsContainer->Begin();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::VertexIterator
VoronoiDiagram2D< TCoordRepType >
::VertexEnd()
{
  return this->m_PointsContainer->End();
}

template< typename TCoordRepType >
typename VoronoiDiagram2D< TCoordRepType >::PointType
VoronoiDiagram2D< TCoordRepType >
::GetSeed(int SeedID)
{
  PointType answer;

  answer[0] = m_Seeds[SeedID][0];
  answer[1] = m_Seeds[SeedID][1];
  return answer;
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::Reset()
{
  m_VoronoiRegions.clear();
  m_VoronoiRegions.resize(m_NumberOfSeeds);
  m_CellNeighborsID.resize(m_NumberOfSeeds);

  for ( unsigned int i = 0; i < m_NumberOfSeeds; i++ )
    {
    m_VoronoiRegions[i] = new PolygonCellType;
    m_CellNeighborsID[i].clear();
    }
}

template< typename TCoordRepType >
void
VoronoiDiagram2D< TCoordRepType >
::InsertCells()
{
  genericCellPointer cellPtr;

  for ( unsigned int i = 0; i < m_NumberOfSeeds; i++ )
    {
    cellPtr.TakeOwnership(m_VoronoiRegions[i]);
    this->SetCell(i, cellPtr);
    }
}

} // end namespace itk

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "printing/printing_context_no_system_dialog.h"

#include <unicode/ulocdata.h>

#include "base/logging.h"
#include "base/values.h"
#include "printing/metafile.h"
#include "printing/print_job_constants.h"
#include "printing/units.h"

namespace printing {

// static
PrintingContext* PrintingContext::Create(const std::string& app_locale) {
  return static_cast<PrintingContext*>(
      new PrintingContextNoSystemDialog(app_locale));
}

PrintingContextNoSystemDialog::PrintingContextNoSystemDialog(
    const std::string& app_locale) : PrintingContext(app_locale) {
}

PrintingContextNoSystemDialog::~PrintingContextNoSystemDialog() {
  ReleaseContext();
}

void PrintingContextNoSystemDialog::AskUserForSettings(
    gfx::NativeView parent_view,
    int max_pages,
    bool has_selection,
    const PrintSettingsCallback& callback) {
  // We don't want to bring up a dialog here.  Ever.  Just signal the callback.
  callback.Run(OK);
}

PrintingContext::Result PrintingContextNoSystemDialog::UseDefaultSettings() {
  DCHECK(!in_print_job_);

  ResetSettings();
  // TODO(abodenha): Fetch these settings from the OS where possible.  See
  // bug 102583.
  // TODO(sanjeevr): We need a better feedback loop between the cloud print
  // dialog and this code.
  int dpi = 300;
  gfx::Size physical_size_device_units;
  gfx::Rect printable_area_device_units;
  int32_t width = 0;
  int32_t height = 0;
  UErrorCode error = U_ZERO_ERROR;
  ulocdata_getPaperSize(app_locale_.c_str(), &height, &width, &error);
  if (error != U_ZERO_ERROR) {
    // If the call failed, assume a paper size of 8.5 x 11 inches.
    LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
                 << error;
    width = static_cast<int>(8.5 * dpi);
    height = static_cast<int>(11 * dpi);
  } else {
    // ulocdata_getPaperSize returns the width and height in mm.
    // Convert this to pixels based on the dpi.
    width = static_cast<int>(ConvertUnitDouble(width, 25.4, 1.0) * dpi);
    height = static_cast<int>(ConvertUnitDouble(height, 25.4, 1.0) * dpi);
  }

  physical_size_device_units.SetSize(width, height);

  // Assume full page is printable for now.
  printable_area_device_units.SetRect(0, 0, width, height);

  settings_.set_dpi(dpi);
  settings_.SetPrinterPrintableArea(physical_size_device_units,
                                    printable_area_device_units,
                                    dpi);

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::UpdatePrinterSettings(
    const DictionaryValue& job_settings, const PageRanges& ranges) {
  bool landscape = false;

  if (!job_settings.GetBoolean(kSettingLandscape, &landscape))
    return OnError();

  if (settings_.dpi() == 0)
    UseDefaultSettings();

  settings_.SetOrientation(landscape);
  settings_.ranges = ranges;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::InitWithSettings(
    const PrintSettings& settings) {
  DCHECK(!in_print_job_);

  settings_ = settings;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::NewDocument(
    const string16& document_name) {
  DCHECK(!in_print_job_);
  in_print_job_ = true;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::NewPage() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  // Intentional No-op.

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::PageDone() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  // Intentional No-op.

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::DocumentDone() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  ResetSettings();
  return OK;
}

void PrintingContextNoSystemDialog::Cancel() {
  abort_printing_ = true;
  in_print_job_ = false;
}

void PrintingContextNoSystemDialog::ReleaseContext() {
  // Intentional No-op.
}

gfx::NativeDrawingContext PrintingContextNoSystemDialog::context() const {
  // Intentional No-op.
  return NULL;
}

}  // namespace printing

<commit_msg>Fix issue with some locales simetimes getting the wrong page size. We use ulocdata_getPaperSize to get the preferred paper size for a region.  The error handling for the call assumed that a value other than U_ZERO_ERROR was an error.  This is incorrect.  The function sometimes returns a warning (negative value).  When that happens, the error handling code defaulted to 8.5x11 pages.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "printing/printing_context_no_system_dialog.h"

#include <unicode/ulocdata.h>

#include "base/logging.h"
#include "base/values.h"
#include "printing/metafile.h"
#include "printing/print_job_constants.h"
#include "printing/units.h"

namespace printing {

// static
PrintingContext* PrintingContext::Create(const std::string& app_locale) {
  return static_cast<PrintingContext*>(
      new PrintingContextNoSystemDialog(app_locale));
}

PrintingContextNoSystemDialog::PrintingContextNoSystemDialog(
    const std::string& app_locale) : PrintingContext(app_locale) {
}

PrintingContextNoSystemDialog::~PrintingContextNoSystemDialog() {
  ReleaseContext();
}

void PrintingContextNoSystemDialog::AskUserForSettings(
    gfx::NativeView parent_view,
    int max_pages,
    bool has_selection,
    const PrintSettingsCallback& callback) {
  // We don't want to bring up a dialog here.  Ever.  Just signal the callback.
  callback.Run(OK);
}

PrintingContext::Result PrintingContextNoSystemDialog::UseDefaultSettings() {
  DCHECK(!in_print_job_);

  ResetSettings();
  // TODO(abodenha): Fetch these settings from the OS where possible.  See
  // bug 102583.
  // TODO(sanjeevr): We need a better feedback loop between the cloud print
  // dialog and this code.
  int dpi = 300;
  gfx::Size physical_size_device_units;
  gfx::Rect printable_area_device_units;
  int32_t width = 0;
  int32_t height = 0;
  UErrorCode error = U_ZERO_ERROR;
  ulocdata_getPaperSize(app_locale_.c_str(), &height, &width, &error);
  if (error > U_ZERO_ERROR) {
    // If the call failed, assume a paper size of 8.5 x 11 inches.
    LOG(WARNING) << "ulocdata_getPaperSize failed, using 8.5 x 11, error: "
                 << error;
    width = static_cast<int>(8.5 * dpi);
    height = static_cast<int>(11 * dpi);
  } else {
    // ulocdata_getPaperSize returns the width and height in mm.
    // Convert this to pixels based on the dpi.
    width = static_cast<int>(ConvertUnitDouble(width, 25.4, 1.0) * dpi);
    height = static_cast<int>(ConvertUnitDouble(height, 25.4, 1.0) * dpi);
  }

  physical_size_device_units.SetSize(width, height);

  // Assume full page is printable for now.
  printable_area_device_units.SetRect(0, 0, width, height);

  settings_.set_dpi(dpi);
  settings_.SetPrinterPrintableArea(physical_size_device_units,
                                    printable_area_device_units,
                                    dpi);

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::UpdatePrinterSettings(
    const DictionaryValue& job_settings, const PageRanges& ranges) {
  bool landscape = false;

  if (!job_settings.GetBoolean(kSettingLandscape, &landscape))
    return OnError();

  if (settings_.dpi() == 0)
    UseDefaultSettings();

  settings_.SetOrientation(landscape);
  settings_.ranges = ranges;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::InitWithSettings(
    const PrintSettings& settings) {
  DCHECK(!in_print_job_);

  settings_ = settings;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::NewDocument(
    const string16& document_name) {
  DCHECK(!in_print_job_);
  in_print_job_ = true;

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::NewPage() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  // Intentional No-op.

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::PageDone() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  // Intentional No-op.

  return OK;
}

PrintingContext::Result PrintingContextNoSystemDialog::DocumentDone() {
  if (abort_printing_)
    return CANCEL;
  DCHECK(in_print_job_);

  ResetSettings();
  return OK;
}

void PrintingContextNoSystemDialog::Cancel() {
  abort_printing_ = true;
  in_print_job_ = false;
}

void PrintingContextNoSystemDialog::ReleaseContext() {
  // Intentional No-op.
}

gfx::NativeDrawingContext PrintingContextNoSystemDialog::context() const {
  // Intentional No-op.
  return NULL;
}

}  // namespace printing

<|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "CaptureServiceImpl.h"

#include <absl/container/flat_hash_set.h>
#include <absl/synchronization/mutex.h>
#include <absl/time/time.h>
#include <pthread.h>
#include <stdint.h>

#include <algorithm>
#include <limits>
#include <thread>
#include <utility>
#include <vector>

#include "CaptureEventBuffer.h"
#include "CaptureEventSender.h"
#include "LinuxTracingHandler.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Tracing.h"
#include "ProducerEventProcessor.h"
#include "capture.pb.h"

namespace orbit_service {

using orbit_grpc_protos::CaptureRequest;
using orbit_grpc_protos::CaptureResponse;

namespace {

using orbit_grpc_protos::ClientCaptureEvent;

class SenderThreadCaptureEventBuffer final : public CaptureEventBuffer {
 public:
  explicit SenderThreadCaptureEventBuffer(CaptureEventSender* event_sender)
      : capture_event_sender_{event_sender} {
    CHECK(capture_event_sender_ != nullptr);
    sender_thread_ = std::thread{[this] { SenderThread(); }};
  }

  void AddEvent(ClientCaptureEvent&& event) override {
    absl::MutexLock lock{&event_buffer_mutex_};
    if (stop_requested_) {
      return;
    }
    event_buffer_.emplace_back(std::move(event));
  }

  void StopAndWait() {
    CHECK(sender_thread_.joinable());
    {
      // Protect stop_requested_ with event_buffer_mutex_ so that we can use stop_requested_
      // in Conditions for Await/LockWhen (specifically, in SenderThread).
      absl::MutexLock lock{&event_buffer_mutex_};
      stop_requested_ = true;
    }
    sender_thread_.join();
  }

  ~SenderThreadCaptureEventBuffer() override { CHECK(!sender_thread_.joinable()); }

 private:
  void SenderThread() {
    pthread_setname_np(pthread_self(), "SenderThread");
    constexpr absl::Duration kSendTimeInterval = absl::Milliseconds(20);
    // This should be lower than kMaxEventsPerResponse in GrpcCaptureEventSender::SendEvents
    // as a few more events are likely to arrive after the condition becomes true.
    constexpr uint64_t kSendEventCountInterval = 5000;

    bool stopped = false;
    while (!stopped) {
      ORBIT_SCOPE("SenderThread iteration");
      event_buffer_mutex_.LockWhenWithTimeout(absl::Condition(
                                                  +[](SenderThreadCaptureEventBuffer* self) {
                                                    return self->event_buffer_.size() >=
                                                               kSendEventCountInterval ||
                                                           self->stop_requested_;
                                                  },
                                                  this),
                                              kSendTimeInterval);
      if (stop_requested_) {
        stopped = true;
      }
      std::vector<ClientCaptureEvent> buffered_events = std::move(event_buffer_);
      event_buffer_.clear();
      event_buffer_mutex_.Unlock();
      capture_event_sender_->SendEvents(std::move(buffered_events));
    }
  }

  std::vector<ClientCaptureEvent> event_buffer_;
  absl::Mutex event_buffer_mutex_;
  CaptureEventSender* capture_event_sender_;
  std::thread sender_thread_;
  bool stop_requested_ = false;
};

class GrpcCaptureEventSender final : public CaptureEventSender {
 public:
  explicit GrpcCaptureEventSender(
      grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer)
      : reader_writer_{reader_writer} {
    CHECK(reader_writer_ != nullptr);
  }

  ~GrpcCaptureEventSender() override {
    LOG("Total number of events sent: %lu", total_number_of_events_sent_);
    LOG("Total number of bytes sent: %lu", total_number_of_bytes_sent_);

    // Ensure we can divide by 0.f safely.
    static_assert(std::numeric_limits<float>::is_iec559);
    float average_bytes =
        static_cast<float>(total_number_of_bytes_sent_) / total_number_of_events_sent_;

    LOG("Average number of bytes per event: %.2f", average_bytes);
  }

  void SendEvents(std::vector<ClientCaptureEvent>&& events) override {
    ORBIT_SCOPE_FUNCTION;
    ORBIT_UINT64("Number of buffered events sent", events.size());
    if (events.empty()) {
      return;
    }

    constexpr uint64_t kMaxEventsPerResponse = 10'000;
    uint64_t number_of_bytes_sent = 0;
    CaptureResponse response;
    for (ClientCaptureEvent& event : events) {
      // We buffer to avoid sending countless tiny messages, but we also want to
      // avoid huge messages, which would cause the capture on the client to jump
      // forward in time in few big steps and not look live anymore.
      if (response.capture_events_size() == kMaxEventsPerResponse) {
        number_of_bytes_sent += response.ByteSizeLong();
        reader_writer_->Write(response);
        response.clear_capture_events();
      }
      response.mutable_capture_events()->Add(std::move(event));
    }
    number_of_bytes_sent += response.ByteSizeLong();
    reader_writer_->Write(response);

    // Ensure we can divide by 0.f safely.
    static_assert(std::numeric_limits<float>::is_iec559);
    float average_bytes = static_cast<float>(number_of_bytes_sent) / events.size();

    ORBIT_FLOAT("Average bytes per CaptureEvent", average_bytes);
    total_number_of_events_sent_ += events.size();
    total_number_of_bytes_sent_ += number_of_bytes_sent;
  }

 private:
  grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer_;

  uint64_t total_number_of_events_sent_ = 0;
  uint64_t total_number_of_bytes_sent_ = 0;
};

}  // namespace

// LinuxTracingHandler::Stop is blocking, until all perf_event_open events have been processed
// and all perf_event_open file descriptors have been closed.
// CaptureStartStopListener::OnCaptureStopRequested is also to be assumed blocking,
// for example until all CaptureEvents from external producers have been received.
// Hence why these methods need to be called in parallel on different threads.
static void StopTracingHandlerAndCaptureStartStopListenersInParallel(
    LinuxTracingHandler* tracing_handler,
    absl::flat_hash_set<CaptureStartStopListener*>* capture_start_stop_listeners) {
  std::vector<std::thread> stop_threads;

  stop_threads.emplace_back([&tracing_handler] {
    tracing_handler->Stop();
    LOG("LinuxTracingHandler stopped: perf_event_open tracing is done");
  });

  for (CaptureStartStopListener* listener : *capture_start_stop_listeners) {
    stop_threads.emplace_back([&listener] {
      listener->OnCaptureStopRequested();
      LOG("CaptureStartStopListener stopped: one or more producers finished capturing");
    });
  }

  for (std::thread& stop_thread : stop_threads) {
    stop_thread.join();
  }
}

grpc::Status CaptureServiceImpl::Capture(
    grpc::ServerContext*,
    grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer) {
  pthread_setname_np(pthread_self(), "CSImpl::Capture");
  if (is_capturing) {
    ERROR("Cannot start capture because another capture is already in progress");
    return grpc::Status(grpc::StatusCode::ALREADY_EXISTS,
                        "Cannot start capture because another capture is already in progress.");
  }
  is_capturing = true;

  GrpcCaptureEventSender capture_event_sender{reader_writer};
  SenderThreadCaptureEventBuffer capture_event_buffer{&capture_event_sender};
  std::unique_ptr<ProducerEventProcessor> producer_event_processor =
      ProducerEventProcessor::Create(&capture_event_buffer);
  LinuxTracingHandler tracing_handler{producer_event_processor.get()};

  CaptureRequest request;
  reader_writer->Read(&request);
  LOG("Read CaptureRequest from Capture's gRPC stream: starting capture");

  tracing_handler.Start(request.capture_options());
  for (CaptureStartStopListener* listener : capture_start_stop_listeners_) {
    listener->OnCaptureStartRequested(request.capture_options(), producer_event_processor.get());
  }

  // The client asks for the capture to be stopped by calling WritesDone.
  // At that point, this call to Read will return false.
  // In the meantime, it blocks if no message is received.
  while (reader_writer->Read(&request)) {
  }
  LOG("Client finished writing on Capture's gRPC stream: stopping capture");

  StopTracingHandlerAndCaptureStartStopListenersInParallel(&tracing_handler,
                                                           &capture_start_stop_listeners_);

  capture_event_buffer.StopAndWait();
  LOG("Finished handling gRPC call to Capture: all capture data has been sent");
  is_capturing = false;
  return grpc::Status::OK;
}

void CaptureServiceImpl::AddCaptureStartStopListener(CaptureStartStopListener* listener) {
  bool new_insertion = capture_start_stop_listeners_.insert(listener).second;
  CHECK(new_insertion);
}

void CaptureServiceImpl::RemoveCaptureStartStopListener(CaptureStartStopListener* listener) {
  bool was_removed = capture_start_stop_listeners_.erase(listener) > 0;
  CHECK(was_removed);
}

}  // namespace orbit_service
<commit_msg>Integrate MemoryInfoProducer to CaptureService<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "CaptureServiceImpl.h"

#include <absl/container/flat_hash_set.h>
#include <absl/synchronization/mutex.h>
#include <absl/time/time.h>
#include <pthread.h>
#include <stdint.h>

#include <algorithm>
#include <limits>
#include <thread>
#include <utility>
#include <vector>

#include "CaptureEventBuffer.h"
#include "CaptureEventSender.h"
#include "LinuxTracingHandler.h"
#include "MemoryInfoHandler.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Tracing.h"
#include "ProducerEventProcessor.h"
#include "capture.pb.h"

namespace orbit_service {

using orbit_grpc_protos::CaptureRequest;
using orbit_grpc_protos::CaptureResponse;

namespace {

using orbit_grpc_protos::ClientCaptureEvent;

class SenderThreadCaptureEventBuffer final : public CaptureEventBuffer {
 public:
  explicit SenderThreadCaptureEventBuffer(CaptureEventSender* event_sender)
      : capture_event_sender_{event_sender} {
    CHECK(capture_event_sender_ != nullptr);
    sender_thread_ = std::thread{[this] { SenderThread(); }};
  }

  void AddEvent(ClientCaptureEvent&& event) override {
    absl::MutexLock lock{&event_buffer_mutex_};
    if (stop_requested_) {
      return;
    }
    event_buffer_.emplace_back(std::move(event));
  }

  void StopAndWait() {
    CHECK(sender_thread_.joinable());
    {
      // Protect stop_requested_ with event_buffer_mutex_ so that we can use stop_requested_
      // in Conditions for Await/LockWhen (specifically, in SenderThread).
      absl::MutexLock lock{&event_buffer_mutex_};
      stop_requested_ = true;
    }
    sender_thread_.join();
  }

  ~SenderThreadCaptureEventBuffer() override { CHECK(!sender_thread_.joinable()); }

 private:
  void SenderThread() {
    pthread_setname_np(pthread_self(), "SenderThread");
    constexpr absl::Duration kSendTimeInterval = absl::Milliseconds(20);
    // This should be lower than kMaxEventsPerResponse in GrpcCaptureEventSender::SendEvents
    // as a few more events are likely to arrive after the condition becomes true.
    constexpr uint64_t kSendEventCountInterval = 5000;

    bool stopped = false;
    while (!stopped) {
      ORBIT_SCOPE("SenderThread iteration");
      event_buffer_mutex_.LockWhenWithTimeout(absl::Condition(
                                                  +[](SenderThreadCaptureEventBuffer* self) {
                                                    return self->event_buffer_.size() >=
                                                               kSendEventCountInterval ||
                                                           self->stop_requested_;
                                                  },
                                                  this),
                                              kSendTimeInterval);
      if (stop_requested_) {
        stopped = true;
      }
      std::vector<ClientCaptureEvent> buffered_events = std::move(event_buffer_);
      event_buffer_.clear();
      event_buffer_mutex_.Unlock();
      capture_event_sender_->SendEvents(std::move(buffered_events));
    }
  }

  std::vector<ClientCaptureEvent> event_buffer_;
  absl::Mutex event_buffer_mutex_;
  CaptureEventSender* capture_event_sender_;
  std::thread sender_thread_;
  bool stop_requested_ = false;
};

class GrpcCaptureEventSender final : public CaptureEventSender {
 public:
  explicit GrpcCaptureEventSender(
      grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer)
      : reader_writer_{reader_writer} {
    CHECK(reader_writer_ != nullptr);
  }

  ~GrpcCaptureEventSender() override {
    LOG("Total number of events sent: %lu", total_number_of_events_sent_);
    LOG("Total number of bytes sent: %lu", total_number_of_bytes_sent_);

    // Ensure we can divide by 0.f safely.
    static_assert(std::numeric_limits<float>::is_iec559);
    float average_bytes =
        static_cast<float>(total_number_of_bytes_sent_) / total_number_of_events_sent_;

    LOG("Average number of bytes per event: %.2f", average_bytes);
  }

  void SendEvents(std::vector<ClientCaptureEvent>&& events) override {
    ORBIT_SCOPE_FUNCTION;
    ORBIT_UINT64("Number of buffered events sent", events.size());
    if (events.empty()) {
      return;
    }

    constexpr uint64_t kMaxEventsPerResponse = 10'000;
    uint64_t number_of_bytes_sent = 0;
    CaptureResponse response;
    for (ClientCaptureEvent& event : events) {
      // We buffer to avoid sending countless tiny messages, but we also want to
      // avoid huge messages, which would cause the capture on the client to jump
      // forward in time in few big steps and not look live anymore.
      if (response.capture_events_size() == kMaxEventsPerResponse) {
        number_of_bytes_sent += response.ByteSizeLong();
        reader_writer_->Write(response);
        response.clear_capture_events();
      }
      response.mutable_capture_events()->Add(std::move(event));
    }
    number_of_bytes_sent += response.ByteSizeLong();
    reader_writer_->Write(response);

    // Ensure we can divide by 0.f safely.
    static_assert(std::numeric_limits<float>::is_iec559);
    float average_bytes = static_cast<float>(number_of_bytes_sent) / events.size();

    ORBIT_FLOAT("Average bytes per CaptureEvent", average_bytes);
    total_number_of_events_sent_ += events.size();
    total_number_of_bytes_sent_ += number_of_bytes_sent;
  }

 private:
  grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer_;

  uint64_t total_number_of_events_sent_ = 0;
  uint64_t total_number_of_bytes_sent_ = 0;
};

}  // namespace

// LinuxTracingHandler::Stop is blocking, until all perf_event_open events have been processed
// and all perf_event_open file descriptors have been closed.
// CaptureStartStopListener::OnCaptureStopRequested is also to be assumed blocking,
// for example until all CaptureEvents from external producers have been received.
// Hence why these methods need to be called in parallel on different threads.
static void StopInternalProducersAndCaptureStartStopListenersInParallel(
    LinuxTracingHandler* tracing_handler, MemoryInfoHandler* memory_info_handler,
    absl::flat_hash_set<CaptureStartStopListener*>* capture_start_stop_listeners) {
  std::vector<std::thread> stop_threads;

  stop_threads.emplace_back([&tracing_handler] {
    tracing_handler->Stop();
    LOG("LinuxTracingHandler stopped: perf_event_open tracing is done");
  });

  stop_threads.emplace_back([&memory_info_handler] {
    memory_info_handler->Stop();
    LOG("MemoryInfoHandler stopped: total memory usage information collection is done");
  });

  for (CaptureStartStopListener* listener : *capture_start_stop_listeners) {
    stop_threads.emplace_back([&listener] {
      listener->OnCaptureStopRequested();
      LOG("CaptureStartStopListener stopped: one or more producers finished capturing");
    });
  }

  for (std::thread& stop_thread : stop_threads) {
    stop_thread.join();
  }
}

grpc::Status CaptureServiceImpl::Capture(
    grpc::ServerContext*,
    grpc::ServerReaderWriter<CaptureResponse, CaptureRequest>* reader_writer) {
  pthread_setname_np(pthread_self(), "CSImpl::Capture");
  if (is_capturing) {
    ERROR("Cannot start capture because another capture is already in progress");
    return grpc::Status(grpc::StatusCode::ALREADY_EXISTS,
                        "Cannot start capture because another capture is already in progress.");
  }
  is_capturing = true;

  GrpcCaptureEventSender capture_event_sender{reader_writer};
  SenderThreadCaptureEventBuffer capture_event_buffer{&capture_event_sender};
  std::unique_ptr<ProducerEventProcessor> producer_event_processor =
      ProducerEventProcessor::Create(&capture_event_buffer);
  LinuxTracingHandler tracing_handler{producer_event_processor.get()};
  MemoryInfoHandler memory_info_handler{producer_event_processor.get()};

  CaptureRequest request;
  reader_writer->Read(&request);
  LOG("Read CaptureRequest from Capture's gRPC stream: starting capture");

  tracing_handler.Start(request.capture_options());
  memory_info_handler.Start(request.capture_options());
  for (CaptureStartStopListener* listener : capture_start_stop_listeners_) {
    listener->OnCaptureStartRequested(request.capture_options(), producer_event_processor.get());
  }

  // The client asks for the capture to be stopped by calling WritesDone.
  // At that point, this call to Read will return false.
  // In the meantime, it blocks if no message is received.
  while (reader_writer->Read(&request)) {
  }
  LOG("Client finished writing on Capture's gRPC stream: stopping capture");

  StopInternalProducersAndCaptureStartStopListenersInParallel(
      &tracing_handler, &memory_info_handler, &capture_start_stop_listeners_);

  capture_event_buffer.StopAndWait();
  LOG("Finished handling gRPC call to Capture: all capture data has been sent");
  is_capturing = false;
  return grpc::Status::OK;
}

void CaptureServiceImpl::AddCaptureStartStopListener(CaptureStartStopListener* listener) {
  bool new_insertion = capture_start_stop_listeners_.insert(listener).second;
  CHECK(new_insertion);
}

void CaptureServiceImpl::RemoveCaptureStartStopListener(CaptureStartStopListener* listener) {
  bool was_removed = capture_start_stop_listeners_.erase(listener) > 0;
  CHECK(was_removed);
}

}  // namespace orbit_service
<|endoftext|>


<commit_before>#ifndef UTIL_H
#define UTIL_H

#include <GL/gl.h>
#include <cmath>
#include <FTGL/ftgl.h>

#include "../Vector3.hpp"
#include "../Box2.hpp"
#include "../Physical.hpp"

#include <boost/math/constants/constants.hpp>
using namespace boost::math;

namespace {
const float TO_DEGREES = 180 / constants::pi<float>();
const float TO_RADIANS = constants::pi<float>() / 180;
}

namespace nt {
namespace gl {

void setGLFrustum(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);

void drawText(FTFont& font, const char* text, int yOffset);

template <typename Vector>
void glVertex(const Vector& vec);
void glVertex(const float& x, const float& y, const float& z);
void glVertex(const double& x, const double& y, const double& z);

template <typename Vector>
void glNormal(const Vector& vec);
void glNormal(const float& x, const float& y, const float& z);
void glNormal(const double& x, const double& y, const double& z);

template <typename Vector>
void glTranslate(const Vector& vec);
void glTranslate(const float& x, const float& y, const float& z);
void glTranslate(const double& x, const double& y, const double& z);

template <typename Scalar>
void glTransform(const Physical<Scalar>& physical);

template <typename Scalar>
void glReverseTransform(const Physical<Scalar>& physical);

void glScissor(const Box2<int>& screenArea);

Vector3<double> getAxisAngles(Vector3<double>& vec);

void glViewport(const Box2<int>& viewArea);

// Implementation follows:

template <typename Vector>
void glVertex(const Vector& vec)
{
	glVertex(vec.x(), vec.y(), vec.z());
}

template <typename Vector>
void glNormal(const Vector& vec)
{
	glNormal(vec.x(), vec.y(), vec.z());
}

template <typename Vector>
void glTranslate(const Vector& vec)
{
    glTranslate(vec.x(), vec.y(), vec.z());
}

template <class T, class U>
void glRotateRadians(const Vector3<T, U>& vec)
{
    glRotated(vec.z() * TO_DEGREES, 0, 0, 1);
    glRotated(vec.x() * TO_DEGREES, 1, 0, 0);
    //glRotated(vec.y() * TO_DEGREES, 0, 1, 0);

}

template <class T, class U>
void glRotateDegrees(const Vector3<T, U>& vec)
{
    glRotated(vec.z(), 0, 0, 1);
    glRotated(vec.x(), 1, 0, 0);
    // glRotated(vec.y(), 0, 1, 0);

}

template <class U>
void glRotateRadians(const Vector3<float, U>& vec)
{
    glRotatef(vec.z() * TO_DEGREES, 0, 0, 1);
    glRotatef(vec.x() * TO_DEGREES, 1, 0, 0);
    //glRotatef(vec.y() * TO_DEGREES, 0, 1, 0);

}

template <class U>
void glRotateDegrees(const Vector3<float, U>& vec)
{
    glRotatef(vec.z(), 0, 0, 1);
    glRotatef(vec.x(), 1, 0, 0);
    // glRotatef(vec.y(), 0, 1, 0);

}
// these 2 functions are for the camera
// backwards means everything flipped!
// values are negative and x is rotated before z
template <class U>
void glRotateRadiansBackwards(const Vector3<float, U>& vec)
{
    glRotatef(-vec.x() * TO_DEGREES, 1, 0, 0);
    glRotatef(-vec.z() * TO_DEGREES, 0, 0, 1);
}
template <class T, class U>
void glRotateRadiansBackwards(const Vector3<T, U>& vec)
{
    glRotated(-vec.x() * TO_DEGREES, 1, 0, 0);
    glRotated(-vec.z() * TO_DEGREES, 0, 0, 1);
}

template <typename Scalar>
void glTransform(const Physical<Scalar>& physical)
{
    glTranslate(physical.getPosition());
    glRotateRadians(physical.getRotation());
}

template <typename Scalar>
void glReverseTransform(const Physical<Scalar>& physical)
{
    glRotateRadians(physical.getRotation());
    glTranslate(-physical.getPosition());
}

} // namespace gl
} // namespace nt

#endif // UTIL_H
<commit_msg>Ignore Z-axis rotation, not Y-axis rotation<commit_after>#ifndef UTIL_H
#define UTIL_H

#include <GL/gl.h>
#include <cmath>
#include <FTGL/ftgl.h>

#include "../Vector3.hpp"
#include "../Box2.hpp"
#include "../Physical.hpp"

#include <boost/math/constants/constants.hpp>
using namespace boost::math;

namespace {
const float TO_DEGREES = 180 / constants::pi<float>();
const float TO_RADIANS = constants::pi<float>() / 180;
}

namespace nt {
namespace gl {

void setGLFrustum(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);

void drawText(FTFont& font, const char* text, int yOffset);

template <typename Vector>
void glVertex(const Vector& vec);
void glVertex(const float& x, const float& y, const float& z);
void glVertex(const double& x, const double& y, const double& z);

template <typename Vector>
void glNormal(const Vector& vec);
void glNormal(const float& x, const float& y, const float& z);
void glNormal(const double& x, const double& y, const double& z);

template <typename Vector>
void glTranslate(const Vector& vec);
void glTranslate(const float& x, const float& y, const float& z);
void glTranslate(const double& x, const double& y, const double& z);

template <typename Scalar>
void glTransform(const Physical<Scalar>& physical);

template <typename Scalar>
void glReverseTransform(const Physical<Scalar>& physical);

void glScissor(const Box2<int>& screenArea);

Vector3<double> getAxisAngles(Vector3<double>& vec);

void glViewport(const Box2<int>& viewArea);

// Implementation follows:

template <typename Vector>
void glVertex(const Vector& vec)
{
	glVertex(vec.x(), vec.y(), vec.z());
}

template <typename Vector>
void glNormal(const Vector& vec)
{
	glNormal(vec.x(), vec.y(), vec.z());
}

template <typename Vector>
void glTranslate(const Vector& vec)
{
    glTranslate(vec.x(), vec.y(), vec.z());
}

template <class T, class U>
void glRotateRadians(const Vector3<T, U>& vec)
{
    //glRotated(vec.z() * TO_DEGREES, 0, 0, 1);
    glRotated(vec.x() * TO_DEGREES, 1, 0, 0);
    glRotated(vec.y() * TO_DEGREES, 0, 1, 0);

}

template <class T, class U>
void glRotateDegrees(const Vector3<T, U>& vec)
{
    //glRotated(vec.z(), 0, 0, 1);
    glRotated(vec.x(), 1, 0, 0);
    glRotated(vec.y(), 0, 1, 0);

}

template <class U>
void glRotateRadians(const Vector3<float, U>& vec)
{
    //glRotatef(vec.z() * TO_DEGREES, 0, 0, 1);
    glRotatef(vec.x() * TO_DEGREES, 1, 0, 0);
    glRotatef(vec.y() * TO_DEGREES, 0, 1, 0);

}

template <class U>
void glRotateDegrees(const Vector3<float, U>& vec)
{
    //glRotatef(vec.z(), 0, 0, 1);
    glRotatef(vec.x(), 1, 0, 0);
    glRotatef(vec.y(), 0, 1, 0);

}
// these 2 functions are for the camera
// backwards means everything flipped!
// values are negative and x is rotated before z
template <class U>
void glRotateRadiansBackwards(const Vector3<float, U>& vec)
{
    glRotatef(-vec.x() * TO_DEGREES, 1, 0, 0);
    glRotatef(-vec.y() * TO_DEGREES, 0, 1, 0);
}
template <class T, class U>
void glRotateRadiansBackwards(const Vector3<T, U>& vec)
{
    glRotated(-vec.x() * TO_DEGREES, 1, 0, 0);
    glRotated(-vec.y() * TO_DEGREES, 0, 1, 0);
}

template <typename Scalar>
void glTransform(const Physical<Scalar>& physical)
{
    glTranslate(physical.getPosition());
    glRotateRadians(physical.getRotation());
}

template <typename Scalar>
void glReverseTransform(const Physical<Scalar>& physical)
{
    glRotateRadians(physical.getRotation());
    glTranslate(-physical.getPosition());
}

} // namespace gl
} // namespace nt

#endif // UTIL_H
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * 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.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** 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 HOLDER 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 "nodes/Reference.h"
#include "commands/FieldSet.h"
#include "model/TreeManager.h"
#include "ModelException.h"
#include "NameText.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(Model::Reference)

namespace Model {

NODE_DEFINE_TYPE_REGISTRATION_METHODS(Reference)

QList<Reference*> Reference::allReferences_;
QSet<Reference*> Reference::pendingResolution_;
QList<std::function<void (Node* subTree)>> Reference::unresolutionSteps_;

Reference::Reference(Node *parent) : Super(parent)
{
	allReferences_.append(this);
	if (parent && parent->manager()) pendingResolution_.insert(this);
}

Reference::Reference(Node *parent, PersistentStore &store, bool) : Super(parent)
{
	allReferences_.append(this);
	name_ = store.loadReferenceValue(this);
	if (state_ == ReferenceNeedsToBeResolved && parent && parent->manager())
		pendingResolution_.insert(this);
}

Reference::~Reference()
{
	pendingResolution_.remove(this);
	allReferences_.removeAll(this);
}

void Reference::setName(const QString &name)
{
	if (name != name_)
	{
		execute(new FieldSet<QString> (this, name_, name));
		target_ = nullptr;
		setResolutionNeeded();
	}
}

Node* Reference::computeTarget() const
{
	Q_ASSERT(false && "Should not call Reference::computeTarget()");
	return nullptr;
}

bool Reference::resolveHelper(bool indirect)
{
	// TODO this is not multithread friendly.
	if (state_ != ReferenceNeedsToBeResolved) return isResolved();
	state_ = ReferenceIsBeingResolved;

	auto newTarget = computeTarget();

	//TODO@cyril What is this for?
//	Q_ASSERT(!newTarget || (newTarget->definesSymbol() && newTarget->symbolName() == name_));

	auto oldTarget = target_;
	target_ = newTarget;

	if (target_ || !indirect)
	{
		// This is needed because of the following situation.
		// We are resolving a reference A, and during the process we explore reference B, needed for the resolution of A,
		// and reference C, which is not needed for the resolution of A. All references but A will be explored indirectly.
		// It could happen that to resolve C properly we need to resolve A first. Therefore when failing to resolve a
		// reference that is explored indirectly, we shouldn't assume that resolution will fail.
		pendingResolution_.remove(this);
		state_ = ReferenceEstablished;
	}
	else state_ = ReferenceNeedsToBeResolved;

	if (oldTarget != target_) targetChanged(oldTarget);

	return isResolved();
}

void Reference::targetChanged(Node*){}

void Reference::save(PersistentStore &store) const
{
	store.saveReferenceValue(name_, target_);
}

void Reference::load(PersistentStore &store)
{
	// TODO: Implement reference loading properly.
	throw ModelException("Loading references outside a Reference constructor is not properly implemented yet");

	if (store.currentNodeType() != typeName())
		throw ModelException("Trying to load a Reference node from an incompatible node type " + store.currentNodeType());

	setName( store.loadReferenceValue(this) );
}

Node* Reference::target()
{
	if (state_ == ReferenceNeedsToBeResolved) resolveHelper(true);
	return state_ == ReferenceEstablished ? target_ : nullptr;
}

void Reference::setResolutionNeeded()
{
	state_ = ReferenceNeedsToBeResolved;
	pendingResolution_.insert(this);
}

template<class NodeType>
void Reference::forAll(Node* subTree, std::function<void (NodeType*)> function)
{
	if (subTree)
	{
		QList<Node*> stack;
		stack << subTree;
		while (!stack.isEmpty())
		{
			auto top = stack.takeLast();

			if (auto node = DCast<NodeType>(top) ) function(node);
			else stack.append(top->children());
		}
	}
}

void Reference::unresolveReferencesHelper(Node* subTree, bool all,
	const QSet<QString>& names)
{
	if (!subTree || (!all && names.isEmpty())) return;

	auto targetManager = subTree->manager();
	bool isRoot = !subTree->parent();

	std::function<void (Reference*)> f;
	if (all)
	{
		f = [](Reference* ref) { ref->setResolutionNeeded();};
	}
	else
	{
		if (names.size() == 2)
		{
			//This case occurs when changing a name. This happens when the user is typing and therefore it is very
			//performance sensitive. Thus we optimize it specially.

			QString first = *names.begin();
			QString second = *++names.begin();

			// Removing this if, and just leaving the statement at the of this method to handle the updates using the
			// defined f function is slow. In one test an additional 4-5ms were needed on top of the 10-13ms processing
			// time on a 3.4GHz CPU. Therefore there is a significant cost associated with calling the f function, and
			// it's betterto just process this case here directly.
			// If needed this optimization could also be used in the other cases.
			if (isRoot)
			{
				for (auto ref : allReferences_)
					if (targetManager == ref->manager())
					{
						auto& refName = ref->name();
						if (refName == first || refName == second)
							ref->setResolutionNeeded();
					}
				return;
			}

			f = [=](Reference* ref)
				{ auto& refName = ref->name(); if (refName == first || refName == second) ref->setResolutionNeeded();};
		}
		else if (names.size() < 20) // Optimize in the case of just a few names, by avoiding hasing.
		{
			// TODO: Find out what's a good value for the magick number 20 above.
			QMap<QString, int> mapNames;
			for (auto n : names) mapNames.insert(n, 0); // TODO: isn't there a way to put void here?

			f = [=](Reference* ref) { if (mapNames.contains(ref->name())) ref->setResolutionNeeded();};
		}
		else
		{
			f = [=](Reference* ref) { if (names.contains(ref->name())) ref->setResolutionNeeded();};
		}
	}

	if (isRoot)
	{
		for (auto ref : allReferences_) if (targetManager == ref->manager()) f(ref);
	}
	else
	{
		// If this is not the root, then explore the references only in the specified subTree, which is faster
		forAll<Reference>(subTree, f);
	}

}

void Reference::unresolveAll(Node* subTree)
{
	unresolveReferencesHelper(subTree, true, {});
}

void Reference::unresolveNames(Node* subTree, const QSet<QString>& names)
{
	unresolveReferencesHelper(subTree, false, names);
}

void Reference::unresolveIfNameIntroduced(Node* subTreeToUnresolve,
		Node* subTreeToLookForNewNames)
{
	QSet<QString> names;
	forAll<NameText>(subTreeToLookForNewNames, [&names](NameText* name){ names.insert(name->get());});
	unresolveReferencesHelper(subTreeToUnresolve, false, names);
}

void Reference::unresolveAfterNewSubTree(Node* subTree)
{
	Reference::unresolveAll(subTree);
	Reference::unresolveIfNameIntroduced(subTree->root(), subTree);
	for (auto step : unresolutionSteps_) step(subTree);
}

void Reference::addUnresolutionSteps(std::function<void (Node* subTree)> step)
{
	unresolutionSteps_.append(step);
}

void Reference::resolvePending()
{
	log.debug("Resolving references");

	int i = 0;
	int round = 0;
	int resolved = 0;
	auto pending = pendingResolution_;

	while (!pending.isEmpty())
	{
		log.debug("resolution round " + QString::number(round) + ", "
					 + QString::number(pendingResolution_.size()) + " references pending.");
		++round;

		for (auto r : pending)
		{
			if ( r->resolve() ) ++resolved;
			if (++i % 10000 == 0)	log.debug("Processed " + QString::number(i) + " references.");
		}

		// As a result of resolution of some references, some other references could have become invalid.
		pending = pendingResolution_;
	}

	log.debug(QString::number(resolved) + " resolution" + (resolved == 1 ? "" : "s") + " in "
				 + QString::number(round) + (round > 1 ? " rounds." : " round."));

	int totalResolvedReferences = 0;
	for (auto r : allReferences_) if (r->isResolved()) ++totalResolvedReferences;
	log.debug("Total number of resolved references: " + QString::number(totalResolvedReferences));
}

}
<commit_msg>Uncomment Q_ASSERT<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * 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.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** 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 HOLDER 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 "nodes/Reference.h"
#include "commands/FieldSet.h"
#include "model/TreeManager.h"
#include "ModelException.h"
#include "NameText.h"

#include "ModelBase/src/nodes/TypedListDefinition.h"
DEFINE_TYPED_LIST(Model::Reference)

namespace Model {

NODE_DEFINE_TYPE_REGISTRATION_METHODS(Reference)

QList<Reference*> Reference::allReferences_;
QSet<Reference*> Reference::pendingResolution_;
QList<std::function<void (Node* subTree)>> Reference::unresolutionSteps_;

Reference::Reference(Node *parent) : Super(parent)
{
	allReferences_.append(this);
	if (parent && parent->manager()) pendingResolution_.insert(this);
}

Reference::Reference(Node *parent, PersistentStore &store, bool) : Super(parent)
{
	allReferences_.append(this);
	name_ = store.loadReferenceValue(this);
	if (state_ == ReferenceNeedsToBeResolved && parent && parent->manager())
		pendingResolution_.insert(this);
}

Reference::~Reference()
{
	pendingResolution_.remove(this);
	allReferences_.removeAll(this);
}

void Reference::setName(const QString &name)
{
	if (name != name_)
	{
		execute(new FieldSet<QString> (this, name_, name));
		target_ = nullptr;
		setResolutionNeeded();
	}
}

Node* Reference::computeTarget() const
{
	Q_ASSERT(false && "Should not call Reference::computeTarget()");
	return nullptr;
}

bool Reference::resolveHelper(bool indirect)
{
	// TODO this is not multithread friendly.
	if (state_ != ReferenceNeedsToBeResolved) return isResolved();
	state_ = ReferenceIsBeingResolved;

	auto newTarget = computeTarget();

	Q_ASSERT(!newTarget || (newTarget->definesSymbol() && newTarget->symbolName() == name_));

	auto oldTarget = target_;
	target_ = newTarget;

	if (target_ || !indirect)
	{
		// This is needed because of the following situation.
		// We are resolving a reference A, and during the process we explore reference B, needed for the resolution of A,
		// and reference C, which is not needed for the resolution of A. All references but A will be explored indirectly.
		// It could happen that to resolve C properly we need to resolve A first. Therefore when failing to resolve a
		// reference that is explored indirectly, we shouldn't assume that resolution will fail.
		pendingResolution_.remove(this);
		state_ = ReferenceEstablished;
	}
	else state_ = ReferenceNeedsToBeResolved;

	if (oldTarget != target_) targetChanged(oldTarget);

	return isResolved();
}

void Reference::targetChanged(Node*){}

void Reference::save(PersistentStore &store) const
{
	store.saveReferenceValue(name_, target_);
}

void Reference::load(PersistentStore &store)
{
	// TODO: Implement reference loading properly.
	throw ModelException("Loading references outside a Reference constructor is not properly implemented yet");

	if (store.currentNodeType() != typeName())
		throw ModelException("Trying to load a Reference node from an incompatible node type " + store.currentNodeType());

	setName( store.loadReferenceValue(this) );
}

Node* Reference::target()
{
	if (state_ == ReferenceNeedsToBeResolved) resolveHelper(true);
	return state_ == ReferenceEstablished ? target_ : nullptr;
}

void Reference::setResolutionNeeded()
{
	state_ = ReferenceNeedsToBeResolved;
	pendingResolution_.insert(this);
}

template<class NodeType>
void Reference::forAll(Node* subTree, std::function<void (NodeType*)> function)
{
	if (subTree)
	{
		QList<Node*> stack;
		stack << subTree;
		while (!stack.isEmpty())
		{
			auto top = stack.takeLast();

			if (auto node = DCast<NodeType>(top) ) function(node);
			else stack.append(top->children());
		}
	}
}

void Reference::unresolveReferencesHelper(Node* subTree, bool all,
	const QSet<QString>& names)
{
	if (!subTree || (!all && names.isEmpty())) return;

	auto targetManager = subTree->manager();
	bool isRoot = !subTree->parent();

	std::function<void (Reference*)> f;
	if (all)
	{
		f = [](Reference* ref) { ref->setResolutionNeeded();};
	}
	else
	{
		if (names.size() == 2)
		{
			//This case occurs when changing a name. This happens when the user is typing and therefore it is very
			//performance sensitive. Thus we optimize it specially.

			QString first = *names.begin();
			QString second = *++names.begin();

			// Removing this if, and just leaving the statement at the of this method to handle the updates using the
			// defined f function is slow. In one test an additional 4-5ms were needed on top of the 10-13ms processing
			// time on a 3.4GHz CPU. Therefore there is a significant cost associated with calling the f function, and
			// it's betterto just process this case here directly.
			// If needed this optimization could also be used in the other cases.
			if (isRoot)
			{
				for (auto ref : allReferences_)
					if (targetManager == ref->manager())
					{
						auto& refName = ref->name();
						if (refName == first || refName == second)
							ref->setResolutionNeeded();
					}
				return;
			}

			f = [=](Reference* ref)
				{ auto& refName = ref->name(); if (refName == first || refName == second) ref->setResolutionNeeded();};
		}
		else if (names.size() < 20) // Optimize in the case of just a few names, by avoiding hasing.
		{
			// TODO: Find out what's a good value for the magick number 20 above.
			QMap<QString, int> mapNames;
			for (auto n : names) mapNames.insert(n, 0); // TODO: isn't there a way to put void here?

			f = [=](Reference* ref) { if (mapNames.contains(ref->name())) ref->setResolutionNeeded();};
		}
		else
		{
			f = [=](Reference* ref) { if (names.contains(ref->name())) ref->setResolutionNeeded();};
		}
	}

	if (isRoot)
	{
		for (auto ref : allReferences_) if (targetManager == ref->manager()) f(ref);
	}
	else
	{
		// If this is not the root, then explore the references only in the specified subTree, which is faster
		forAll<Reference>(subTree, f);
	}

}

void Reference::unresolveAll(Node* subTree)
{
	unresolveReferencesHelper(subTree, true, {});
}

void Reference::unresolveNames(Node* subTree, const QSet<QString>& names)
{
	unresolveReferencesHelper(subTree, false, names);
}

void Reference::unresolveIfNameIntroduced(Node* subTreeToUnresolve,
		Node* subTreeToLookForNewNames)
{
	QSet<QString> names;
	forAll<NameText>(subTreeToLookForNewNames, [&names](NameText* name){ names.insert(name->get());});
	unresolveReferencesHelper(subTreeToUnresolve, false, names);
}

void Reference::unresolveAfterNewSubTree(Node* subTree)
{
	Reference::unresolveAll(subTree);
	Reference::unresolveIfNameIntroduced(subTree->root(), subTree);
	for (auto step : unresolutionSteps_) step(subTree);
}

void Reference::addUnresolutionSteps(std::function<void (Node* subTree)> step)
{
	unresolutionSteps_.append(step);
}

void Reference::resolvePending()
{
	log.debug("Resolving references");

	int i = 0;
	int round = 0;
	int resolved = 0;
	auto pending = pendingResolution_;

	while (!pending.isEmpty())
	{
		log.debug("resolution round " + QString::number(round) + ", "
					 + QString::number(pendingResolution_.size()) + " references pending.");
		++round;

		for (auto r : pending)
		{
			if ( r->resolve() ) ++resolved;
			if (++i % 10000 == 0)	log.debug("Processed " + QString::number(i) + " references.");
		}

		// As a result of resolution of some references, some other references could have become invalid.
		pending = pendingResolution_;
	}

	log.debug(QString::number(resolved) + " resolution" + (resolved == 1 ? "" : "s") + " in "
				 + QString::number(round) + (round > 1 ? " rounds." : " round."));

	int totalResolvedReferences = 0;
	for (auto r : allReferences_) if (r->isResolved()) ++totalResolvedReferences;
	log.debug("Total number of resolved references: " + QString::number(totalResolvedReferences));
}

}
<|endoftext|>


<commit_before>//===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Threading.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif

#include "gtest/gtest.h"

using namespace llvm;

namespace {

#ifdef HAVE_PTHREAD_H
namespace test1 {
  llvm::ManagedStatic<int> ms;
  void *helper(void*) {
    *ms;
    return NULL;
  }

  // Valgrind's leak checker complains glibc's stack allocation.
  // To appease valgrind, we provide our own stack for each thread.
  void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
    void *stack = malloc(n);
    pthread_attr_init(&a);
#if defined(__linux__)
    pthread_attr_setstack(&a, stack, n);
#endif
    return stack;
  }
}

TEST(Initialize, MultipleThreads) {
  // Run this test under tsan: http://code.google.com/p/data-race-test/

  pthread_attr_t a1, a2;
  void *p1 = test1::allocate_stack(a1);
  void *p2 = test1::allocate_stack(a2);

  llvm_start_multithreaded();
  pthread_t t1, t2;
  pthread_create(&t1, &a1, test1::helper, NULL);
  pthread_create(&t2, &a2, test1::helper, NULL);
  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  free(p1);
  free(p2);
  llvm_stop_multithreaded();
}
#endif

} // anonymous namespace
<commit_msg>Disable Initialize.MultipleThreads test under MemorySanitizer.<commit_after>//===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Threading.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif

#include "gtest/gtest.h"

using namespace llvm;

namespace {

#if defined(HAVE_PTHREAD_H) && !__has_feature(memory_sanitizer)
namespace test1 {
  llvm::ManagedStatic<int> ms;
  void *helper(void*) {
    *ms;
    return NULL;
  }

  // Valgrind's leak checker complains glibc's stack allocation.
  // To appease valgrind, we provide our own stack for each thread.
  void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
    void *stack = malloc(n);
    pthread_attr_init(&a);
#if defined(__linux__)
    pthread_attr_setstack(&a, stack, n);
#endif
    return stack;
  }
}

TEST(Initialize, MultipleThreads) {
  // Run this test under tsan: http://code.google.com/p/data-race-test/

  pthread_attr_t a1, a2;
  void *p1 = test1::allocate_stack(a1);
  void *p2 = test1::allocate_stack(a2);

  llvm_start_multithreaded();
  pthread_t t1, t2;
  pthread_create(&t1, &a1, test1::helper, NULL);
  pthread_create(&t2, &a2, test1::helper, NULL);
  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  free(p1);
  free(p2);
  llvm_stop_multithreaded();
}
#endif

} // anonymous namespace
<|endoftext|>