<commit_before>// bsls_outputredirector.cpp                                          -*-C++-*-
#include <bsls_outputredirector.h>

#include <bsls_ident.h>
BSLS_IDENT("$Id$ $CSID$")

#include <bsls_assert.h>
#include <bsls_bsltestutil.h>   // for testing only

#include <algorithm>

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

#include <sys/types.h> // 'struct stat': required on Sun and Windows only

#if defined(BSLS_PLATFORM_OS_WINDOWS)
# include <fcntl.h>     // '_O_BINARY'
# include <io.h>        // '_dup2', '_dup', '_close'
# define snprintf _snprintf
#else
# include <unistd.h>
# include <stdint.h>    // 'SIZE_MAX', cannot include on all Windows platforms
# include <stdlib.h>    // 'mkstemp'
#endif

#ifndef SIZE_MAX
#define SIZE_MAX (static_cast<size_t>(-1))
    // 'SIZE_MAX' is only defined as part of C99, so it may not exist in some
    // pre-C++11 compilers.
#endif

namespace BloombergLP {
namespace bsls {

// PRIVATE MANIPULATORS
void OutputRedirector::cleanup()
{
    disable();
    cleanupFiles();
}

void OutputRedirector::cleanupFiles()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    _close(d_duplicatedOriginalFd);
#else
    close(d_duplicatedOriginalFd);
#endif

    d_duplicatedOriginalFd = -1;

    if (d_isFileCreatedFlag) {
        unlink(d_fileName);
        d_isFileCreatedFlag = false;
    }
}

bool OutputRedirector::generateTempFileName()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    char tmpPathBuf[k_PATH_BUFFER_SIZE];
    if (! GetTempPathA(k_PATH_BUFFER_SIZE, tmpPathBuf) ||
        ! GetTempFileNameA(tmpPathBuf, "bsls", 0, d_fileName)) {
        return false;                                                 // RETURN
    }
#else
    static const char patternBuf[] = { "/tmp/bslsXXXXXX" };

    std::fill(d_fileName, d_fileName + sizeof(d_fileName), 0xa5);
    ::strncpy(d_fileName, patternBuf, sizeof(d_fileName));
    if ('\0' != d_fileName[sizeof(d_fileName) - 1]) {
        return false;                                                 // RETURN
    }
    if (0 != ::strcmp(d_fileName, patternBuf)) {
        return false;                                                 // RETURN
    }

    const int fd = ::mkstemp(d_fileName);
    if (fd < 0) {
        // 'mkstemp' failed.

        return false;                                                 // RETURN
    }
    int rc = ::close(fd);
    if (0 != rc) {
        return false;                                                 // RETURN
    }
    if ('\0' != d_fileName[sizeof(d_fileName) - 1]) {
        return false;                                                 // RETURN
    }
#endif
    if (d_veryVerbose) {
        fprintf(nonRedirectedStream(),
                "\tUsing '%s' as a base filename.\n",
                d_fileName);
    }
    return '\0' != d_fileName[0]; // Ensure that 'd_fileName' is not empty
}

// CREATORS
OutputRedirector::OutputRedirector(Stream which,
                                   bool   verbose,
                                   bool   veryVerbose)
: d_stream(which)
, d_isRedirectingFlag(false)
, d_isFileCreatedFlag(false)
, d_isOutputReadyFlag(false)
, d_outputSize(0)
, d_duplicatedOriginalFd(-1)
, d_verbose(verbose)
, d_veryVerbose(veryVerbose)
{
    BSLS_ASSERT(which == e_STDOUT_STREAM || which == e_STDERR_STREAM);

    d_fileName[0] = '\0';
    memset(&d_originalStat, 0, sizeof(struct stat));
}

OutputRedirector::~OutputRedirector()
{
    cleanup();
}

// MANIPULATORS
void OutputRedirector::disable()
{
    if (!d_isRedirectingFlag) {
        return;                                                       // RETURN
    }

    d_isRedirectingFlag = false;

    fflush(redirectedStream());

#ifdef BSLS_PLATFORM_OS_WINDOWS
    const int status = _dup2(d_duplicatedOriginalFd,
                             _fileno(redirectedStream()));
#else
    const int status = dup2(d_duplicatedOriginalFd,
                            fileno(redirectedStream()));
#endif

    if (status < 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Bad 'dup2' status.\n",
                    __LINE__);
        }
        cleanupFiles();
        abort();
    }
}

void OutputRedirector::enable()
{
    if (d_isRedirectingFlag) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Warning " __FILE__ "(%d): Output already redirected\n",
                    __LINE__);
        }

        return;                                                       // RETURN
    }

    // Retain information about original file descriptor for use in later
    // tests.

    const int originalFD = fileno(redirectedStream());

    BSLS_ASSERT(-1 != originalFD);
    BSLS_ASSERT(0 == fstat(originalFD, &d_originalStat));

    if (d_duplicatedOriginalFd == -1) {
#ifdef BSLS_PLATFORM_OS_WINDOWS
        d_duplicatedOriginalFd = _dup(originalFD);
#else
        d_duplicatedOriginalFd = dup(originalFD);
#endif
    }

    if (d_duplicatedOriginalFd < 0) {
        if (d_veryVerbose) {
                fprintf(nonRedirectedStream(),
                        "Error " __FILE__ "(%d): Bad 'dup' value.\n",
                        __LINE__);
            }
        cleanup();
        abort();
    }

    if (!d_isFileCreatedFlag) {
        if (!generateTempFileName()) {

            // Get temp file name

            if (d_veryVerbose) {
                fprintf(nonRedirectedStream(),
                        "Error "
                        __FILE__
                        "(%d): Failed to get temp file name for capture\n",
                        __LINE__);
            }
            cleanup();
            abort();
        }

        d_isFileCreatedFlag = true;
    }

    if (! freopen(d_fileName, "w+", redirectedStream())) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Failed to redirect stdout to"
                    " temp file '%s'\n",
                    __LINE__, d_fileName);
        }
        cleanup();
        abort();
    }

#ifdef BSLS_PLATFORM_OS_WINDOWS
    // In Windows, we need to convert the stream to binary mode because Windows
    // will automatically convert '\n' to '\r\n' in text mode output.  Normally
    // this would not be a problem, since the '\r\n' would be converted back to
    // '\n' when we read the file.  However, since we are using the size of the
    // written file to know how much to read, having extra characters will lead
    // to a faulty size reading.

    if (_setmode(_fileno(redirectedStream()), _O_BINARY) < 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Binary mode change failed.\n",
                    __LINE__);
        }
        cleanup();
        abort();
    }
#endif

    if (EOF == fflush(redirectedStream())) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Warning " __FILE__ "(%d): Error flushing stream\n",
                    __LINE__);
        }
    }

    d_isRedirectingFlag = true;
}

bool OutputRedirector::load()
{
    BSLS_ASSERT(d_isRedirectingFlag);

    if (ferror(redirectedStream()) != 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Stream has an error\n",
                    __LINE__);
        }
        return false;                                                 // RETURN
    }

    const long tempOutputSize = ftell(redirectedStream());
    const long incremented    = tempOutputSize + 1;

    if (tempOutputSize < 0 || incremented < 0) {
        // Protect against overflow or negative value

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Bad value from 'ftell': %ld",
                    incremented);
        }
        return false;                                                 // RETURN
    }

    // Conversion to 'unsigned long' is safe because 'incremented' > 0

    if (static_cast<unsigned long>(incremented) > SIZE_MAX) {
        // Our 'incremented' will not fit in a size_t, so it is too big for our
        // buffer.

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Bad value from 'ftell': %ld",
                    incremented);
        }
        return false;                                                 // RETURN
    }

    // Conversion to 'size_t' is safe because 'tempOutputSize' is nonnegative
    // and 'tempOutputSize'+1 is no larger than 'SIZE_MAX'.

    d_outputSize = static_cast<size_t>(tempOutputSize);

    if (static_cast<size_t>(incremented) > k_OUTPUT_REDIRECTOR_BUFFER_SIZE) {
        // Refuse to load output if it will not all fit in the scratch buffer,
        // INCLUDING the final null byte.

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error "
                        __FILE__
                        "(%d): Captured output exceeds read buffer size\n",
                    __LINE__);
        }
        d_outputSize = 0u;
        return false;                                                 // RETURN
    }

    rewind(redirectedStream());

    const long charsRead = fread(d_outputBuffer,
                                 sizeof(char),
                                 d_outputSize,
                                 redirectedStream());

    if (charsRead < 0 || static_cast<unsigned long>(charsRead)!=d_outputSize) {
        // We failed to read all output from the capture file.

        if (d_veryVerbose) {
            if (ferror(redirectedStream())) {
                // We encountered a file error, not 'EOF'.

                fprintf(nonRedirectedStream(),
                        "Error "
                            __FILE__
                            "(%d): Non-EOF error with file\n",
                        __LINE__);
            }
            fprintf(nonRedirectedStream(),
                    "Error "
                        __FILE__
                        "(%d): Could not read all captured output\n",
                    __LINE__);
        }

        if (charsRead < 0) {
            d_outputBuffer[0] = '\0';
        } else if (static_cast<unsigned long>(charsRead) >= d_outputSize) {
            // This case should never happen.  This assignment is safe because
            // the total buffer size is enough to hold 'd_outputSize' + 1.

            d_outputBuffer[d_outputSize] = '\0';
        } else {
            d_outputBuffer[charsRead] = '\0';
        }
            // ...to ensure that direct inspection of buffer does not overflow

        return false;                                                 // RETURN

    } else {
        // We have read all output from the capture file.

        d_outputBuffer[d_outputSize] = '\0';
    }

    d_isOutputReadyFlag = true;

    return true;
}

void OutputRedirector::clear()
{
    BSLS_ASSERT(d_isRedirectingFlag);

    d_outputSize = 0u;
    d_isOutputReadyFlag = false;
    d_outputBuffer[0] = '\0';
    rewind(redirectedStream());
}

// ACCESSORS
int OutputRedirector::compare(const char *expected) const
{
    BSLS_ASSERT(expected);

    return compare(expected, strlen(expected));
}

int
OutputRedirector::compare(const char *expected, size_t expectedLength) const
{
    BSLS_ASSERT(expected || ! expectedLength);

    if (!d_isOutputReadyFlag) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): No captured output available\n",
                    __LINE__);
        }
        return -1;                                                    // RETURN
    }

    // Use 'memcmp' instead of 'strncmp' to compare 'd_outputBuffer' to
    // 'expected', because 'expected' is allowed to contain embedded nulls.

    return static_cast<size_t>(d_outputSize) != expectedLength ||
           memcmp(d_outputBuffer, expected, expectedLength);
}

const char *OutputRedirector::getOutput() const
{
    return d_outputBuffer;
}

bool OutputRedirector::isOutputReady() const
{
    return d_isOutputReadyFlag;
}

bool OutputRedirector::isRedirecting() const
{
    return d_isRedirectingFlag;
}

FILE *OutputRedirector::nonRedirectedStream() const
{
    // This should return the opposite values

    if (d_stream == e_STDOUT_STREAM) {
        return stderr;                                                // RETURN
    } else {
        return stdout;                                                // RETURN
    }
}

const struct stat& OutputRedirector::originalStat() const
{
    return d_originalStat;
}

size_t OutputRedirector::outputSize() const
{
    return d_outputSize;
}

FILE *OutputRedirector::redirectedStream() const
{
    if (d_stream == e_STDOUT_STREAM) {
        return stdout;                                                // RETURN
    } else {
        return stderr;                                                // RETURN
    }
}

OutputRedirector::Stream OutputRedirector::redirectedStreamId() const
{
    return d_stream;
}

}  // close package namespace
}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>bsls_outputredirector: lengthen temp name pattern, doc change<commit_after>// bsls_outputredirector.cpp                                          -*-C++-*-
#include <bsls_outputredirector.h>

#include <bsls_ident.h>
BSLS_IDENT("$Id$ $CSID$")

#include <bsls_assert.h>
#include <bsls_bsltestutil.h>   // for testing only

#include <algorithm>

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

#include <sys/types.h> // 'struct stat': required on Sun and Windows only

#if defined(BSLS_PLATFORM_OS_WINDOWS)
# include <fcntl.h>     // '_O_BINARY'
# include <io.h>        // '_dup2', '_dup', '_close'
# define snprintf _snprintf
#else
# include <unistd.h>
# include <stdint.h>    // 'SIZE_MAX', cannot include on all Windows platforms
# include <stdlib.h>    // 'mkstemp'
#endif

#ifndef SIZE_MAX
#define SIZE_MAX (static_cast<size_t>(-1))
    // 'SIZE_MAX' is only defined as part of C99, so it may not exist in some
    // pre-C++11 compilers.
#endif

namespace BloombergLP {
namespace bsls {

// PRIVATE MANIPULATORS
void OutputRedirector::cleanup()
{
    disable();
    cleanupFiles();
}

void OutputRedirector::cleanupFiles()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    _close(d_duplicatedOriginalFd);
#else
    close(d_duplicatedOriginalFd);
#endif

    d_duplicatedOriginalFd = -1;

    if (d_isFileCreatedFlag) {
        unlink(d_fileName);
        d_isFileCreatedFlag = false;
    }
}

bool OutputRedirector::generateTempFileName()
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    char tmpPathBuf[k_PATH_BUFFER_SIZE];
    if (! GetTempPathA(k_PATH_BUFFER_SIZE, tmpPathBuf) ||
        ! GetTempFileNameA(tmpPathBuf, "bsls", 0, d_fileName)) {
        return false;                                                 // RETURN
    }
#else
    static const char patternBuf[] = { "/tmp/bsls_outputredirector_XXXXXX" };

    // Fill 'd_fileName' with garbage.

    std::fill(d_fileName, d_fileName + sizeof(d_fileName), 0xa5);

    // Copy in the pattern.

    ::strncpy(d_fileName, patternBuf, sizeof(d_fileName));
    if ('\0' != d_fileName[sizeof(d_fileName) - 1]) {
        return false;                                                 // RETURN
    }
    if (0 != ::strcmp(d_fileName, patternBuf)) {
        return false;                                                 // RETURN
    }

    const int fd = ::mkstemp(d_fileName);
    if (fd < 0) {
        // 'mkstemp' failed.

        return false;                                                 // RETURN
    }
    int rc = ::close(fd);
    if (0 != rc) {
        return false;                                                 // RETURN
    }
    if ('\0' != d_fileName[sizeof(d_fileName) - 1]) {
        return false;                                                 // RETURN
    }
#endif
    if (d_veryVerbose) {
        fprintf(nonRedirectedStream(),
                "\tUsing '%s' as a base filename.\n",
                d_fileName);
    }
    return '\0' != d_fileName[0]; // Ensure that 'd_fileName' is not empty
}

// CREATORS
OutputRedirector::OutputRedirector(Stream which,
                                   bool   verbose,
                                   bool   veryVerbose)
: d_stream(which)
, d_isRedirectingFlag(false)
, d_isFileCreatedFlag(false)
, d_isOutputReadyFlag(false)
, d_outputSize(0)
, d_duplicatedOriginalFd(-1)
, d_verbose(verbose)
, d_veryVerbose(veryVerbose)
{
    BSLS_ASSERT(which == e_STDOUT_STREAM || which == e_STDERR_STREAM);

    d_fileName[0] = '\0';
    memset(&d_originalStat, 0, sizeof(struct stat));
}

OutputRedirector::~OutputRedirector()
{
    cleanup();
}

// MANIPULATORS
void OutputRedirector::disable()
{
    if (!d_isRedirectingFlag) {
        return;                                                       // RETURN
    }

    d_isRedirectingFlag = false;

    fflush(redirectedStream());

#ifdef BSLS_PLATFORM_OS_WINDOWS
    const int status = _dup2(d_duplicatedOriginalFd,
                             _fileno(redirectedStream()));
#else
    const int status = dup2(d_duplicatedOriginalFd,
                            fileno(redirectedStream()));
#endif

    if (status < 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Bad 'dup2' status.\n",
                    __LINE__);
        }
        cleanupFiles();
        abort();
    }
}

void OutputRedirector::enable()
{
    if (d_isRedirectingFlag) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Warning " __FILE__ "(%d): Output already redirected\n",
                    __LINE__);
        }

        return;                                                       // RETURN
    }

    // Retain information about original file descriptor for use in later
    // tests.

    const int originalFD = fileno(redirectedStream());

    BSLS_ASSERT(-1 != originalFD);
    BSLS_ASSERT(0 == fstat(originalFD, &d_originalStat));

    if (d_duplicatedOriginalFd == -1) {
#ifdef BSLS_PLATFORM_OS_WINDOWS
        d_duplicatedOriginalFd = _dup(originalFD);
#else
        d_duplicatedOriginalFd = dup(originalFD);
#endif
    }

    if (d_duplicatedOriginalFd < 0) {
        if (d_veryVerbose) {
                fprintf(nonRedirectedStream(),
                        "Error " __FILE__ "(%d): Bad 'dup' value.\n",
                        __LINE__);
            }
        cleanup();
        abort();
    }

    if (!d_isFileCreatedFlag) {
        if (!generateTempFileName()) {

            // Get temp file name

            if (d_veryVerbose) {
                fprintf(nonRedirectedStream(),
                        "Error "
                        __FILE__
                        "(%d): Failed to get temp file name for capture\n",
                        __LINE__);
            }
            cleanup();
            abort();
        }

        d_isFileCreatedFlag = true;
    }

    if (! freopen(d_fileName, "w+", redirectedStream())) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Failed to redirect stdout to"
                    " temp file '%s'\n",
                    __LINE__, d_fileName);
        }
        cleanup();
        abort();
    }

#ifdef BSLS_PLATFORM_OS_WINDOWS
    // In Windows, we need to convert the stream to binary mode because Windows
    // will automatically convert '\n' to '\r\n' in text mode output.  Normally
    // this would not be a problem, since the '\r\n' would be converted back to
    // '\n' when we read the file.  However, since we are using the size of the
    // written file to know how much to read, having extra characters will lead
    // to a faulty size reading.

    if (_setmode(_fileno(redirectedStream()), _O_BINARY) < 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Binary mode change failed.\n",
                    __LINE__);
        }
        cleanup();
        abort();
    }
#endif

    if (EOF == fflush(redirectedStream())) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Warning " __FILE__ "(%d): Error flushing stream\n",
                    __LINE__);
        }
    }

    d_isRedirectingFlag = true;
}

bool OutputRedirector::load()
{
    BSLS_ASSERT(d_isRedirectingFlag);

    if (ferror(redirectedStream()) != 0) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): Stream has an error\n",
                    __LINE__);
        }
        return false;                                                 // RETURN
    }

    const long tempOutputSize = ftell(redirectedStream());
    const long incremented    = tempOutputSize + 1;

    if (tempOutputSize < 0 || incremented < 0) {
        // Protect against overflow or negative value

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Bad value from 'ftell': %ld",
                    incremented);
        }
        return false;                                                 // RETURN
    }

    // Conversion to 'unsigned long' is safe because 'incremented' > 0

    if (static_cast<unsigned long>(incremented) > SIZE_MAX) {
        // Our 'incremented' will not fit in a size_t, so it is too big for our
        // buffer.

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Bad value from 'ftell': %ld",
                    incremented);
        }
        return false;                                                 // RETURN
    }

    // Conversion to 'size_t' is safe because 'tempOutputSize' is nonnegative
    // and 'tempOutputSize'+1 is no larger than 'SIZE_MAX'.

    d_outputSize = static_cast<size_t>(tempOutputSize);

    if (static_cast<size_t>(incremented) > k_OUTPUT_REDIRECTOR_BUFFER_SIZE) {
        // Refuse to load output if it will not all fit in the scratch buffer,
        // INCLUDING the final null byte.

        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error "
                        __FILE__
                        "(%d): Captured output exceeds read buffer size\n",
                    __LINE__);
        }
        d_outputSize = 0u;
        return false;                                                 // RETURN
    }

    rewind(redirectedStream());

    const long charsRead = fread(d_outputBuffer,
                                 sizeof(char),
                                 d_outputSize,
                                 redirectedStream());

    if (charsRead < 0 || static_cast<unsigned long>(charsRead)!=d_outputSize) {
        // We failed to read all output from the capture file.

        if (d_veryVerbose) {
            if (ferror(redirectedStream())) {
                // We encountered a file error, not 'EOF'.

                fprintf(nonRedirectedStream(),
                        "Error "
                            __FILE__
                            "(%d): Non-EOF error with file\n",
                        __LINE__);
            }
            fprintf(nonRedirectedStream(),
                    "Error "
                        __FILE__
                        "(%d): Could not read all captured output\n",
                    __LINE__);
        }

        if (charsRead < 0) {
            d_outputBuffer[0] = '\0';
        } else if (static_cast<unsigned long>(charsRead) >= d_outputSize) {
            // This case should never happen.  This assignment is safe because
            // the total buffer size is enough to hold 'd_outputSize' + 1.

            d_outputBuffer[d_outputSize] = '\0';
        } else {
            d_outputBuffer[charsRead] = '\0';
        }
            // ...to ensure that direct inspection of buffer does not overflow

        return false;                                                 // RETURN

    } else {
        // We have read all output from the capture file.

        d_outputBuffer[d_outputSize] = '\0';
    }

    d_isOutputReadyFlag = true;

    return true;
}

void OutputRedirector::clear()
{
    BSLS_ASSERT(d_isRedirectingFlag);

    d_outputSize = 0u;
    d_isOutputReadyFlag = false;
    d_outputBuffer[0] = '\0';
    rewind(redirectedStream());
}

// ACCESSORS
int OutputRedirector::compare(const char *expected) const
{
    BSLS_ASSERT(expected);

    return compare(expected, strlen(expected));
}

int
OutputRedirector::compare(const char *expected, size_t expectedLength) const
{
    BSLS_ASSERT(expected || ! expectedLength);

    if (!d_isOutputReadyFlag) {
        if (d_veryVerbose) {
            fprintf(nonRedirectedStream(),
                    "Error " __FILE__ "(%d): No captured output available\n",
                    __LINE__);
        }
        return -1;                                                    // RETURN
    }

    // Use 'memcmp' instead of 'strncmp' to compare 'd_outputBuffer' to
    // 'expected', because 'expected' is allowed to contain embedded nulls.

    return static_cast<size_t>(d_outputSize) != expectedLength ||
           memcmp(d_outputBuffer, expected, expectedLength);
}

const char *OutputRedirector::getOutput() const
{
    return d_outputBuffer;
}

bool OutputRedirector::isOutputReady() const
{
    return d_isOutputReadyFlag;
}

bool OutputRedirector::isRedirecting() const
{
    return d_isRedirectingFlag;
}

FILE *OutputRedirector::nonRedirectedStream() const
{
    // This should return the opposite values

    if (d_stream == e_STDOUT_STREAM) {
        return stderr;                                                // RETURN
    } else {
        return stdout;                                                // RETURN
    }
}

const struct stat& OutputRedirector::originalStat() const
{
    return d_originalStat;
}

size_t OutputRedirector::outputSize() const
{
    return d_outputSize;
}

FILE *OutputRedirector::redirectedStream() const
{
    if (d_stream == e_STDOUT_STREAM) {
        return stdout;                                                // RETURN
    } else {
        return stderr;                                                // RETURN
    }
}

OutputRedirector::Stream OutputRedirector::redirectedStreamId() const
{
    return d_stream;
}

}  // close package namespace
}  // close enterprise namespace

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


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    FeatEdge.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <math.h>
#include "FeatEdge.hh"
#include "vlMath.hh"
#include "Polygon.hh"
#include "FNormals.hh"

// Description:
// Construct object with feature angle = 30; all types of edges extracted
// and colored.
vlFeatureEdges::vlFeatureEdges()
{
  this->FeatureAngle = 30.0;
  this->BoundaryEdges = 1;
  this->FeatureEdges = 1;
  this->NonManifoldEdges = 1;
  this->Coloring = 1;
}

// Generate feature edges for mesh
void vlFeatureEdges::Execute()
{
  vlFloatPoints *newPts;
  vlFloatScalars *newScalars;
  vlCellArray *newLines;
  vlPolyData Mesh;
  int i, j, numNei, cellId;
  int numBEdges, numNonManifoldEdges, numFedges;
  float scalar, n[3], *x1, *x2, cosAngle;
  vlMath math;
  vlPolygon poly;
  int lineIds[2];
  int npts, pts[MAX_CELL_SIZE];
  vlCellArray *inPolys;
  vlFloatNormals *polyNormals;
  int numPts, nei;
  vlIdList edge(2), neighbors(MAX_CELL_SIZE);

  vlDebugMacro(<<"Executing feature edges");
  this->Initialize();
//
//  Check input
//
  if ( (numPts=this->Input->GetNumberOfPoints()) )
    {
    vlErrorMacro(<<"No input data!");
    return;
    }

  // build cell structure.  Only operate with polygons.
  Mesh.SetPoints(this->Input->GetPoints());
  Mesh.SetPolys(this->Input->GetPolys());
//
//  Allocate storage for lines/points
//
  newPts = new vlFloatPoints(numPts/10,numPts); // arbitrary allocations size
  newScalars = new vlFloatScalars(numPts/10,numPts);
  newLines = new vlCellArray(numPts/10);
//
//  Loop over all polygons generating boundary, non-manifold, and feature edges
//
  if (this->BoundaryEdges || this->NonManifoldEdges || this->FeatureEdges)
    {
    if ( this->FeatureEdges )
      {
      polyNormals = new vlFloatNormals(inPolys->GetNumberOfCells());

      for (cellId=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts);
      cellId++)
        {
        poly.ComputeNormal(this->Input->GetPoints(),npts,pts,n);
        polyNormals->InsertNormal(cellId,n);
        }

      cosAngle = cos ((double) math.DegreesToRadians() * this->FeatureAngle);
      }

    numBEdges = numNonManifoldEdges = numFedges = 0;
    for (cellId=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts);
    cellId++)
      {
      for (i=0; i < npts; i++)
        {
        edge.SetId(0,pts[i]);
        edge.SetId(1,pts[(i+1)%npts]);
        Mesh.GetCellNeighbors(cellId,edge,neighbors);

        if ( (numNei=neighbors.GetNumberOfIds()) < 1 && this->BoundaryEdges )
          {
          numBEdges++;
          scalar = 0.0;
          }
        else if ( numNei > 1 && this->NonManifoldEdges )
          {
          // check to make sure that this edge hasn't been created before
          for (j=0; j < numNei; j++)
            if ( neighbors.GetId(j) < cellId )
              break;
          if ( j >= numNei )
            {
            numNonManifoldEdges++;
            scalar = 0.33333;
            }
          }
        else if ( numNei == 1 && (nei=neighbors.GetId(0)) > cellId )
          {
          if ( math.Dot(polyNormals->GetNormal(nei),polyNormals->GetNormal(cellId)) <= cosAngle )
            {
            numFedges++;
            scalar = 0.66667;
            }
          else
            {
            continue;
            }
          }

        x1 = Mesh.GetPoint(edge.GetId(0));
        x2 = Mesh.GetPoint(edge.GetId(1));

        lineIds[0] = newPts->InsertNextPoint(x1);
        lineIds[1] = newPts->InsertNextPoint(x2);

        newLines->InsertNextCell(2,lineIds);

        newScalars->InsertScalar(lineIds[0], scalar);
        newScalars->InsertScalar(lineIds[1], scalar);
        }
      }
    vlDebugMacro(<<"Created " << numBEdges << " boundary edges, " <<
                 numNonManifoldEdges << " non-manifold edges, " <<
                 numFedges << " feature edges");
    if ( this->FeatureEdges ) delete polyNormals;
    }
//
//  Update ourselves.
//
  this->SetPoints(newPts);
  this->SetLines(newLines);
  if ( this->Coloring )
    this->PointData.SetScalars(newScalars);
  else
    delete newScalars;
}

void vlFeatureEdges::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlFeatureEdges::GetClassName()))
    {
    vlPolyToPolyFilter::PrintSelf(os,indent);

    os << indent << "Feature Angle: " << this->FeatureAngle << "\n";
    os << indent << "BoundaryEdges: " << (this->BoundaryEdges ? "On\n" : "Off\n");
    os << indent << "FeatureEdges: " << (this->FeatureEdges ? "On\n" : "Off\n");
    os << indent << "Non-Manifold Edges: " << (this->NonManifoldEdges ? "On\n" : "Off\n");
    os << indent << "Coloring: " << (this->Coloring ? "On\n" : "Off\n");
   }
}

<commit_msg>*** empty log message ***<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    FeatEdge.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file
or its contents may be copied, reproduced or altered in any way
without the express written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include "FeatEdge.hh"
#include "vlMath.hh"
#include "Polygon.hh"
#include "FNormals.hh"

// Description:
// Construct object with feature angle = 30; all types of edges extracted
// and colored.
vlFeatureEdges::vlFeatureEdges()
{
  this->FeatureAngle = 30.0;
  this->BoundaryEdges = 1;
  this->FeatureEdges = 1;
  this->NonManifoldEdges = 1;
  this->Coloring = 1;
}

// Generate feature edges for mesh
void vlFeatureEdges::Execute()
{
  vlFloatPoints *newPts;
  vlFloatScalars *newScalars;
  vlCellArray *newLines;
  vlPolyData Mesh;
  int i, j, numNei, cellId;
  int numBEdges, numNonManifoldEdges, numFedges;
  float scalar, n[3], *x1, *x2, cosAngle;
  vlMath math;
  vlPolygon poly;
  int lineIds[2];
  int npts, *pts;
  vlCellArray *inPolys;
  vlFloatNormals *polyNormals;
  int numPts, nei;
  vlIdList neighbors(MAX_CELL_SIZE);
  int p1, p2;

  vlDebugMacro(<<"Executing feature edges");
  this->Initialize();
//
//  Check input
//
  if ( (numPts=this->Input->GetNumberOfPoints()) )
    {
    vlErrorMacro(<<"No input data!");
    return;
    }

  // build cell structure.  Only operate with polygons.
  Mesh.SetPoints(this->Input->GetPoints());
  inPolys = this->Input->GetPolys();
  Mesh.SetPolys(inPolys);
  Mesh.BuildLinks();
//
//  Allocate storage for lines/points
//
  newPts = new vlFloatPoints(numPts/10,numPts); // arbitrary allocations size
  newScalars = new vlFloatScalars(numPts/10,numPts);
  newLines = new vlCellArray(numPts/10);
//
//  Loop over all polygons generating boundary, non-manifold, and feature edges
//
  if (this->BoundaryEdges || this->NonManifoldEdges || this->FeatureEdges)
    {
    if ( this->FeatureEdges )
      {
      polyNormals = new vlFloatNormals(inPolys->GetNumberOfCells());

      for (cellId=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts);
      cellId++)
        {
        poly.ComputeNormal(this->Input->GetPoints(),npts,pts,n);
        polyNormals->InsertNormal(cellId,n);
        }

      cosAngle = cos ((double) math.DegreesToRadians() * this->FeatureAngle);
      }

    numBEdges = numNonManifoldEdges = numFedges = 0;
    for (cellId=0, inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts);
    cellId++)
      {
      for (i=0; i < npts; i++)
        {
        p1 = pts[i];
        p2 = pts[(i+1)%npts];
        Mesh.GetCellEdgeNeighbors(cellId,p1,p2,neighbors);

        if ( (numNei=neighbors.GetNumberOfIds()) < 1 && this->BoundaryEdges )
          {
          numBEdges++;
          scalar = 0.0;
          }
        else if ( numNei > 1 && this->NonManifoldEdges )
          {
          // check to make sure that this edge hasn't been created before
          for (j=0; j < numNei; j++)
            if ( neighbors.GetId(j) < cellId )
              break;
          if ( j >= numNei )
            {
            numNonManifoldEdges++;
            scalar = 0.33333;
            }
          }
        else if ( numNei == 1 && (nei=neighbors.GetId(0)) > cellId )
          {
          if ( math.Dot(polyNormals->GetNormal(nei),polyNormals->GetNormal(cellId)) <= cosAngle )
            {
            numFedges++;
            scalar = 0.66667;
            }
          else
            {
            continue;
            }
          }

        x1 = Mesh.GetPoint(p1);
        x2 = Mesh.GetPoint(p2);

        lineIds[0] = newPts->InsertNextPoint(x1);
        lineIds[1] = newPts->InsertNextPoint(x2);

        newLines->InsertNextCell(2,lineIds);

        newScalars->InsertScalar(lineIds[0], scalar);
        newScalars->InsertScalar(lineIds[1], scalar);
        }
      }
    vlDebugMacro(<<"Created " << numBEdges << " boundary edges, " <<
                 numNonManifoldEdges << " non-manifold edges, " <<
                 numFedges << " feature edges");
    if ( this->FeatureEdges ) delete polyNormals;
    }
//
//  Update ourselves.
//
  this->SetPoints(newPts);
  this->SetLines(newLines);
  if ( this->Coloring )
    this->PointData.SetScalars(newScalars);
  else
    delete newScalars;
}

void vlFeatureEdges::PrintSelf(ostream& os, vlIndent indent)
{
  if (this->ShouldIPrint(vlFeatureEdges::GetClassName()))
    {
    vlPolyToPolyFilter::PrintSelf(os,indent);

    os << indent << "Feature Angle: " << this->FeatureAngle << "\n";
    os << indent << "BoundaryEdges: " << (this->BoundaryEdges ? "On\n" : "Off\n");
    os << indent << "FeatureEdges: " << (this->FeatureEdges ? "On\n" : "Off\n");
    os << indent << "Non-Manifold Edges: " << (this->NonManifoldEdges ? "On\n" : "Off\n");
    os << indent << "Coloring: " << (this->Coloring ? "On\n" : "Off\n");
   }
}

<|endoftext|>


<commit_before>#ifndef GUI_HPP
#define GUI_HPP
#include <wx/toplevel.h>
#include "MainFrame.hpp"
#include "Notifier.hpp"
#include <string>
#include <vector>
#include <array>
#include <stack>
#include <mutex>

#include "Preset.hpp"

namespace Slic3r { namespace GUI {

class App: public wxApp
{
public:
    virtual bool OnInit() override;
    App() : wxApp() {}

    /// Save position, size, and maximize state for a TopLevelWindow (includes Frames) by name in Settings.
    void save_window_pos(const wxTopLevelWindow* window, const wxString& name );

    /// Move/resize a named TopLevelWindow (includes Frames) from Settings
    void restore_window_pos(wxTopLevelWindow* window, const wxString& name );

    /// Function to add callback functions to the idle loop stack.
    void CallAfter(std::function<void()> cb_function);

    void OnUnhandledException() override;

    std::vector<Presets> presets { preset_types, Presets() };
    std::array<wxString, preset_types> preset_ini { };
private:
    std::unique_ptr<Notifier> notifier {nullptr};

    void load_presets();

    wxString datadir {""};
    const std::string LogChannel {"APP"}; //< Which log these messages should go to.

    /// Lock to guard the callback stack
    std::mutex callback_register;

    /// callbacks registered to run during idle event.
    std::stack<std::function<void()> > cb {};
};

/// Quick reference to this app with its cast applied.
#define SLIC3RAPP (dynamic_cast<App*>(wxTheApp))

}} // namespace Slic3r::GUI
#endif // GUI_HPP
<commit_msg>Moved the basic preset store back to an array of vectors.<commit_after>#ifndef GUI_HPP
#define GUI_HPP
#include <wx/toplevel.h>
#include "MainFrame.hpp"
#include "Notifier.hpp"
#include <string>
#include <vector>
#include <array>
#include <stack>
#include <mutex>

#include "Preset.hpp"

namespace Slic3r { namespace GUI {

class App: public wxApp
{
public:
    virtual bool OnInit() override;
    App() : wxApp() {}

    /// Save position, size, and maximize state for a TopLevelWindow (includes Frames) by name in Settings.
    void save_window_pos(const wxTopLevelWindow* window, const wxString& name );

    /// Move/resize a named TopLevelWindow (includes Frames) from Settings
    void restore_window_pos(wxTopLevelWindow* window, const wxString& name );

    /// Function to add callback functions to the idle loop stack.
    void CallAfter(std::function<void()> cb_function);

    void OnUnhandledException() override;

    std::array<Presets, preset_types> presets { Presets() };
    std::array<wxString, preset_types> preset_ini { };
private:
    std::unique_ptr<Notifier> notifier {nullptr};

    void load_presets();

    wxString datadir {""};
    const std::string LogChannel {"APP"}; //< Which log these messages should go to.

    /// Lock to guard the callback stack
    std::mutex callback_register;

    /// callbacks registered to run during idle event.
    std::stack<std::function<void()> > cb {};
};

/// Quick reference to this app with its cast applied.
#define SLIC3RAPP (dynamic_cast<App*>(wxTheApp))

}} // namespace Slic3r::GUI
#endif // GUI_HPP
<|endoftext|>


<commit_before>// Gripper.cpp

#include "stdafx.h"
#include "Gripper.h"
#include "../interface/HeeksColor.h"

static unsigned char circle[18] = {0x1c, 0x00, 0x63, 0x00, 0x41, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x00, 0x63, 0x00, 0x1c, 0x00};
static unsigned char translation_circle[30] = {0x00, 0x80, 0x01, 0xc0, 0x00, 0x80, 0x01, 0xc0, 0x06, 0x30, 0x04, 0x10, 0x28, 0x0a, 0x78, 0x0f, 0x28, 0x0a, 0x04, 0x10, 0x06, 0x30, 0x01, 0xc0, 0x00, 0x80, 0x01, 0xc0, 0x00, 0x80};
static unsigned char rotation_circle[26] = {0x01, 0xc0, 0x06, 0x30, 0x04, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, 0x06, 0x31, 0x61, 0xc2, 0x60, 0x02, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char rotation_object_circle[26] = {0x01, 0xc0, 0x06, 0xb0, 0x04, 0x90, 0x08, 0x88, 0x0f, 0xf8, 0x08, 0x88, 0x04, 0x90, 0x06, 0xb1, 0x61, 0xc2, 0x60, 0x02, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char scale_circle[30] = {0x03, 0xe0, 0x0c, 0x18, 0x10, 0x04, 0x21, 0xc2, 0x26, 0x32, 0x44, 0x11, 0x48, 0x09, 0x48, 0x09, 0x48, 0x09, 0x44, 0x11, 0x26, 0x32, 0x21, 0xc2, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char angle_circle[32] = {0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, 0x04, 0x10, 0x02, 0x40, 0x03, 0xe0, 0x07, 0x70, 0x05, 0x50, 0x08, 0x88, 0x08, 0x88, 0x08, 0x08, 0x04, 0x10, 0x06, 0x30, 0x01, 0xc0};

Gripper::Gripper(const gp_Pnt& pos, const wxChar* str, EnumGripperType gripper_type){
	position = pos;
	prompt = wxString(str);
	m_gripper_type = gripper_type;
}

void Gripper::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(HeeksColor(0, 0, 0));
	}
	glRasterPos3d(position.X(), position.Y(), position.Z());
	switch(m_gripper_type){
		case GripperTypeTranslate:
			glBitmap(16, 15, 8, 7, 10.0, 0.0, translation_circle);
			break;
		case GripperTypeRotateObject:
			glBitmap(16, 13, 8, 4, 10.0, 0.0, rotation_object_circle);
			break;
		case GripperTypeRotate:
			glBitmap(16, 13, 8, 4, 10.0, 0.0, rotation_circle);
			break;
		case GripperTypeScale:
			glBitmap(16, 15, 8, 7, 10.0, 0.0, scale_circle);
			break;
		case GripperTypeAngle:
			glBitmap(14, 16, 9, 11, 10.0, 0.0, angle_circle);
			break;
		case GripperTypeStretch:
			glBitmap(9, 9, 4, 4, 10.0, 0.0, circle);
			break;
		default:
			glBitmap(9, 9, 4, 4, 10.0, 0.0, circle);
			break;
	}
}

bool Gripper::ModifyByMatrix(const double *m){
	gp_Trsf mat = make_matrix(m);
	position.Transform(mat);
	return false;
}
<commit_msg>Fixed Issue 58:  	 Grippers hard to pick I draw the grippers with a little cube for select mode.<commit_after>// Gripper.cpp

#include "stdafx.h"
#include "Gripper.h"
#include "../interface/HeeksColor.h"

static unsigned char circle[18] = {0x1c, 0x00, 0x63, 0x00, 0x41, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x00, 0x63, 0x00, 0x1c, 0x00};
static unsigned char translation_circle[30] = {0x00, 0x80, 0x01, 0xc0, 0x00, 0x80, 0x01, 0xc0, 0x06, 0x30, 0x04, 0x10, 0x28, 0x0a, 0x78, 0x0f, 0x28, 0x0a, 0x04, 0x10, 0x06, 0x30, 0x01, 0xc0, 0x00, 0x80, 0x01, 0xc0, 0x00, 0x80};
static unsigned char rotation_circle[26] = {0x01, 0xc0, 0x06, 0x30, 0x04, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, 0x06, 0x31, 0x61, 0xc2, 0x60, 0x02, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char rotation_object_circle[26] = {0x01, 0xc0, 0x06, 0xb0, 0x04, 0x90, 0x08, 0x88, 0x0f, 0xf8, 0x08, 0x88, 0x04, 0x90, 0x06, 0xb1, 0x61, 0xc2, 0x60, 0x02, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char scale_circle[30] = {0x03, 0xe0, 0x0c, 0x18, 0x10, 0x04, 0x21, 0xc2, 0x26, 0x32, 0x44, 0x11, 0x48, 0x09, 0x48, 0x09, 0x48, 0x09, 0x44, 0x11, 0x26, 0x32, 0x21, 0xc2, 0x10, 0x04, 0x0c, 0x18, 0x03, 0xe0};
static unsigned char angle_circle[32] = {0x10, 0x04, 0x10, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, 0x04, 0x10, 0x02, 0x40, 0x03, 0xe0, 0x07, 0x70, 0x05, 0x50, 0x08, 0x88, 0x08, 0x88, 0x08, 0x08, 0x04, 0x10, 0x06, 0x30, 0x01, 0xc0};

Gripper::Gripper(const gp_Pnt& pos, const wxChar* str, EnumGripperType gripper_type){
	position = pos;
	prompt = wxString(str);
	m_gripper_type = gripper_type;
}

void Gripper::glCommands(bool select, bool marked, bool no_color){
	if(!no_color){
		wxGetApp().glColorEnsuringContrast(HeeksColor(0, 0, 0));
	}
	if(select)
	{
		double s = 5.0 / wxGetApp().GetPixelScale();
		double p[8][3] = {
			-s, -s, -s,
			s, -s, -s,
			s, s, -s,
			-s, s, -s,
			-s, -s, s,
			s, -s, s,
			s, s, s,
			-s, s, s
		};

		for(int i = 0; i<8; i++){
			p[i][0] += position.X();
			p[i][1] += position.Y();
			p[i][2] += position.Z();
		}

		glBegin(GL_TRIANGLES);
		glVertex3dv(p[0]);
		glVertex3dv(p[2]);
		glVertex3dv(p[1]);
		glVertex3dv(p[0]);
		glVertex3dv(p[3]);
		glVertex3dv(p[2]);

		glVertex3dv(p[0]);
		glVertex3dv(p[1]);
		glVertex3dv(p[5]);
		glVertex3dv(p[0]);
		glVertex3dv(p[5]);
		glVertex3dv(p[4]);

		glVertex3dv(p[3]);
		glVertex3dv(p[0]);
		glVertex3dv(p[4]);
		glVertex3dv(p[3]);
		glVertex3dv(p[4]);
		glVertex3dv(p[7]);

		glVertex3dv(p[4]);
		glVertex3dv(p[5]);
		glVertex3dv(p[6]);
		glVertex3dv(p[4]);
		glVertex3dv(p[6]);
		glVertex3dv(p[7]);

		glVertex3dv(p[3]);
		glVertex3dv(p[7]);
		glVertex3dv(p[6]);
		glVertex3dv(p[3]);
		glVertex3dv(p[6]);
		glVertex3dv(p[2]);

		glVertex3dv(p[2]);
		glVertex3dv(p[6]);
		glVertex3dv(p[5]);
		glVertex3dv(p[2]);
		glVertex3dv(p[5]);
		glVertex3dv(p[1]);

		glEnd();
	}
	else
	{
		glRasterPos3d(position.X(), position.Y(), position.Z());
		switch(m_gripper_type){
		case GripperTypeTranslate:
			glBitmap(16, 15, 8, 7, 10.0, 0.0, translation_circle);
			break;
		case GripperTypeRotateObject:
			glBitmap(16, 13, 8, 4, 10.0, 0.0, rotation_object_circle);
			break;
		case GripperTypeRotate:
			glBitmap(16, 13, 8, 4, 10.0, 0.0, rotation_circle);
			break;
		case GripperTypeScale:
			glBitmap(16, 15, 8, 7, 10.0, 0.0, scale_circle);
			break;
		case GripperTypeAngle:
			glBitmap(14, 16, 9, 11, 10.0, 0.0, angle_circle);
			break;
		case GripperTypeStretch:
			glBitmap(9, 9, 4, 4, 10.0, 0.0, circle);
			break;
		default:
			glBitmap(9, 9, 4, 4, 10.0, 0.0, circle);
			break;
		}
	}
}

bool Gripper::ModifyByMatrix(const double *m){
	gp_Trsf mat = make_matrix(m);
	position.Transform(mat);
	return false;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <index/base.h>
#include <node/blockstorage.h>
#include <node/ui_interface.h>
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
#include <warnings.h>

using node::ReadBlockFromDisk;

constexpr uint8_t DB_BEST_BLOCK{'B'};

constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds

template <typename... Args>
static void FatalError(const char* fmt, const Args&... args)
{
    std::string strMessage = tfm::format(fmt, args...);
    SetMiscWarning(Untranslated(strMessage));
    LogPrintf("*** %s\n", strMessage);
    AbortError(_("A fatal internal error occurred, see debug.log for details"));
    StartShutdown();
}

BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
    CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
{}

bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
{
    bool success = Read(DB_BEST_BLOCK, locator);
    if (!success) {
        locator.SetNull();
    }
    return success;
}

void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator)
{
    batch.Write(DB_BEST_BLOCK, locator);
}

BaseIndex::~BaseIndex()
{
    Interrupt();
    Stop();
}

bool BaseIndex::Init()
{
    CBlockLocator locator;
    if (!GetDB().ReadBestBlock(locator)) {
        locator.SetNull();
    }

    LOCK(cs_main);
    CChain& active_chain = m_chainstate->m_chain;
    if (locator.IsNull()) {
        SetBestBlockIndex(nullptr);
    } else {
        SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
    }
    m_synced = m_best_block_index.load() == active_chain.Tip();
    if (!m_synced) {
        bool prune_violation = false;
        if (!m_best_block_index) {
            // index is not built yet
            // make sure we have all block data back to the genesis
            prune_violation = m_chainstate->m_blockman.GetFirstStoredBlock(*active_chain.Tip()) != active_chain.Genesis();
        }
        // in case the index has a best block set and is not fully synced
        // check if we have the required blocks to continue building the index
        else {
            const CBlockIndex* block_to_test = m_best_block_index.load();
            if (!active_chain.Contains(block_to_test)) {
                // if the bestblock is not part of the mainchain, find the fork
                // and make sure we have all data down to the fork
                block_to_test = active_chain.FindFork(block_to_test);
            }
            const CBlockIndex* block = active_chain.Tip();
            prune_violation = true;
            // check backwards from the tip if we have all block data until we reach the indexes bestblock
            while (block_to_test && block && (block->nStatus & BLOCK_HAVE_DATA)) {
                if (block_to_test == block) {
                    prune_violation = false;
                    break;
                }
                // block->pprev must exist at this point, since block_to_test is part of the chain
                // and thus must be encountered when going backwards from the tip
                assert(block->pprev);
                block = block->pprev;
            }
        }
        if (prune_violation) {
            return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
        }
    }
    return true;
}

static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
    AssertLockHeld(cs_main);

    if (!pindex_prev) {
        return chain.Genesis();
    }

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex) {
        return pindex;
    }

    return chain.Next(chain.FindFork(pindex_prev));
}

void BaseIndex::ThreadSync()
{
    SetSyscallSandboxPolicy(SyscallSandboxPolicy::TX_INDEX);
    const CBlockIndex* pindex = m_best_block_index.load();
    if (!m_synced) {
        auto& consensus_params = Params().GetConsensus();

        int64_t last_log_time = 0;
        int64_t last_locator_write_time = 0;
        while (true) {
            if (m_interrupt) {
                SetBestBlockIndex(pindex);
                // No need to handle errors in Commit. If it fails, the error will be already be
                // logged. The best way to recover is to continue, as index cannot be corrupted by
                // a missed commit to disk for an advanced index state.
                Commit();
                return;
            }

            {
                LOCK(cs_main);
                const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain);
                if (!pindex_next) {
                    SetBestBlockIndex(pindex);
                    m_synced = true;
                    // No need to handle errors in Commit. See rationale above.
                    Commit();
                    break;
                }
                if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) {
                    FatalError("%s: Failed to rewind index %s to a previous chain tip",
                               __func__, GetName());
                    return;
                }
                pindex = pindex_next;
            }

            int64_t current_time = GetTime();
            if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
                LogPrintf("Syncing %s with block chain from height %d\n",
                          GetName(), pindex->nHeight);
                last_log_time = current_time;
            }

            if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
                SetBestBlockIndex(pindex);
                last_locator_write_time = current_time;
                // No need to handle errors in Commit. See rationale above.
                Commit();
            }

            CBlock block;
            if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
                FatalError("%s: Failed to read block %s from disk",
                           __func__, pindex->GetBlockHash().ToString());
                return;
            }
            if (!WriteBlock(block, pindex)) {
                FatalError("%s: Failed to write block %s to index database",
                           __func__, pindex->GetBlockHash().ToString());
                return;
            }
        }
    }

    if (pindex) {
        LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
    } else {
        LogPrintf("%s is enabled\n", GetName());
    }
}

bool BaseIndex::Commit()
{
    CDBBatch batch(GetDB());
    if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
        return error("%s: Failed to commit latest %s state", __func__, GetName());
    }
    return true;
}

bool BaseIndex::CommitInternal(CDBBatch& batch)
{
    LOCK(cs_main);
    // Don't commit anything if we haven't indexed any block yet
    // (this could happen if init is interrupted).
    if (m_best_block_index == nullptr) {
        return false;
    }
    GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
    return true;
}

bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
{
    assert(current_tip == m_best_block_index);
    assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);

    // In the case of a reorg, ensure persisted block locator is not stale.
    // Pruning has a minimum of 288 blocks-to-keep and getting the index
    // out of sync may be possible but a users fault.
    // In case we reorg beyond the pruned depth, ReadBlockFromDisk would
    // throw and lead to a graceful shutdown
    SetBestBlockIndex(new_tip);
    if (!Commit()) {
        // If commit fails, revert the best block index to avoid corruption.
        SetBestBlockIndex(current_tip);
        return false;
    }

    return true;
}

void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
{
    if (!m_synced) {
        return;
    }

    const CBlockIndex* best_block_index = m_best_block_index.load();
    if (!best_block_index) {
        if (pindex->nHeight != 0) {
            FatalError("%s: First block connected is not the genesis block (height=%d)",
                       __func__, pindex->nHeight);
            return;
        }
    } else {
        // Ensure block connects to an ancestor of the current best block. This should be the case
        // most of the time, but may not be immediately after the sync thread catches up and sets
        // m_synced. Consider the case where there is a reorg and the blocks on the stale branch are
        // in the ValidationInterface queue backlog even after the sync thread has caught up to the
        // new chain tip. In this unlikely event, log a warning and let the queue clear.
        if (best_block_index->GetAncestor(pindex->nHeight - 1) != pindex->pprev) {
            LogPrintf("%s: WARNING: Block %s does not connect to an ancestor of " /* Continued */
                      "known best chain (tip=%s); not updating index\n",
                      __func__, pindex->GetBlockHash().ToString(),
                      best_block_index->GetBlockHash().ToString());
            return;
        }
        if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) {
            FatalError("%s: Failed to rewind index %s to a previous chain tip",
                       __func__, GetName());
            return;
        }
    }

    if (WriteBlock(*block, pindex)) {
        SetBestBlockIndex(pindex);
    } else {
        FatalError("%s: Failed to write block %s to index",
                   __func__, pindex->GetBlockHash().ToString());
        return;
    }
}

void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
{
    if (!m_synced) {
        return;
    }

    const uint256& locator_tip_hash = locator.vHave.front();
    const CBlockIndex* locator_tip_index;
    {
        LOCK(cs_main);
        locator_tip_index = m_chainstate->m_blockman.LookupBlockIndex(locator_tip_hash);
    }

    if (!locator_tip_index) {
        FatalError("%s: First block (hash=%s) in locator was not found",
                   __func__, locator_tip_hash.ToString());
        return;
    }

    // This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
    // immediately after the sync thread catches up and sets m_synced. Consider the case where
    // there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
    // backlog even after the sync thread has caught up to the new chain tip. In this unlikely
    // event, log a warning and let the queue clear.
    const CBlockIndex* best_block_index = m_best_block_index.load();
    if (best_block_index->GetAncestor(locator_tip_index->nHeight) != locator_tip_index) {
        LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known best " /* Continued */
                  "chain (tip=%s); not writing index locator\n",
                  __func__, locator_tip_hash.ToString(),
                  best_block_index->GetBlockHash().ToString());
        return;
    }

    // No need to handle errors in Commit. If it fails, the error will be already be logged. The
    // best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
    // for an advanced index state.
    Commit();
}

bool BaseIndex::BlockUntilSyncedToCurrentChain() const
{
    AssertLockNotHeld(cs_main);

    if (!m_synced) {
        return false;
    }

    {
        // Skip the queue-draining stuff if we know we're caught up with
        // m_chain.Tip().
        LOCK(cs_main);
        const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
        const CBlockIndex* best_block_index = m_best_block_index.load();
        if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
            return true;
        }
    }

    LogPrintf("%s: %s is catching up on block notifications\n", __func__, GetName());
    SyncWithValidationInterfaceQueue();
    return true;
}

void BaseIndex::Interrupt()
{
    m_interrupt();
}

bool BaseIndex::Start(CChainState& active_chainstate)
{
    m_chainstate = &active_chainstate;
    // Need to register this ValidationInterface before running Init(), so that
    // callbacks are not missed if Init sets m_synced to true.
    RegisterValidationInterface(this);
    if (!Init()) {
        return false;
    }

    m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
    return true;
}

void BaseIndex::Stop()
{
    UnregisterValidationInterface(this);

    if (m_thread_sync.joinable()) {
        m_thread_sync.join();
    }
}

IndexSummary BaseIndex::GetSummary() const
{
    IndexSummary summary{};
    summary.name = GetName();
    summary.synced = m_synced;
    summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0;
    return summary;
}

void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
    assert(!node::fPruneMode || AllowPrune());

    m_best_block_index = block;
    if (AllowPrune() && block) {
        node::PruneLockInfo prune_lock;
        prune_lock.height_first = block->nHeight;
        WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
    }
}
<commit_msg>index: Don't commit a best block before indexing it during sync<commit_after>// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <index/base.h>
#include <node/blockstorage.h>
#include <node/ui_interface.h>
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
#include <warnings.h>

using node::ReadBlockFromDisk;

constexpr uint8_t DB_BEST_BLOCK{'B'};

constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds

template <typename... Args>
static void FatalError(const char* fmt, const Args&... args)
{
    std::string strMessage = tfm::format(fmt, args...);
    SetMiscWarning(Untranslated(strMessage));
    LogPrintf("*** %s\n", strMessage);
    AbortError(_("A fatal internal error occurred, see debug.log for details"));
    StartShutdown();
}

BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
    CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
{}

bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
{
    bool success = Read(DB_BEST_BLOCK, locator);
    if (!success) {
        locator.SetNull();
    }
    return success;
}

void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator)
{
    batch.Write(DB_BEST_BLOCK, locator);
}

BaseIndex::~BaseIndex()
{
    Interrupt();
    Stop();
}

bool BaseIndex::Init()
{
    CBlockLocator locator;
    if (!GetDB().ReadBestBlock(locator)) {
        locator.SetNull();
    }

    LOCK(cs_main);
    CChain& active_chain = m_chainstate->m_chain;
    if (locator.IsNull()) {
        SetBestBlockIndex(nullptr);
    } else {
        SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
    }
    m_synced = m_best_block_index.load() == active_chain.Tip();
    if (!m_synced) {
        bool prune_violation = false;
        if (!m_best_block_index) {
            // index is not built yet
            // make sure we have all block data back to the genesis
            prune_violation = m_chainstate->m_blockman.GetFirstStoredBlock(*active_chain.Tip()) != active_chain.Genesis();
        }
        // in case the index has a best block set and is not fully synced
        // check if we have the required blocks to continue building the index
        else {
            const CBlockIndex* block_to_test = m_best_block_index.load();
            if (!active_chain.Contains(block_to_test)) {
                // if the bestblock is not part of the mainchain, find the fork
                // and make sure we have all data down to the fork
                block_to_test = active_chain.FindFork(block_to_test);
            }
            const CBlockIndex* block = active_chain.Tip();
            prune_violation = true;
            // check backwards from the tip if we have all block data until we reach the indexes bestblock
            while (block_to_test && block && (block->nStatus & BLOCK_HAVE_DATA)) {
                if (block_to_test == block) {
                    prune_violation = false;
                    break;
                }
                // block->pprev must exist at this point, since block_to_test is part of the chain
                // and thus must be encountered when going backwards from the tip
                assert(block->pprev);
                block = block->pprev;
            }
        }
        if (prune_violation) {
            return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
        }
    }
    return true;
}

static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain& chain) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
    AssertLockHeld(cs_main);

    if (!pindex_prev) {
        return chain.Genesis();
    }

    const CBlockIndex* pindex = chain.Next(pindex_prev);
    if (pindex) {
        return pindex;
    }

    return chain.Next(chain.FindFork(pindex_prev));
}

void BaseIndex::ThreadSync()
{
    SetSyscallSandboxPolicy(SyscallSandboxPolicy::TX_INDEX);
    const CBlockIndex* pindex = m_best_block_index.load();
    if (!m_synced) {
        auto& consensus_params = Params().GetConsensus();

        int64_t last_log_time = 0;
        int64_t last_locator_write_time = 0;
        while (true) {
            if (m_interrupt) {
                SetBestBlockIndex(pindex);
                // No need to handle errors in Commit. If it fails, the error will be already be
                // logged. The best way to recover is to continue, as index cannot be corrupted by
                // a missed commit to disk for an advanced index state.
                Commit();
                return;
            }

            {
                LOCK(cs_main);
                const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain);
                if (!pindex_next) {
                    SetBestBlockIndex(pindex);
                    m_synced = true;
                    // No need to handle errors in Commit. See rationale above.
                    Commit();
                    break;
                }
                if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) {
                    FatalError("%s: Failed to rewind index %s to a previous chain tip",
                               __func__, GetName());
                    return;
                }
                pindex = pindex_next;
            }

            int64_t current_time = GetTime();
            if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
                LogPrintf("Syncing %s with block chain from height %d\n",
                          GetName(), pindex->nHeight);
                last_log_time = current_time;
            }

            if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
                SetBestBlockIndex(pindex->pprev);
                last_locator_write_time = current_time;
                // No need to handle errors in Commit. See rationale above.
                Commit();
            }

            CBlock block;
            if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
                FatalError("%s: Failed to read block %s from disk",
                           __func__, pindex->GetBlockHash().ToString());
                return;
            }
            if (!WriteBlock(block, pindex)) {
                FatalError("%s: Failed to write block %s to index database",
                           __func__, pindex->GetBlockHash().ToString());
                return;
            }
        }
    }

    if (pindex) {
        LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
    } else {
        LogPrintf("%s is enabled\n", GetName());
    }
}

bool BaseIndex::Commit()
{
    CDBBatch batch(GetDB());
    if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
        return error("%s: Failed to commit latest %s state", __func__, GetName());
    }
    return true;
}

bool BaseIndex::CommitInternal(CDBBatch& batch)
{
    LOCK(cs_main);
    // Don't commit anything if we haven't indexed any block yet
    // (this could happen if init is interrupted).
    if (m_best_block_index == nullptr) {
        return false;
    }
    GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
    return true;
}

bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
{
    assert(current_tip == m_best_block_index);
    assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);

    // In the case of a reorg, ensure persisted block locator is not stale.
    // Pruning has a minimum of 288 blocks-to-keep and getting the index
    // out of sync may be possible but a users fault.
    // In case we reorg beyond the pruned depth, ReadBlockFromDisk would
    // throw and lead to a graceful shutdown
    SetBestBlockIndex(new_tip);
    if (!Commit()) {
        // If commit fails, revert the best block index to avoid corruption.
        SetBestBlockIndex(current_tip);
        return false;
    }

    return true;
}

void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
{
    if (!m_synced) {
        return;
    }

    const CBlockIndex* best_block_index = m_best_block_index.load();
    if (!best_block_index) {
        if (pindex->nHeight != 0) {
            FatalError("%s: First block connected is not the genesis block (height=%d)",
                       __func__, pindex->nHeight);
            return;
        }
    } else {
        // Ensure block connects to an ancestor of the current best block. This should be the case
        // most of the time, but may not be immediately after the sync thread catches up and sets
        // m_synced. Consider the case where there is a reorg and the blocks on the stale branch are
        // in the ValidationInterface queue backlog even after the sync thread has caught up to the
        // new chain tip. In this unlikely event, log a warning and let the queue clear.
        if (best_block_index->GetAncestor(pindex->nHeight - 1) != pindex->pprev) {
            LogPrintf("%s: WARNING: Block %s does not connect to an ancestor of " /* Continued */
                      "known best chain (tip=%s); not updating index\n",
                      __func__, pindex->GetBlockHash().ToString(),
                      best_block_index->GetBlockHash().ToString());
            return;
        }
        if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) {
            FatalError("%s: Failed to rewind index %s to a previous chain tip",
                       __func__, GetName());
            return;
        }
    }

    if (WriteBlock(*block, pindex)) {
        SetBestBlockIndex(pindex);
    } else {
        FatalError("%s: Failed to write block %s to index",
                   __func__, pindex->GetBlockHash().ToString());
        return;
    }
}

void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
{
    if (!m_synced) {
        return;
    }

    const uint256& locator_tip_hash = locator.vHave.front();
    const CBlockIndex* locator_tip_index;
    {
        LOCK(cs_main);
        locator_tip_index = m_chainstate->m_blockman.LookupBlockIndex(locator_tip_hash);
    }

    if (!locator_tip_index) {
        FatalError("%s: First block (hash=%s) in locator was not found",
                   __func__, locator_tip_hash.ToString());
        return;
    }

    // This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
    // immediately after the sync thread catches up and sets m_synced. Consider the case where
    // there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
    // backlog even after the sync thread has caught up to the new chain tip. In this unlikely
    // event, log a warning and let the queue clear.
    const CBlockIndex* best_block_index = m_best_block_index.load();
    if (best_block_index->GetAncestor(locator_tip_index->nHeight) != locator_tip_index) {
        LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known best " /* Continued */
                  "chain (tip=%s); not writing index locator\n",
                  __func__, locator_tip_hash.ToString(),
                  best_block_index->GetBlockHash().ToString());
        return;
    }

    // No need to handle errors in Commit. If it fails, the error will be already be logged. The
    // best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
    // for an advanced index state.
    Commit();
}

bool BaseIndex::BlockUntilSyncedToCurrentChain() const
{
    AssertLockNotHeld(cs_main);

    if (!m_synced) {
        return false;
    }

    {
        // Skip the queue-draining stuff if we know we're caught up with
        // m_chain.Tip().
        LOCK(cs_main);
        const CBlockIndex* chain_tip = m_chainstate->m_chain.Tip();
        const CBlockIndex* best_block_index = m_best_block_index.load();
        if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
            return true;
        }
    }

    LogPrintf("%s: %s is catching up on block notifications\n", __func__, GetName());
    SyncWithValidationInterfaceQueue();
    return true;
}

void BaseIndex::Interrupt()
{
    m_interrupt();
}

bool BaseIndex::Start(CChainState& active_chainstate)
{
    m_chainstate = &active_chainstate;
    // Need to register this ValidationInterface before running Init(), so that
    // callbacks are not missed if Init sets m_synced to true.
    RegisterValidationInterface(this);
    if (!Init()) {
        return false;
    }

    m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
    return true;
}

void BaseIndex::Stop()
{
    UnregisterValidationInterface(this);

    if (m_thread_sync.joinable()) {
        m_thread_sync.join();
    }
}

IndexSummary BaseIndex::GetSummary() const
{
    IndexSummary summary{};
    summary.name = GetName();
    summary.synced = m_synced;
    summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0;
    return summary;
}

void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
    assert(!node::fPruneMode || AllowPrune());

    m_best_block_index = block;
    if (AllowPrune() && block) {
        node::PruneLockInfo prune_lock;
        prune_lock.height_first = block->nHeight;
        WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
    }
}
<|endoftext|>


<commit_before>/* This file is part of Ingen.
 * Copyright 2007-2011 David Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen 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 details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <signal.h>
#include <stdlib.h>
#include <time.h>

#include <iostream>
#include <string>

#include <boost/optional.hpp>

#include <glibmm/convert.h>
#include <glibmm/miscutils.h>
#include <glibmm/thread.h>

#include "raul/Configuration.hpp"
#include "raul/Path.hpp"
#include "raul/SharedPtr.hpp"
#include "raul/Thread.hpp"
#include "raul/log.hpp"

#include "serd/serd.h"
#include "sord/sordmm.hpp"

#include "ingen-config.h"

#include "ingen/EngineBase.hpp"
#include "ingen/EngineInterface.hpp"
#include "serialisation/Parser.hpp"
#include "shared/Configuration.hpp"
#include "shared/World.hpp"
#include "shared/runtime_paths.hpp"
#ifdef WITH_BINDINGS
#include "bindings/ingen_bindings.hpp"
#endif

using namespace std;
using namespace Raul;
using namespace Ingen;

static const timespec main_rate = { 0, 125000000 }; // 1/8 second

Ingen::Shared::World* world = NULL;

void
ingen_interrupt(int)
{
	cout << "ingen: Interrupted" << endl;
	if (world->local_engine())
		world->local_engine()->quit();
	delete world;
	exit(EXIT_FAILURE);
}

void
ingen_try(bool cond, const char* msg)
{
	if (!cond) {
		cerr << "ingen: Error: " << msg << endl;
		delete world;
		exit(EXIT_FAILURE);
	}
}

int
main(int argc, char** argv)
{
	Shared::Configuration conf;

	// Parse command line options
	try {
		conf.parse(argc, argv);
	} catch (std::exception& e) {
		cout << "ingen: " << e.what() << endl;
		return EXIT_FAILURE;
	}

	// Verify option sanity
	if (argc <= 1) {
		conf.print_usage("ingen", cout);
		return EXIT_FAILURE;
	} else if (conf.option("help").get_bool()) {
		conf.print_usage("ingen", cout);
		return EXIT_SUCCESS;
	}

	// Set bundle path from executable location so resources can be found
	Shared::set_bundle_path_from_code((void*)&main);

	SharedPtr<EngineInterface> engine_interface;

	Glib::thread_init();
#if HAVE_SOUP
	g_type_init();
#endif

	Ingen::Shared::World* world = new Ingen::Shared::World(&conf, argc, argv);

#if INGEN_JACK_SESSION
	if (conf.option("uuid").get_string()) {
		world->set_jack_uuid(conf.option("uuid").get_string());
	}
#endif

	// Run engine
	if (conf.option("engine").get_bool()) {
		ingen_try(world->load_module("engine"),
		          "Unable to load engine module");

		ingen_try(world->local_engine(),
		          "Unable to create engine");

		engine_interface = world->engine();

		// Not loading a GUI, load network engine interfaces
		if (!conf.option("gui").get_bool()) {
			#ifdef HAVE_LIBLO
			ingen_try(world->load_module("osc"),
			          "Unable to load OSC module");
			#endif
			#ifdef HAVE_SOUP
			ingen_try(world->load_module("http"),
			          "Unable to load HTTP module");
			#endif
		}
	}

	// If we don't have a local engine interface (for GUI), use network
	if (!engine_interface) {
		const char* const uri = conf.option("connect").get_string();
		ingen_try((engine_interface = world->interface(uri)),
		          (string("Unable to create interface to `") + uri + "'").c_str());
	}

	// Activate the engine, if we have one
	if (world->local_engine()) {
		ingen_try(world->load_module("jack"),
		          "Unable to load jack module");
	}

	world->set_engine(engine_interface);

	// Load a patch
	if (conf.option("load").is_valid() && engine_interface) {
		boost::optional<Path>   parent;
		boost::optional<Symbol> symbol;
		const Raul::Atom&       path_option = conf.option("path");

		if (path_option.is_valid()) {
			if (Path::is_valid(path_option.get_string())) {
				const Path p(path_option.get_string());
				if (!p.is_root()) {
					parent = p.parent();
					symbol = p.symbol();
				}
			} else {
				cerr << "Invalid path given: '" << path_option << endl;
			}
		}

		ingen_try(world->load_module("serialisation"),
		          "Unable to load serialisation module");

		ingen_try(world->parser(),
		          "Unable to create parser");

		string uri = conf.option("load").get_string();
		if (!serd_uri_string_has_scheme((const uint8_t*)uri.c_str())) {
			// Does not start with legal URI scheme, assume path
			uri = Glib::filename_to_uri(
				(Glib::path_is_absolute(uri))
				? uri
				: Glib::build_filename(Glib::get_current_dir(), uri));
		}

		engine_interface->get("ingen:plugins");
		world->parser()->parse_file(
			world, engine_interface.get(), uri, parent, symbol);
	}

	// Load GUI
	if (conf.option("gui").get_bool())
		ingen_try(world->load_module("gui"),
		          "Unable to load GUI module");

	// Run a script
	if (conf.option("run").is_valid()) {
#ifdef WITH_BINDINGS
		ingen_try(world->load_module("bindings"),
		          "Unable to load bindings module");

		world->run("application/x-python", conf.option("run").get_string());
#else
		cerr << "This build of ingen does not support scripting." << endl;
#endif

	// Run main loop
	} else if (world->local_engine() && !conf.option("gui").get_bool()) {
		// Set up signal handlers that will set quit_flag on interrupt
		signal(SIGINT, ingen_interrupt);
		signal(SIGTERM, ingen_interrupt);

		// Activate the enginie
		world->local_engine()->activate();

		// Run engine main loop until interrupt
		while (world->local_engine()->main_iteration()) {
			nanosleep(&main_rate, NULL);
		}
		info << "Finished main loop" << endl;

		world->local_engine()->deactivate();
	}

	// Shut down
	if (world->local_engine())
		world->local_engine()->deactivate();

	delete world;

	return 0;
}

<commit_msg>Initialise client module when necessary (partially fix OSC/HTTP).<commit_after>/* This file is part of Ingen.
 * Copyright 2007-2011 David Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen 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 details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <signal.h>
#include <stdlib.h>
#include <time.h>

#include <iostream>
#include <string>

#include <boost/optional.hpp>

#include <glibmm/convert.h>
#include <glibmm/miscutils.h>
#include <glibmm/thread.h>

#include "raul/Configuration.hpp"
#include "raul/Path.hpp"
#include "raul/SharedPtr.hpp"
#include "raul/Thread.hpp"
#include "raul/log.hpp"

#include "serd/serd.h"
#include "sord/sordmm.hpp"

#include "ingen-config.h"

#include "ingen/EngineBase.hpp"
#include "ingen/EngineInterface.hpp"
#include "serialisation/Parser.hpp"
#include "shared/Configuration.hpp"
#include "shared/World.hpp"
#include "shared/runtime_paths.hpp"
#ifdef WITH_BINDINGS
#include "bindings/ingen_bindings.hpp"
#endif

using namespace std;
using namespace Raul;
using namespace Ingen;

static const timespec main_rate = { 0, 125000000 }; // 1/8 second

Ingen::Shared::World* world = NULL;

void
ingen_interrupt(int)
{
	cout << "ingen: Interrupted" << endl;
	if (world->local_engine())
		world->local_engine()->quit();
	delete world;
	exit(EXIT_FAILURE);
}

void
ingen_try(bool cond, const char* msg)
{
	if (!cond) {
		cerr << "ingen: Error: " << msg << endl;
		delete world;
		exit(EXIT_FAILURE);
	}
}

int
main(int argc, char** argv)
{
	Shared::Configuration conf;

	// Parse command line options
	try {
		conf.parse(argc, argv);
	} catch (std::exception& e) {
		cout << "ingen: " << e.what() << endl;
		return EXIT_FAILURE;
	}

	// Verify option sanity
	if (argc <= 1) {
		conf.print_usage("ingen", cout);
		return EXIT_FAILURE;
	} else if (conf.option("help").get_bool()) {
		conf.print_usage("ingen", cout);
		return EXIT_SUCCESS;
	}

	// Set bundle path from executable location so resources can be found
	Shared::set_bundle_path_from_code((void*)&main);

	SharedPtr<EngineInterface> engine_interface;

	Glib::thread_init();
#if HAVE_SOUP
	g_type_init();
#endif

	Ingen::Shared::World* world = new Ingen::Shared::World(&conf, argc, argv);

#if INGEN_JACK_SESSION
	if (conf.option("uuid").get_string()) {
		world->set_jack_uuid(conf.option("uuid").get_string());
	}
#endif

	// Run engine
	if (conf.option("engine").get_bool()) {
		ingen_try(world->load_module("engine"),
		          "Unable to load engine module");

		ingen_try(world->local_engine(),
		          "Unable to create engine");

		engine_interface = world->engine();

		// Not loading a GUI, load network engine interfaces
		if (!conf.option("gui").get_bool()) {
			#ifdef HAVE_LIBLO
			ingen_try(world->load_module("osc"),
			          "Unable to load OSC module");
			#endif
			#ifdef HAVE_SOUP
			ingen_try(world->load_module("http"),
			          "Unable to load HTTP module");
			#endif
		}
	}

	// If we don't have a local engine interface (for GUI), use network
	if (!engine_interface) {
		ingen_try(world->load_module("client"),
		          "Unable to load client module");
		const char* const uri = conf.option("connect").get_string();
		ingen_try((engine_interface = world->interface(uri)),
		          (string("Unable to create interface to `") + uri + "'").c_str());
	}

	// Activate the engine, if we have one
	if (world->local_engine()) {
		ingen_try(world->load_module("jack"),
		          "Unable to load jack module");
	}

	world->set_engine(engine_interface);

	// Load a patch
	if (conf.option("load").is_valid() && engine_interface) {
		boost::optional<Path>   parent;
		boost::optional<Symbol> symbol;
		const Raul::Atom&       path_option = conf.option("path");

		if (path_option.is_valid()) {
			if (Path::is_valid(path_option.get_string())) {
				const Path p(path_option.get_string());
				if (!p.is_root()) {
					parent = p.parent();
					symbol = p.symbol();
				}
			} else {
				cerr << "Invalid path given: '" << path_option << endl;
			}
		}

		ingen_try(world->load_module("serialisation"),
		          "Unable to load serialisation module");

		ingen_try(world->parser(),
		          "Unable to create parser");

		string uri = conf.option("load").get_string();
		if (!serd_uri_string_has_scheme((const uint8_t*)uri.c_str())) {
			// Does not start with legal URI scheme, assume path
			uri = Glib::filename_to_uri(
				(Glib::path_is_absolute(uri))
				? uri
				: Glib::build_filename(Glib::get_current_dir(), uri));
		}

		engine_interface->get("ingen:plugins");
		world->parser()->parse_file(
			world, engine_interface.get(), uri, parent, symbol);
	}

	// Load GUI
	if (conf.option("gui").get_bool())
		ingen_try(world->load_module("gui"),
		          "Unable to load GUI module");

	// Run a script
	if (conf.option("run").is_valid()) {
#ifdef WITH_BINDINGS
		ingen_try(world->load_module("bindings"),
		          "Unable to load bindings module");

		world->run("application/x-python", conf.option("run").get_string());
#else
		cerr << "This build of ingen does not support scripting." << endl;
#endif

	// Run main loop
	} else if (world->local_engine() && !conf.option("gui").get_bool()) {
		// Set up signal handlers that will set quit_flag on interrupt
		signal(SIGINT, ingen_interrupt);
		signal(SIGTERM, ingen_interrupt);

		// Activate the enginie
		world->local_engine()->activate();

		// Run engine main loop until interrupt
		while (world->local_engine()->main_iteration()) {
			nanosleep(&main_rate, NULL);
		}
		info << "Finished main loop" << endl;

		world->local_engine()->deactivate();
	}

	// Shut down
	if (world->local_engine())
		world->local_engine()->deactivate();

	delete world;

	return 0;
}

<|endoftext|>


<commit_before>/*
 Accepts input with a list of urls and the included text, as:
 url1 word1 word2...
 url2 word1 word2...
 url3 ...
 ...

 And organizes them into a map of strings and heaps, the heap containing the
 all the urls in which that word occurs and their frequencies.
*/

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <string>
#include "Indexer.h"

using namespace std;

Indexer::Indexer(){}

void Indexer::initializeIndex(){
    string url_line;
    string url;
    string word;
    istringstream ss;
    unordered_map<string, unsigned int> frequency;

    while (!cin.eof()) {

        // get url followed by all the words
        getline(cin, url_line);
        ss.str(url_line);
        ss >> url;

        while (ss >> word) {
            // count the frequency of each word
            if (frequency.find(word) == frequency.end()) {
                if (indexer.find(word) == indexer.end()) {
                    URLheap heap;
                    indexer[word] = heap;
                    // make a new heap since the word is not in our indexer
                }
                frequency[word] = 1;
            } else {
                frequency[word] += 1;
            }
        }

        // add those frequency pairs to the wolrd indexer
        for (auto it = frequency.begin(); it != frequency.end(); it++) {
            indexer[it->first].push_back(pair<string, unsigned int>(url, it->second));
            push_heap(indexer[it->first].begin(), indexer[it->first].end(), index_sort());
        }

        url_line.clear();
        url.clear();
        ss.clear();
        frequency.clear();

    }
}

unordered_map<string, URLheap > Indexer::getIndexer(){
    return indexer;
}

void Indexer::toFile() {
	ofstream mapFileStream;
	mapFileStream.open("mapFile.txt");
	for(auto it = indexer.begin(); it != indexer.end(); it++)
	{
		mapFileStream << it->first << " ";
		for(auto it2 = it->second.begin(); it2 != it->second.end(); it2++)
		{
			mapFileStream << it2->first << " " << it2->second << " ";
		}
		mapFileStream << endl;
	}
	mapFileStream.close();
}

//make_map() { }
//
//reduce_map() { }
//
<commit_msg>Just added a file stream in Indexer<commit_after>/*
 Accepts input with a list of urls and the included text, as:
 url1 word1 word2...
 url2 word1 word2...
 url3 ...
 ...

 And organizes them into a map of strings and heaps, the heap containing the
 all the urls in which that word occurs and their frequencies.
*/

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <string>
#include "Indexer.h"

using namespace std;

Indexer::Indexer(){}

void Indexer::initializeIndex(){
    string url_line;
    string url;
    string word;
    istringstream ss;
    ifstream fs;
    fin.open(".urlText.txt")
    unordered_map<string, unsigned int> frequency;

    while (!fin.eof()) {

        // get url followed by all the words
        getline(fin, url_line);
        ss.str(url_line);
        ss >> url;

        while (ss >> word) {
            // count the frequency of each word
            if (frequency.find(word) == frequency.end()) {
		/*
                if (indexer.find(word) == indexer.end()) {
                    URLheap heap;
                    indexer[word] = heap;
                    // make a new heap since the word is not in our indexer
                }
		*/
                frequency[word] = 1;
            } else {
                frequency[word] += 1;
            }
        }

        // add those frequency pairs to the wolrd indexer
        for (auto it = frequency.begin(); it != frequency.end(); it++) {
            indexer[it->first].push_back(pair<string, unsigned int>(url, it->second));
            push_heap(indexer[it->first].begin(), indexer[it->first].end(), index_sort());
        }

        url_line.clear();
        url.clear();
        ss.clear();
        frequency.clear();

    }
}

unordered_map<string, URLheap > Indexer::getIndexer(){
    return indexer;
}

void Indexer::toFile() {
	ofstream mapFileStream;
	mapFileStream.open("mapFile.txt");
	for(auto it = indexer.begin(); it != indexer.end(); it++)
	{
		mapFileStream << it->first << " ";
		for(auto it2 = it->second.begin(); it2 != it->second.end(); it2++)
		{
			mapFileStream << it2->first << " " << it2->second << " ";
		}
		mapFileStream << endl;
	}
	mapFileStream.close();
}

//make_map() { }
//
//reduce_map() { }
//
<|endoftext|>