<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#include "../../../StroikaPreComp.h"

#include "../../../Characters/FloatConversion.h"
#include "../../../Characters/Format.h"
#include "../../../Characters/String2Int.h"
#include "../../../Characters/StringBuilder.h"
#include "../../../Characters/String_Constant.h"
#include "../../../Streams/TextReader.h"
#include "../../BadFormatException.h"

#include "Reader.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::DataExchange;

using Characters::Character;
using Characters::StringBuilder;
using Memory::Byte;
using Memory::Optional;
using Characters::String_Constant;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

namespace {

    /*
     * Parse strategy:
     *      o   Pre-pass to map all input to UNICODE - and then just handle a sequence of unicode strings
     *      o   Classic resursive decent parser.
     *      o   Inline lexical analysis (cuz very simple)
     */

    enum ReadState_ {
        eNeutral_,
        eInObject_,
        eInArray_,
        eInNumber_,
        eInString_,
    };

    /*
     * Utilities to treat string iterator/end ptr as a 'stream pointer' - and get next char
     */
    inline wchar_t NextChar_ (const Streams::InputStream<Character>& in)
    {
        Require (not in.IsAtEOF ());
        return in.Read ()->As<wchar_t> ();
    }

    VariantValue Reader_value_ (const Streams::InputStream<Character>& in);

    // throw if bad hex digit
    unsigned int HexChar2Num_ (char c)
    {
        if ('0' <= c and c <= '9') {
            return c - '0';
        }
        if ('A' <= c and c <= 'F') {
            return (c - 'A') + 10;
        }
        if ('a' <= c and c <= 'f') {
            return (c - 'a') + 10;
        }
        Execution::Throw (BadFormatException (String_Constant{L"JSON: bad hex digit after \\u"}));
    }

    // 'in' is positioned to the start of string, and we read, leaving in possitioned just after end of string
    VariantValue Reader_String_ (const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Require (not in.IsAtEOF ());
        wchar_t c = NextChar_ (in);
        if (c != '\"') {
            Execution::Throw (BadFormatException (String_Constant{L"JSON: Expected quoted string"}));
        }
        // accumulate chars, and check for close-quote
        StringBuilder result;
        while (true) {
            if (in.IsAtEOF ()) {
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
            }
            c = NextChar_ (in);
            if (c == '\"') {
                return VariantValue (result.str ());
            }
            else if (c == '\\') {
                // quoted character read...
                if (in.IsAtEOF ()) {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
                }
                c = NextChar_ (in);
                switch (c) {
                    case 'b':
                        c = '\b';
                        break;
                    case 'f':
                        c = '\f';
                        break;
                    case 'n':
                        c = '\n';
                        break;
                    case 'r':
                        c = '\r';
                        break;
                    case 't':
                        c = '\t';
                        break;
                    case 'u': {
                        // Not sure this is right -- But I hope so ... -- LGP 2012-11-29
                        wchar_t newC = '\0';
                        for (int n = 0; n < 4; ++n) {
                            if (in.IsAtEOF ()) {
                                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
                            }
                            newC += HexChar2Num_ (static_cast<char> (NextChar_ (in)));
                            if (n != 3) {
                                newC <<= 4;
                            }
                        }
                        c = newC;
                    } break;
                    default: {
                        // if we have \N for any unrecognized N, just treat it as N
                    }
                }
            }
            result += c; // must handle other character quoting (besides \u which was preflighted)
        }
    }

    // 'in' is positioned to the second character of number (first passed as arg), and we read, leaving in positioned just after end of number
    static constexpr Character kDash_{'-'};
    VariantValue Reader_Number_ (wchar_t initialChar, const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Require (initialChar == '-' or iswdigit (initialChar));

        bool containsDot = false;
        // ACCUMULATE STRING, and then call builtin number parsing functions...
        // This accumulation is NOT as restrictive as it could be - but should accept all valid numbers
        StringBuilder tmp;
        for (wchar_t c = initialChar; c != '\0'; c = in.Read ().Value ('\0').As<wchar_t> ()) {
            if (iswdigit (c) or c == '.' or c == 'e' or c == 'E' or c == '+' or c == '-') {
                tmp += c;
                if (c == '.') {
                    containsDot = true;
                }
            }
            else {
                // any other character signals end of number (not a syntax error)
                // but backup - don't consume next character - not part of number
                Assert (not!tmp.empty ()); // at least consumed 'initialChar'
                in.Seek (Streams::Whence::eFromCurrent, -1);
                break;
            }
        }
        if (containsDot) {
            return VariantValue (Characters::String2Float<long double> (tmp.str ()));
        }
        else {
            // if no - use unsigned since has wider range (if no -)
            String t = tmp.str ();
            return t.LTrim ().StartsWith (kDash_) ? VariantValue (Characters::String2Int<long long int> (t)) : VariantValue (Characters::String2Int<unsigned long long int> (t));
        }
    }

    // NOTE: THIS STARTS SEEKED JUST PAST OPENING '{'
    VariantValue Reader_Object_ (const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Require (not in.IsAtEOF ());
        Mapping<String, VariantValue> result;

        // accumulate elements, and check for close-array
        enum LookingFor { eName,
                          eValue,
                          eColon,
                          eComma };
        LookingFor lf = eName;

        Optional<String> curName;
        while (true) {
            Optional<Character> oNextChar = in.Read ();
            if (oNextChar.IsMissing ()) {
                in.Seek (Streams::Whence::eFromCurrent, -1);
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for '}')"}));
            }
            wchar_t nextChar = oNextChar->As<wchar_t> ();
            if (nextChar == '}') {
                if (lf == eName or lf == eComma) {
                    // skip char
                    return VariantValue (result);
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected '}' reading object"}));
                }
            }
            else if (iswspace (nextChar)) {
                // skip char
            }
            else if (nextChar == ',') {
                if (lf == eComma) {
                    // skip char
                    lf = eName; // next elt
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected ',' reading object"}));
                }
            }
            else if (nextChar == ':') {
                if (lf == eColon) {
                    // skip char
                    lf = eValue; // next elt
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected ':' reading object"}));
                }
            }
            else {
                in.Seek (Streams::Whence::eFromCurrent, -1);
                if (lf == eName) {
                    curName = Reader_String_ (in).As<wstring> ();
                    lf      = eColon;
                }
                else if (lf == eValue) {
                    Assert (curName.IsPresent ());
                    result.Add (*curName, Reader_value_ (in));
                    curName.clear ();
                    lf = eComma;
                }
                else {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character looking for colon or comma reading object"}));
                }
            }
        }
    }

    // NOTE - called with OPENING '[' already read
    VariantValue Reader_Array_ (const Streams::InputStream<Characters::Character>& in)
    {
        Require (in != nullptr);
        Require (not in.IsAtEOF ());
        vector<VariantValue> result;

        // accumulate elements, and check for close-array
        bool lookingForElt = true;
        while (true) {
            if (in.IsAtEOF ()) {
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for ']')"}));
            }
            if (in.Peek () == ']') {
                if (lookingForElt) {
                    // allow ending ',' - harmless - could  be more aggressive - but if so - careful of zero-sized array special case
                }
                NextChar_ (in); // skip char
                return VariantValue (result);
            }
            else if (in.Peek () == ',') {
                if (lookingForElt) {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected second ',' in reading array"}));
                }
                else {
                    lookingForElt = true;
                }
                NextChar_ (in); // skip char
            }
            else if (iswspace (in.Peek ()->As<wchar_t> ())) {
                NextChar_ (in); // skip char
            }
            else {
                // not looking at whitespace, in midst of array, and array not terminated, so better be looking at a value
                if (lookingForElt) {
                    Containers::ReserveSpeedTweekAdd1 (result);
                    result.push_back (Reader_value_ (in));
                    lookingForElt = false;
                }
                else {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character (missing ',' ?) in reading array"}));
                }
            }
        }
    }

    VariantValue Reader_SpecialToken_ (wchar_t initialChar, const Streams::InputStream<Characters::Character>& in)
    {
        Require (in != nullptr);
        Streams::SeekOffsetType savedPos = in.GetOffset ();
        switch (initialChar) {
            case 'f': {
                Character buf[4];
                if (in.ReadAll (begin (buf), end (buf)) == 4 and
                    buf[0] == 'a' and
                    buf[1] == 'l' and
                    buf[2] == 's' and
                    buf[3] == 'e') {
                    return VariantValue{false};
                }
            } break;
            case 't': {
                Character buf[3];
                if (in.ReadAll (begin (buf), end (buf)) == 3 and
                    buf[0] == 'r' and
                    buf[1] == 'u' and
                    buf[2] == 'e') {
                    return VariantValue{true};
                }
            } break;
            case 'n': {
                Character buf[3];
                if (in.ReadAll (begin (buf), end (buf)) == 3 and
                    buf[0] == 'u' and
                    buf[1] == 'l' and
                    buf[2] == 'l') {
                    return VariantValue{};
                }
            } break;
        }
        in.Seek (savedPos - 1); // because handed initial char, and seeked past it
        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unrecognized token"}));
    }

    VariantValue Reader_value_ (const Streams::InputStream<Characters::Character>& in)
    {
        // Skip initial whitespace, and look for any value:
        //      string
        //      number
        //      object
        //      array
        //      true
        //      false
        //      null
        for (Optional<Character> oc = in.Read (); oc; oc = in.Read ()) {
            switch (oc->As<wchar_t> ()) {
                case '\"':
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    return Reader_String_ (in);

                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '-':
                    return Reader_Number_ (oc->As<wchar_t> (), in);

                case '{':
                    return Reader_Object_ (in);
                case '[':
                    return Reader_Array_ (in);

                case 't':
                case 'f':
                case 'n':
                    return Reader_SpecialToken_ (oc->As<wchar_t> (), in);

                default: {
                    if (iswspace (oc->As<wchar_t> ())) {
                        // ignore
                    }
                    else {
                        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character looking for start of value"}));
                    }
                }
            }
        }
        // if we get here - nothing found
        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF looking for value"}));
    }
}

/*
 ********************************************************************************
 ************************* Variant::JSON::Reader ********************************
 ********************************************************************************
 */
class Variant::JSON::Reader::Rep_ : public Variant::Reader::_IRep {
public:
    virtual _SharedPtrIRep Clone () const override
    {
        return make_shared<Rep_> (); // no instance data
    }
    virtual String GetDefaultFileSuffix () const override
    {
        return String_Constant{L".json"};
    }
    virtual VariantValue Read (const Streams::InputStream<Byte>& in) override
    {
        constexpr bool kSeekable_{true};
        return Read (Streams::TextReader (in, kSeekable_));
    }
    virtual VariantValue Read (const Streams::InputStream<Characters::Character>& in) override
    {
#if USE_NOISY_TRACE_IN_THIS_MODULE_
        Debug::TraceContextBumper ctx ("DataExchange::JSON::Reader::Rep_::Read");
#endif
        Require (in.IsSeekable ());
        return Reader_value_ (in);
    }
};
Variant::JSON::Reader::Reader ()
    : inherited (make_shared<Rep_> ())
{
}
<commit_msg>fixed a couple small assertion/regressions in JSON/Reader for recent changes<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#include "../../../StroikaPreComp.h"

#include "../../../Characters/FloatConversion.h"
#include "../../../Characters/Format.h"
#include "../../../Characters/String2Int.h"
#include "../../../Characters/StringBuilder.h"
#include "../../../Characters/String_Constant.h"
#include "../../../Streams/TextReader.h"
#include "../../BadFormatException.h"

#include "Reader.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::DataExchange;

using Characters::Character;
using Characters::StringBuilder;
using Memory::Byte;
using Memory::Optional;
using Characters::String_Constant;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

namespace {

    /*
     * Parse strategy:
     *      o   Pre-pass to map all input to UNICODE - and then just handle a sequence of unicode strings
     *      o   Classic resursive decent parser.
     *      o   Inline lexical analysis (cuz very simple)
     */

    enum ReadState_ {
        eNeutral_,
        eInObject_,
        eInArray_,
        eInNumber_,
        eInString_,
    };

    /*
     * Utilities to treat string iterator/end ptr as a 'stream pointer' - and get next char
     */
    inline wchar_t NextChar_ (const Streams::InputStream<Character>& in)
    {
        Require (not in.IsAtEOF ());
        return in.Read ()->As<wchar_t> ();
    }

    VariantValue Reader_value_ (const Streams::InputStream<Character>& in);

    // throw if bad hex digit
    unsigned int HexChar2Num_ (char c)
    {
        if ('0' <= c and c <= '9') {
            return c - '0';
        }
        if ('A' <= c and c <= 'F') {
            return (c - 'A') + 10;
        }
        if ('a' <= c and c <= 'f') {
            return (c - 'a') + 10;
        }
        Execution::Throw (BadFormatException (String_Constant{L"JSON: bad hex digit after \\u"}));
    }

    // 'in' is positioned to the start of string, and we read, leaving in possitioned just after end of string
    VariantValue Reader_String_ (const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Require (not in.IsAtEOF ());
        wchar_t c = NextChar_ (in);
        if (c != '\"') {
            Execution::Throw (BadFormatException (String_Constant{L"JSON: Expected quoted string"}));
        }
        // accumulate chars, and check for close-quote
        StringBuilder result;
        while (true) {
            if (in.IsAtEOF ()) {
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
            }
            c = NextChar_ (in);
            if (c == '\"') {
                return VariantValue (result.str ());
            }
            else if (c == '\\') {
                // quoted character read...
                if (in.IsAtEOF ()) {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
                }
                c = NextChar_ (in);
                switch (c) {
                    case 'b':
                        c = '\b';
                        break;
                    case 'f':
                        c = '\f';
                        break;
                    case 'n':
                        c = '\n';
                        break;
                    case 'r':
                        c = '\r';
                        break;
                    case 't':
                        c = '\t';
                        break;
                    case 'u': {
                        // Not sure this is right -- But I hope so ... -- LGP 2012-11-29
                        wchar_t newC = '\0';
                        for (int n = 0; n < 4; ++n) {
                            if (in.IsAtEOF ()) {
                                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for close quote)"}));
                            }
                            newC += HexChar2Num_ (static_cast<char> (NextChar_ (in)));
                            if (n != 3) {
                                newC <<= 4;
                            }
                        }
                        c = newC;
                    } break;
                    default: {
                        // if we have \N for any unrecognized N, just treat it as N
                    }
                }
            }
            result += c; // must handle other character quoting (besides \u which was preflighted)
        }
    }

    // 'in' is positioned to the second character of number (first passed as arg), and we read, leaving in positioned just after end of number
    static constexpr Character kDash_{'-'};
    VariantValue Reader_Number_ (wchar_t initialChar, const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Require (initialChar == '-' or iswdigit (initialChar));

        bool containsDot = false;
        // ACCUMULATE STRING, and then call builtin number parsing functions...
        // This accumulation is NOT as restrictive as it could be - but should accept all valid numbers
        StringBuilder tmp;
        for (wchar_t c = initialChar; c != '\0'; c = in.Read ().Value ('\0').As<wchar_t> ()) {
            if (iswdigit (c) or c == '.' or c == 'e' or c == 'E' or c == '+' or c == '-') {
                tmp += c;
                if (c == '.') {
                    containsDot = true;
                }
            }
            else {
                // any other character signals end of number (not a syntax error)
                // but backup - don't consume next character - not part of number
                Assert (not tmp.empty ()); // at least consumed 'initialChar'
                in.Seek (Streams::Whence::eFromCurrent, -1);
                break;
            }
        }
        if (containsDot) {
            return VariantValue (Characters::String2Float<long double> (tmp.str ()));
        }
        else {
            // if no - use unsigned since has wider range (if no -)
            String t = tmp.str ();
            return t.LTrim ().StartsWith (kDash_) ? VariantValue (Characters::String2Int<long long int> (t)) : VariantValue (Characters::String2Int<unsigned long long int> (t));
        }
    }

    // NOTE: THIS STARTS SEEKED JUST PAST OPENING '{'
    VariantValue Reader_Object_ (const Streams::InputStream<Character>& in)
    {
        Require (in != nullptr);
        Mapping<String, VariantValue> result;

        // accumulate elements, and check for close-array
        enum LookingFor { eName,
                          eValue,
                          eColon,
                          eComma };
        LookingFor lf = eName;

        Optional<String> curName;
        while (true) {
            Optional<Character> oNextChar = in.Read ();
            if (oNextChar.IsMissing ()) {
                in.Seek (Streams::Whence::eFromCurrent, -1);
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for '}')"}));
            }
            wchar_t nextChar = oNextChar->As<wchar_t> ();
            if (nextChar == '}') {
                if (lf == eName or lf == eComma) {
                    // skip char
                    return VariantValue (result);
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected '}' reading object"}));
                }
            }
            else if (iswspace (nextChar)) {
                // skip char
            }
            else if (nextChar == ',') {
                if (lf == eComma) {
                    // skip char
                    lf = eName; // next elt
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected ',' reading object"}));
                }
            }
            else if (nextChar == ':') {
                if (lf == eColon) {
                    // skip char
                    lf = eValue; // next elt
                }
                else {
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected ':' reading object"}));
                }
            }
            else {
                in.Seek (Streams::Whence::eFromCurrent, -1);
                if (lf == eName) {
                    curName = Reader_String_ (in).As<wstring> ();
                    lf      = eColon;
                }
                else if (lf == eValue) {
                    Assert (curName.IsPresent ());
                    result.Add (*curName, Reader_value_ (in));
                    curName.clear ();
                    lf = eComma;
                }
                else {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character looking for colon or comma reading object"}));
                }
            }
        }
    }

    // NOTE - called with OPENING '[' already read
    VariantValue Reader_Array_ (const Streams::InputStream<Characters::Character>& in)
    {
        Require (in != nullptr);
        vector<VariantValue> result;

        // accumulate elements, and check for close-array
        bool lookingForElt = true;
        while (true) {
            if (in.IsAtEOF ()) {
                Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF reading string (looking for ']')"}));
            }
            if (in.Peek () == ']') {
                if (lookingForElt) {
                    // allow ending ',' - harmless - could  be more aggressive - but if so - careful of zero-sized array special case
                }
                NextChar_ (in); // skip char
                return VariantValue (result);
            }
            else if (in.Peek () == ',') {
                if (lookingForElt) {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected second ',' in reading array"}));
                }
                else {
                    lookingForElt = true;
                }
                NextChar_ (in); // skip char
            }
            else if (iswspace (in.Peek ()->As<wchar_t> ())) {
                NextChar_ (in); // skip char
            }
            else {
                // not looking at whitespace, in midst of array, and array not terminated, so better be looking at a value
                if (lookingForElt) {
                    Containers::ReserveSpeedTweekAdd1 (result);
                    result.push_back (Reader_value_ (in));
                    lookingForElt = false;
                }
                else {
                    Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character (missing ',' ?) in reading array"}));
                }
            }
        }
    }

    VariantValue Reader_SpecialToken_ (wchar_t initialChar, const Streams::InputStream<Characters::Character>& in)
    {
        Require (in != nullptr);
        Streams::SeekOffsetType savedPos = in.GetOffset ();
        switch (initialChar) {
            case 'f': {
                Character buf[4];
                if (in.ReadAll (begin (buf), end (buf)) == 4 and
                    buf[0] == 'a' and
                    buf[1] == 'l' and
                    buf[2] == 's' and
                    buf[3] == 'e') {
                    return VariantValue{false};
                }
            } break;
            case 't': {
                Character buf[3];
                if (in.ReadAll (begin (buf), end (buf)) == 3 and
                    buf[0] == 'r' and
                    buf[1] == 'u' and
                    buf[2] == 'e') {
                    return VariantValue{true};
                }
            } break;
            case 'n': {
                Character buf[3];
                if (in.ReadAll (begin (buf), end (buf)) == 3 and
                    buf[0] == 'u' and
                    buf[1] == 'l' and
                    buf[2] == 'l') {
                    return VariantValue{};
                }
            } break;
        }
        in.Seek (savedPos - 1); // because handed initial char, and seeked past it
        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unrecognized token"}));
    }

    VariantValue Reader_value_ (const Streams::InputStream<Characters::Character>& in)
    {
        // Skip initial whitespace, and look for any value:
        //      string
        //      number
        //      object
        //      array
        //      true
        //      false
        //      null
        for (Optional<Character> oc = in.Read (); oc; oc = in.Read ()) {
            switch (oc->As<wchar_t> ()) {
                case '\"':
                    in.Seek (Streams::Whence::eFromCurrent, -1);
                    return Reader_String_ (in);

                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '-':
                    return Reader_Number_ (oc->As<wchar_t> (), in);

                case '{':
                    return Reader_Object_ (in);
                case '[':
                    return Reader_Array_ (in);

                case 't':
                case 'f':
                case 'n':
                    return Reader_SpecialToken_ (oc->As<wchar_t> (), in);

                default: {
                    if (iswspace (oc->As<wchar_t> ())) {
                        // ignore
                    }
                    else {
                        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected character looking for start of value"}));
                    }
                }
            }
        }
        // if we get here - nothing found
        Execution::Throw (BadFormatException (String_Constant{L"JSON: Unexpected EOF looking for value"}));
    }
}

/*
 ********************************************************************************
 ************************* Variant::JSON::Reader ********************************
 ********************************************************************************
 */
class Variant::JSON::Reader::Rep_ : public Variant::Reader::_IRep {
public:
    virtual _SharedPtrIRep Clone () const override
    {
        return make_shared<Rep_> (); // no instance data
    }
    virtual String GetDefaultFileSuffix () const override
    {
        return String_Constant{L".json"};
    }
    virtual VariantValue Read (const Streams::InputStream<Byte>& in) override
    {
        constexpr bool kSeekable_{true};
        return Read (Streams::TextReader (in, kSeekable_));
    }
    virtual VariantValue Read (const Streams::InputStream<Characters::Character>& in) override
    {
#if USE_NOISY_TRACE_IN_THIS_MODULE_
        Debug::TraceContextBumper ctx ("DataExchange::JSON::Reader::Rep_::Read");
#endif
        Require (in.IsSeekable ());
        return Reader_value_ (in);
    }
};
Variant::JSON::Reader::Reader ()
    : inherited (make_shared<Rep_> ())
{
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <otbMachineLearningModel.h>

typedef otb::MachineLearningModel<float,short>          MachineLearningModelType1;
typedef MachineLearningModelType1::InputValueType       InputValueType1;
typedef MachineLearningModelType1::InputSampleType      InputSampleType1;
typedef MachineLearningModelType1::InputListSampleType  InputListSampleType1;
typedef MachineLearningModelType1::TargetValueType      TargetValueType1;
typedef MachineLearningModelType1::TargetSampleType     TargetSampleType1;
typedef MachineLearningModelType1::TargetListSampleType TargetListSampleType1;

typedef otb::MachineLearningModel<float,itk::VariableLengthVector<double>> MachineLearningModelType2;
typedef MachineLearningModelType2::InputValueType       InputValueType2;
typedef MachineLearningModelType2::InputSampleType      InputSampleType2;
typedef MachineLearningModelType2::InputListSampleType  InputListSampleType2;
typedef MachineLearningModelType2::TargetValueType      TargetValueType2;
typedef MachineLearningModelType2::TargetSampleType     TargetSampleType2;
typedef MachineLearningModelType2::TargetListSampleType TargetListSampleType2;

<commit_msg>BUG: avoid >> at the end of nested templates<commit_after>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <otbMachineLearningModel.h>

typedef otb::MachineLearningModel<float,short>          MachineLearningModelType1;
typedef MachineLearningModelType1::InputValueType       InputValueType1;
typedef MachineLearningModelType1::InputSampleType      InputSampleType1;
typedef MachineLearningModelType1::InputListSampleType  InputListSampleType1;
typedef MachineLearningModelType1::TargetValueType      TargetValueType1;
typedef MachineLearningModelType1::TargetSampleType     TargetSampleType1;
typedef MachineLearningModelType1::TargetListSampleType TargetListSampleType1;

typedef otb::MachineLearningModel<float,itk::VariableLengthVector<double> > MachineLearningModelType2;
typedef MachineLearningModelType2::InputValueType       InputValueType2;
typedef MachineLearningModelType2::InputSampleType      InputSampleType2;
typedef MachineLearningModelType2::InputListSampleType  InputListSampleType2;
typedef MachineLearningModelType2::TargetValueType      TargetValueType2;
typedef MachineLearningModelType2::TargetSampleType     TargetSampleType2;
typedef MachineLearningModelType2::TargetListSampleType TargetListSampleType2;

<|endoftext|>


<commit_before>#include <node.h>
#include <node_object_wrap.h>
extern "C" {
#include <unicode/usprep.h>
#include <string.h>
}
#include <exception>

using namespace v8;
using namespace node;

/*** Utility ***/

static Handle<Value> throwTypeError(const char *msg)
{
  return ThrowException(Exception::TypeError(String::New(msg)));
}

/* supports return of just enum */
class UnknownProfileException : public std::exception {
};

class StringPrep : public ObjectWrap {
public:
  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;
    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    NODE_SET_PROTOTYPE_METHOD(t, "prepare", Prepare);

    target->Set(String::NewSymbol("StringPrep"), t->GetFunction());
  }

  bool good() const
  {
    // warnings are negative, errors positive
    return error <= 0;
  }

  const char *errorName() const
  {
    return u_errorName(error);
  }

  Handle<Value> makeException() const
  {
    return ThrowException(Exception::Error(String::New(errorName())));
  }

protected:
  /*** Constructor ***/

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;

    if (args.Length() == 1 && args[0]->IsString())
      {
	String::Utf8Value arg0(args[0]->ToString());
	UStringPrepProfileType profileType = parseProfileType(arg0);

	if (profileType < 0)
	  return throwTypeError("Unknown StringPrep profile");
	else
	  {
	    StringPrep *self = new StringPrep(profileType);
	    if (self->good())
	      {
		self->Wrap(args.This());
		return args.This();
	      }
	    else
	      {
                Handle<Value> exception = self->makeException();
		delete self;
		return ThrowException(exception);
	      }
	  }
      }
    else
      return throwTypeError("Bad argument.");
  }

  StringPrep(const UStringPrepProfileType profileType)
  {
    profile = usprep_openByType(profileType, &error);
  }

  /*** Destructor ***/

  ~StringPrep()
  {
    if (profile)
      usprep_close(profile);
  }

  /*** Prepare ***/

  static Handle<Value> Prepare(const Arguments& args)
  {
    HandleScope scope;

    if (args.Length() == 1 && args[0]->IsString())
      {
        StringPrep *self = ObjectWrap::Unwrap<StringPrep>(args.This());
	String::Utf8Value arg0(args[0]->ToString());
        return scope.Close(self->prepare(arg0));
      }
    else
      return throwTypeError("Bad argument.");
  }

  Handle<Value> prepare(String::Utf8Value &str)
  {
    size_t destLen = str.length();
    char *dest = NULL;
    while(!dest)
      {
        dest = new char[destLen];
        size_t w = usprep_prepare(profile,
                                  reinterpret_cast<UChar *>(*str), str.length(),
                                  reinterpret_cast<UChar *>(dest), destLen,
                                  USPREP_DEFAULT, NULL, &error);

        if (error == U_BUFFER_OVERFLOW_ERROR)
          {
            // retry with a dest buffer twice as large
            destLen *= 2;
            delete[] dest;
            dest = NULL;
          }
        else if (!good())
          {
            // other error, just bail out
            delete[] dest;
            return ThrowException(makeException());
          }
      }

    Local<String> result = String::New(dest, destLen);
    delete[] dest;
    return result;
  }

private:
  UStringPrepProfile *profile;
  UErrorCode error;

  static enum UStringPrepProfileType parseProfileType(String::Utf8Value &profile)
  //throw(UnknownProfileException)
  {
    if (strcasecmp(*profile, "nameprep") == 0)
      return USPREP_RFC3491_NAMEPREP;
    if (strcasecmp(*profile, "nfs4_cs_prep") == 0)
      return USPREP_RFC3530_NFS4_CS_PREP;
    if (strcasecmp(*profile, "nfs4_cs_prep") == 0)
      return USPREP_RFC3530_NFS4_CS_PREP_CI;
    if (strcasecmp(*profile, "nfs4_cis_prep") == 0)
      return USPREP_RFC3530_NFS4_CIS_PREP;
    if (strcasecmp(*profile, "nfs4_mixed_prep prefix") == 0)
      return USPREP_RFC3530_NFS4_MIXED_PREP_PREFIX;
    if (strcasecmp(*profile, "nfs4_mixed_prep suffix") == 0)
      return USPREP_RFC3530_NFS4_MIXED_PREP_SUFFIX;
    if (strcasecmp(*profile, "iscsi") == 0)
      return USPREP_RFC3722_ISCSI;
    if (strcasecmp(*profile, "nodeprep") == 0)
      return USPREP_RFC3920_NODEPREP;
    if (strcasecmp(*profile, "resourceprep") == 0)
      return USPREP_RFC3920_RESOURCEPREP;
    if (strcasecmp(*profile, "mib") == 0)
      return USPREP_RFC4011_MIB;
    if (strcasecmp(*profile, "saslprep") == 0)
      return USPREP_RFC4013_SASLPREP;
    if (strcasecmp(*profile, "trace") == 0)
      return USPREP_RFC4505_TRACE;
    if (strcasecmp(*profile, "ldap") == 0)
      return USPREP_RFC4518_LDAP;
    if (strcasecmp(*profile, "ldapci") == 0)
      return USPREP_RFC4518_LDAP_CI;

    throw UnknownProfileException();
  }
};

/*** Initialization ***/

extern "C" void init(Handle<Object> target)
{
  HandleScope scope;
  StringPrep::Initialize(target);
}

<commit_msg>node-stringprep: fix error handling<commit_after>#include <node.h>
#include <node_object_wrap.h>
extern "C" {
#include <unicode/usprep.h>
#include <string.h>
}
#include <exception>

using namespace v8;
using namespace node;

/*** Utility ***/

static Handle<Value> throwTypeError(const char *msg)
{
  return ThrowException(Exception::TypeError(String::New(msg)));
}

/* supports return of just enum */
class UnknownProfileException : public std::exception {
};

class StringPrep : public ObjectWrap {
public:
  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;
    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    NODE_SET_PROTOTYPE_METHOD(t, "prepare", Prepare);

    target->Set(String::NewSymbol("StringPrep"), t->GetFunction());
  }

  bool good() const
  {
    // warnings are negative, errors positive
    return error <= 0;
  }

  const char *errorName() const
  {
    return u_errorName(error);
  }

  Handle<Value> makeException() const
  {
    return Exception::Error(String::New(errorName()));
  }

protected:
  /*** Constructor ***/

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;

    if (args.Length() == 1 && args[0]->IsString())
      {
	String::Utf8Value arg0(args[0]->ToString());
        UStringPrepProfileType profileType;
        try
          {
            profileType = parseProfileType(arg0);
          }
        catch (UnknownProfileException &)
          {
            return throwTypeError("Unknown StringPrep profile");
          }

        StringPrep *self = new StringPrep(profileType);
        if (self->good())
          {
            self->Wrap(args.This());
            return args.This();
          }
        else
          {
            Handle<Value> exception = self->makeException();
            delete self;
            return ThrowException(exception);
	  }
      }
    else
      return throwTypeError("Bad argument.");
  }

  StringPrep(const UStringPrepProfileType profileType)
    : error(U_ZERO_ERROR)
  {
    profile = usprep_openByType(profileType, &error);
  }

  /*** Destructor ***/

  ~StringPrep()
  {
    if (profile)
      usprep_close(profile);
  }

  /*** Prepare ***/

  static Handle<Value> Prepare(const Arguments& args)
  {
    HandleScope scope;

    if (args.Length() == 1 && args[0]->IsString())
      {
        StringPrep *self = ObjectWrap::Unwrap<StringPrep>(args.This());
	String::Utf8Value arg0(args[0]->ToString());
        return scope.Close(self->prepare(arg0));
      }
    else
      return throwTypeError("Bad argument.");
  }

  Handle<Value> prepare(String::Utf8Value &str)
  {
    size_t destLen = str.length();
    char *dest = NULL;
    while(!dest)
      {
        dest = new char[destLen];
        size_t w = usprep_prepare(profile,
                                  reinterpret_cast<UChar *>(*str), str.length(),
                                  reinterpret_cast<UChar *>(dest), destLen,
                                  USPREP_DEFAULT, NULL, &error);

        if (error == U_BUFFER_OVERFLOW_ERROR)
          {
            // retry with a dest buffer twice as large
            destLen *= 2;
            delete[] dest;
            dest = NULL;
          }
        else if (!good())
          {
            // other error, just bail out
            delete[] dest;
            return ThrowException(makeException());
          }
      }

    Local<String> result = String::New(dest, destLen);
    delete[] dest;
    return result;
  }

private:
  UStringPrepProfile *profile;
  UErrorCode error;

  static enum UStringPrepProfileType parseProfileType(String::Utf8Value &profile)
    throw(UnknownProfileException)
  {
    if (strcasecmp(*profile, "nameprep") == 0)
      return USPREP_RFC3491_NAMEPREP;
    if (strcasecmp(*profile, "nfs4_cs_prep") == 0)
      return USPREP_RFC3530_NFS4_CS_PREP;
    if (strcasecmp(*profile, "nfs4_cs_prep") == 0)
      return USPREP_RFC3530_NFS4_CS_PREP_CI;
    if (strcasecmp(*profile, "nfs4_cis_prep") == 0)
      return USPREP_RFC3530_NFS4_CIS_PREP;
    if (strcasecmp(*profile, "nfs4_mixed_prep prefix") == 0)
      return USPREP_RFC3530_NFS4_MIXED_PREP_PREFIX;
    if (strcasecmp(*profile, "nfs4_mixed_prep suffix") == 0)
      return USPREP_RFC3530_NFS4_MIXED_PREP_SUFFIX;
    if (strcasecmp(*profile, "iscsi") == 0)
      return USPREP_RFC3722_ISCSI;
    if (strcasecmp(*profile, "nodeprep") == 0)
      return USPREP_RFC3920_NODEPREP;
    if (strcasecmp(*profile, "resourceprep") == 0)
      return USPREP_RFC3920_RESOURCEPREP;
    if (strcasecmp(*profile, "mib") == 0)
      return USPREP_RFC4011_MIB;
    if (strcasecmp(*profile, "saslprep") == 0)
      return USPREP_RFC4013_SASLPREP;
    if (strcasecmp(*profile, "trace") == 0)
      return USPREP_RFC4505_TRACE;
    if (strcasecmp(*profile, "ldap") == 0)
      return USPREP_RFC4518_LDAP;
    if (strcasecmp(*profile, "ldapci") == 0)
      return USPREP_RFC4518_LDAP_CI;

    throw UnknownProfileException();
  }
};

/*** Initialization ***/

extern "C" void init(Handle<Object> target)
{
  HandleScope scope;
  StringPrep::Initialize(target);
}

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

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

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"
#include <stdio.h>

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static const int insetX = 5;    // text inset in x from calltip border
static const int widthArrow = 14;

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	rectUp = PRectangle(0,0,0,0);
	rectDown = PRectangle(0,0,0,0);
	lineHeight = 1;
	startHighlight = 0;
	endHighlight = 0;
	tabSize = 0;
	useStyleCallTip = false;    // for backwards compatibility

#ifdef __APPLE__
	// proper apple colours for the default
	colourBG.desired = ColourDesired(0xff, 0xff, 0xc6);
	colourUnSel.desired = ColourDesired(0, 0, 0);
#else
	colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
	colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
#endif
	colourSel.desired = ColourDesired(0, 0, 0x80);
	colourShade.desired = ColourDesired(0, 0, 0);
	colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
	font.Release();
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

// Although this test includes 0, we should never see a \0 character.
static bool IsArrowCharacter(char ch) {
	return (ch == 0) || (ch == '\001') || (ch == '\002');
}

// We ignore tabs unless a tab width has been set.
bool CallTip::IsTabCharacter(char ch) {
	return (tabSize > 0) && (ch == '\t');
}

int CallTip::NextTabPos(int x) {
	if (tabSize > 0) {              // paranoia... not called unless this is true
		x -= insetX;                // position relative to text
		x = (x + tabSize) / tabSize;  // tab "number"
		return tabSize*x + insetX;  // position of next tab
	} else {
		return x + 1;                 // arbitrary
	}
}

// Draw a section of the call tip that does not include \n in one colour.
// The text may include up to numEnds tabs or arrow characters.
void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
	int posStart, int posEnd, int ytext, PRectangle rcClient,
	bool highlight, bool draw) {
	s += posStart;
	int len = posEnd - posStart;

	// Divide the text into sections that are all text, or that are
	// single arrows or single tab characters (if tabSize > 0).
	int maxEnd = 0;
	const int numEnds = 10;
	int ends[numEnds + 2];
	for (int i=0;i<len;i++) {
		if ((maxEnd < numEnds) &&
		        (IsArrowCharacter(s[i]) || IsTabCharacter(s[i])) ) {
			if (i > 0)
				ends[maxEnd++] = i;
			ends[maxEnd++] = i+1;
		}
	}
	ends[maxEnd++] = len;
	int startSeg = 0;
	int xEnd;
	for (int seg = 0; seg<maxEnd; seg++) {
		int endSeg = ends[seg];
		if (endSeg > startSeg) {
			if (IsArrowCharacter(s[startSeg])) {
				bool upArrow = s[startSeg] == '\001';
				rcClient.left = x;
				rcClient.right = rcClient.left + widthArrow;
				if (draw) {
					const int halfWidth = widthArrow / 2 - 3;
					const int centreX = rcClient.left + widthArrow / 2 - 1;
					const int centreY = (rcClient.top + rcClient.bottom) / 2;
					surface->FillRectangle(rcClient, colourBG.allocated);
					PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1,
					                         rcClient.right - 2, rcClient.bottom - 1);
					surface->FillRectangle(rcClientInner, colourUnSel.allocated);

					if (upArrow) {      // Up arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY + halfWidth / 2),
    						Point(centreX + halfWidth, centreY + halfWidth / 2),
    						Point(centreX, centreY - halfWidth + halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					} else {            // Down arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY - halfWidth / 2),
    						Point(centreX + halfWidth, centreY - halfWidth / 2),
    						Point(centreX, centreY + halfWidth - halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					}
				}
				xEnd = rcClient.right;
				offsetMain = xEnd;
				if (upArrow) {
					rectUp = rcClient;
				} else {
					rectDown = rcClient;
				}
			} else if (IsTabCharacter(s[startSeg])) {
				xEnd = NextTabPos(x);
			} else {
				xEnd = x + surface->WidthText(font, s + startSeg, endSeg - startSeg);
				if (draw) {
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->DrawTextTransparent(rcClient, font, ytext,
										s+startSeg, endSeg - startSeg,
					                             highlight ? colourSel.allocated : colourUnSel.allocated);
				}
			}
			x = xEnd;
			startSeg = endSeg;
		}
	}
}

int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	int maxWidth = 0;

	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		rcClient.top = ytext - ascent - 1;

		int x = insetX;     // start each line at this inset

		DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
			ytext, rcClient, false, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
			ytext, rcClient, true, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
			ytext, rcClient, false, draw);

		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
		rcClient.bottom += lineHeight;
		maxWidth = Platform::Maximum(maxWidth, x);
	}
	return maxWidth;
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);

	offsetMain = insetX;    // initial alignment assuming no arrows
	PaintContents(surfaceWindow, true);

#ifndef __APPLE__
	// OSX doesn't put borders on "help tags"
	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
#endif
}

void CallTip::MouseClick(Point pt) {
	clickPlace = 0;
	if (rectUp.Contains(pt))
		clickPlace = 1;
	if (rectDown.Contains(pt))
		clickPlace = 2;
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size,
                                 int codePage_, int characterSet, Window &wParent) {
	clickPlace = 0;
	if (val)
		delete []val;
	val = 0;
	val = new char[strlen(defn) + 1];
	strcpy(val, defn);
	codePage = codePage_;
	Surface *surfaceMeasure = Surface::Allocate();
	if (!surfaceMeasure)
		return PRectangle();
	surfaceMeasure->Init(wParent.GetID());
	surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
	surfaceMeasure->SetDBCSMode(codePage);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
	font.Create(faceName, characterSet, deviceHeight, false, false);
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int numLines = 1;
	const char *newline;
	const char *look = val;
	rectUp = PRectangle(0,0,0,0);
	rectDown = PRectangle(0,0,0,0);
	offsetMain = insetX;            // changed to right edge of any arrows
	int width = PaintContents(surfaceMeasure, false) + insetX;
	while ((newline = strchr(look, '\n')) != NULL) {
		look = newline + 1;
		numLines++;
	}
	lineHeight = surfaceMeasure->Height(font);

	// Extra line for border and an empty line at top and bottom. The returned
	// rectangle is aligned to the right edge of the last arrow encountered in
	// the tip text, else to the tip text left edge.
	int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
	delete surfaceMeasure;
	return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}

// Set the tab size (sizes > 0 enable the use of tabs). This also enables the
// use of the STYLE_CALLTIP.
void CallTip::SetTabSize(int tabSz) {
	tabSize = tabSz;
	useStyleCallTip = true;
}

// It might be better to have two access functions for this and to use
// them for all settings of colours.
void CallTip::SetForeBack(const ColourPair &fore, const ColourPair &back) {
	colourBG = back;
	colourUnSel = fore;
}
<commit_msg>Removed unnecessary check for NULL.<commit_after>// Scintilla source code edit control
/** @file CallTip.cxx
 ** Code for displaying call tips.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

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

#include "Platform.h"

#include "Scintilla.h"
#include "CallTip.h"
#include <stdio.h>

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static const int insetX = 5;    // text inset in x from calltip border
static const int widthArrow = 14;

CallTip::CallTip() {
	wCallTip = 0;
	inCallTipMode = false;
	posStartCallTip = 0;
	val = 0;
	rectUp = PRectangle(0,0,0,0);
	rectDown = PRectangle(0,0,0,0);
	lineHeight = 1;
	startHighlight = 0;
	endHighlight = 0;
	tabSize = 0;
	useStyleCallTip = false;    // for backwards compatibility

#ifdef __APPLE__
	// proper apple colours for the default
	colourBG.desired = ColourDesired(0xff, 0xff, 0xc6);
	colourUnSel.desired = ColourDesired(0, 0, 0);
#else
	colourBG.desired = ColourDesired(0xff, 0xff, 0xff);
	colourUnSel.desired = ColourDesired(0x80, 0x80, 0x80);
#endif
	colourSel.desired = ColourDesired(0, 0, 0x80);
	colourShade.desired = ColourDesired(0, 0, 0);
	colourLight.desired = ColourDesired(0xc0, 0xc0, 0xc0);
}

CallTip::~CallTip() {
	font.Release();
	wCallTip.Destroy();
	delete []val;
	val = 0;
}

void CallTip::RefreshColourPalette(Palette &pal, bool want) {
	pal.WantFind(colourBG, want);
	pal.WantFind(colourUnSel, want);
	pal.WantFind(colourSel, want);
	pal.WantFind(colourShade, want);
	pal.WantFind(colourLight, want);
}

// Although this test includes 0, we should never see a \0 character.
static bool IsArrowCharacter(char ch) {
	return (ch == 0) || (ch == '\001') || (ch == '\002');
}

// We ignore tabs unless a tab width has been set.
bool CallTip::IsTabCharacter(char ch) {
	return (tabSize > 0) && (ch == '\t');
}

int CallTip::NextTabPos(int x) {
	if (tabSize > 0) {              // paranoia... not called unless this is true
		x -= insetX;                // position relative to text
		x = (x + tabSize) / tabSize;  // tab "number"
		return tabSize*x + insetX;  // position of next tab
	} else {
		return x + 1;                 // arbitrary
	}
}

// Draw a section of the call tip that does not include \n in one colour.
// The text may include up to numEnds tabs or arrow characters.
void CallTip::DrawChunk(Surface *surface, int &x, const char *s,
	int posStart, int posEnd, int ytext, PRectangle rcClient,
	bool highlight, bool draw) {
	s += posStart;
	int len = posEnd - posStart;

	// Divide the text into sections that are all text, or that are
	// single arrows or single tab characters (if tabSize > 0).
	int maxEnd = 0;
	const int numEnds = 10;
	int ends[numEnds + 2];
	for (int i=0;i<len;i++) {
		if ((maxEnd < numEnds) &&
		        (IsArrowCharacter(s[i]) || IsTabCharacter(s[i])) ) {
			if (i > 0)
				ends[maxEnd++] = i;
			ends[maxEnd++] = i+1;
		}
	}
	ends[maxEnd++] = len;
	int startSeg = 0;
	int xEnd;
	for (int seg = 0; seg<maxEnd; seg++) {
		int endSeg = ends[seg];
		if (endSeg > startSeg) {
			if (IsArrowCharacter(s[startSeg])) {
				bool upArrow = s[startSeg] == '\001';
				rcClient.left = x;
				rcClient.right = rcClient.left + widthArrow;
				if (draw) {
					const int halfWidth = widthArrow / 2 - 3;
					const int centreX = rcClient.left + widthArrow / 2 - 1;
					const int centreY = (rcClient.top + rcClient.bottom) / 2;
					surface->FillRectangle(rcClient, colourBG.allocated);
					PRectangle rcClientInner(rcClient.left + 1, rcClient.top + 1,
					                         rcClient.right - 2, rcClient.bottom - 1);
					surface->FillRectangle(rcClientInner, colourUnSel.allocated);

					if (upArrow) {      // Up arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY + halfWidth / 2),
    						Point(centreX + halfWidth, centreY + halfWidth / 2),
    						Point(centreX, centreY - halfWidth + halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					} else {            // Down arrow
						Point pts[] = {
    						Point(centreX - halfWidth, centreY - halfWidth / 2),
    						Point(centreX + halfWidth, centreY - halfWidth / 2),
    						Point(centreX, centreY + halfWidth - halfWidth / 2),
						};
						surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
                 						colourBG.allocated, colourBG.allocated);
					}
				}
				xEnd = rcClient.right;
				offsetMain = xEnd;
				if (upArrow) {
					rectUp = rcClient;
				} else {
					rectDown = rcClient;
				}
			} else if (IsTabCharacter(s[startSeg])) {
				xEnd = NextTabPos(x);
			} else {
				xEnd = x + surface->WidthText(font, s + startSeg, endSeg - startSeg);
				if (draw) {
					rcClient.left = x;
					rcClient.right = xEnd;
					surface->DrawTextTransparent(rcClient, font, ytext,
										s+startSeg, endSeg - startSeg,
					                             highlight ? colourSel.allocated : colourUnSel.allocated);
				}
			}
			x = xEnd;
			startSeg = endSeg;
		}
	}
}

int CallTip::PaintContents(Surface *surfaceWindow, bool draw) {
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	// To make a nice small call tip window, it is only sized to fit most normal characters without accents
	int ascent = surfaceWindow->Ascent(font) - surfaceWindow->InternalLeading(font);

	// For each line...
	// Draw the definition in three parts: before highlight, highlighted, after highlight
	int ytext = rcClient.top + ascent + 1;
	rcClient.bottom = ytext + surfaceWindow->Descent(font) + 1;
	char *chunkVal = val;
	bool moreChunks = true;
	int maxWidth = 0;

	while (moreChunks) {
		char *chunkEnd = strchr(chunkVal, '\n');
		if (chunkEnd == NULL) {
			chunkEnd = chunkVal + strlen(chunkVal);
			moreChunks = false;
		}
		int chunkOffset = chunkVal - val;
		int chunkLength = chunkEnd - chunkVal;
		int chunkEndOffset = chunkOffset + chunkLength;
		int thisStartHighlight = Platform::Maximum(startHighlight, chunkOffset);
		thisStartHighlight = Platform::Minimum(thisStartHighlight, chunkEndOffset);
		thisStartHighlight -= chunkOffset;
		int thisEndHighlight = Platform::Maximum(endHighlight, chunkOffset);
		thisEndHighlight = Platform::Minimum(thisEndHighlight, chunkEndOffset);
		thisEndHighlight -= chunkOffset;
		rcClient.top = ytext - ascent - 1;

		int x = insetX;     // start each line at this inset

		DrawChunk(surfaceWindow, x, chunkVal, 0, thisStartHighlight,
			ytext, rcClient, false, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisStartHighlight, thisEndHighlight,
			ytext, rcClient, true, draw);
		DrawChunk(surfaceWindow, x, chunkVal, thisEndHighlight, chunkLength,
			ytext, rcClient, false, draw);

		chunkVal = chunkEnd + 1;
		ytext += lineHeight;
		rcClient.bottom += lineHeight;
		maxWidth = Platform::Maximum(maxWidth, x);
	}
	return maxWidth;
}

void CallTip::PaintCT(Surface *surfaceWindow) {
	if (!val)
		return;
	PRectangle rcClientPos = wCallTip.GetClientPosition();
	PRectangle rcClientSize(0, 0, rcClientPos.right - rcClientPos.left,
	                        rcClientPos.bottom - rcClientPos.top);
	PRectangle rcClient(1, 1, rcClientSize.right - 1, rcClientSize.bottom - 1);

	surfaceWindow->FillRectangle(rcClient, colourBG.allocated);

	offsetMain = insetX;    // initial alignment assuming no arrows
	PaintContents(surfaceWindow, true);

#ifndef __APPLE__
	// OSX doesn't put borders on "help tags"
	// Draw a raised border around the edges of the window
	surfaceWindow->MoveTo(0, rcClientSize.bottom - 1);
	surfaceWindow->PenColour(colourShade.allocated);
	surfaceWindow->LineTo(rcClientSize.right - 1, rcClientSize.bottom - 1);
	surfaceWindow->LineTo(rcClientSize.right - 1, 0);
	surfaceWindow->PenColour(colourLight.allocated);
	surfaceWindow->LineTo(0, 0);
	surfaceWindow->LineTo(0, rcClientSize.bottom - 1);
#endif
}

void CallTip::MouseClick(Point pt) {
	clickPlace = 0;
	if (rectUp.Contains(pt))
		clickPlace = 1;
	if (rectDown.Contains(pt))
		clickPlace = 2;
}

PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn,
                                 const char *faceName, int size,
                                 int codePage_, int characterSet, Window &wParent) {
	clickPlace = 0;
	delete []val;
	val = 0;
	val = new char[strlen(defn) + 1];
	strcpy(val, defn);
	codePage = codePage_;
	Surface *surfaceMeasure = Surface::Allocate();
	if (!surfaceMeasure)
		return PRectangle();
	surfaceMeasure->Init(wParent.GetID());
	surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage);
	surfaceMeasure->SetDBCSMode(codePage);
	startHighlight = 0;
	endHighlight = 0;
	inCallTipMode = true;
	posStartCallTip = pos;
	int deviceHeight = surfaceMeasure->DeviceHeightFont(size);
	font.Create(faceName, characterSet, deviceHeight, false, false);
	// Look for multiple lines in the text
	// Only support \n here - simply means container must avoid \r!
	int numLines = 1;
	const char *newline;
	const char *look = val;
	rectUp = PRectangle(0,0,0,0);
	rectDown = PRectangle(0,0,0,0);
	offsetMain = insetX;            // changed to right edge of any arrows
	int width = PaintContents(surfaceMeasure, false) + insetX;
	while ((newline = strchr(look, '\n')) != NULL) {
		look = newline + 1;
		numLines++;
	}
	lineHeight = surfaceMeasure->Height(font);

	// Extra line for border and an empty line at top and bottom. The returned
	// rectangle is aligned to the right edge of the last arrow encountered in
	// the tip text, else to the tip text left edge.
	int height = lineHeight * numLines - surfaceMeasure->InternalLeading(font) + 2 + 2;
	delete surfaceMeasure;
	return PRectangle(pt.x - offsetMain, pt.y + 1, pt.x + width - offsetMain, pt.y + 1 + height);
}

void CallTip::CallTipCancel() {
	inCallTipMode = false;
	if (wCallTip.Created()) {
		wCallTip.Destroy();
	}
}

void CallTip::SetHighlight(int start, int end) {
	// Avoid flashing by checking something has really changed
	if ((start != startHighlight) || (end != endHighlight)) {
		startHighlight = start;
		endHighlight = end;
		if (wCallTip.Created()) {
			wCallTip.InvalidateAll();
		}
	}
}

// Set the tab size (sizes > 0 enable the use of tabs). This also enables the
// use of the STYLE_CALLTIP.
void CallTip::SetTabSize(int tabSz) {
	tabSize = tabSz;
	useStyleCallTip = true;
}

// It might be better to have two access functions for this and to use
// them for all settings of colours.
void CallTip::SetForeBack(const ColourPair &fore, const ColourPair &back) {
	colourBG = back;
	colourUnSel = fore;
}
<|endoftext|>


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

#include "Interval.h"
#include "WTF/CurrentTime.h"

namespace WebCore {

const char* kIntervalExtensionName = "v8/Interval";

class IntervalExtensionWrapper : public v8::Extension {
public:
    IntervalExtensionWrapper() :
        v8::Extension(kIntervalExtensionName,
          "native function HiResTime();"
          "function Interval() {"
          "  var start_ = 0;"
          "  var stop_ = 0;"
          "  this.start = function() {"
          "    start_ = HiResTime();"
          "  };"
          "  this.stop = function() {"
          "    stop_ = HiResTime();"
          "    if (start_ == 0)"
          "      stop_ = 0;"
          "  };"
          "  this.microseconds = function() {"
          "    if (stop_ == 0)"
          "      stop();"
          "    return Math.ceil((stop_ - start_) * 1000000);"
          "  };"
          "}") {};

    virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(v8::Handle<v8::String> name) {
        if (name->Equals(v8::String::New("HiResTime")))
            return v8::FunctionTemplate::New(HiResTime);
        return v8::Handle<v8::FunctionTemplate>();
    }

    static v8::Handle<v8::Value> HiResTime(const v8::Arguments& args) {
        return v8::Number::New(WTF::currentTime());
    }
};

v8::Extension*  IntervalExtension::Get() {
    return new IntervalExtensionWrapper();
}

}

<commit_msg>Case sensitive directory names on linux<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "Interval.h"
#include "wtf/CurrentTime.h"

namespace WebCore {

const char* kIntervalExtensionName = "v8/Interval";

class IntervalExtensionWrapper : public v8::Extension {
public:
    IntervalExtensionWrapper() :
        v8::Extension(kIntervalExtensionName,
          "native function HiResTime();"
          "function Interval() {"
          "  var start_ = 0;"
          "  var stop_ = 0;"
          "  this.start = function() {"
          "    start_ = HiResTime();"
          "  };"
          "  this.stop = function() {"
          "    stop_ = HiResTime();"
          "    if (start_ == 0)"
          "      stop_ = 0;"
          "  };"
          "  this.microseconds = function() {"
          "    if (stop_ == 0)"
          "      stop();"
          "    return Math.ceil((stop_ - start_) * 1000000);"
          "  };"
          "}") {};

    virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(v8::Handle<v8::String> name) {
        if (name->Equals(v8::String::New("HiResTime")))
            return v8::FunctionTemplate::New(HiResTime);
        return v8::Handle<v8::FunctionTemplate>();
    }

    static v8::Handle<v8::Value> HiResTime(const v8::Arguments& args) {
        return v8::Number::New(WTF::currentTime());
    }
};

v8::Extension*  IntervalExtension::Get() {
    return new IntervalExtensionWrapper();
}

}

<|endoftext|>


<commit_before>#include <b9.hpp>
#include <b9/loader.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

/// B9run's usage string. Printed when run with -help.
static const char* usage =
    "Usage: b9run [<option>...] [--] <module> [<main>]\n"
    "   Or: b9run -help\n"
    "Options:\n"
    "  -callstyle <style>: Set the calling style. One of:\n"
    "      interpreter:   Calls are made through the interpreter\n"
    "      direct:        Calls are made directly, but parameters are on the "
    "operand stack\n"
    "      passparameter: Direct calls, with parameters passed in CPU "
    "registers\n"
    "      operandstack:  Like passparam, but will keep the VM operand stack "
    "updated\n"
    "  -loop <n>:   Run the program <n> times\n"
    "  -inline <n>: Enable inlining\n"
    "  -debug:      Enable debug code\n"
    "  -verbose:    Run with verbose printing\n"
    "  -help:       Print this help message";

/// The b9run program's global configuration.
struct RunConfig {
  b9::VirtualMachineConfig vm;
  const char* moduleName = "";
  const char* mainFunction = "b9main";
  std::size_t loopCount = 1;
  bool verbose = false;
};

/// Print the configuration summary.
std::ostream& operator<<(std::ostream& out, const RunConfig& cfg) {
  return out << "Loading:      " << cfg.moduleName << std::endl
             << "Executing:    " << cfg.mainFunction << std::endl
             << "Call Style:   " << cfg.vm.jitConfig.callStyle << std::endl
             << "Looping:      " << cfg.loopCount << " times" << std::endl
             << "Inline depth: " << cfg.vm.jitConfig.maxInlineDepth;
}

/// Parse CLI arguments and set up the config.
static bool parseArguments(RunConfig& cfg, const int argc, char* argv[]) {
  std::size_t i = 1;

  for (; i < argc; i++) {
    const char* arg = argv[i];

    if (strcmp(arg, "-help") == 0) {
      std::cout << usage << std::endl;
      exit(EXIT_SUCCESS);
    } else if (strcmp(arg, "-loop") == 0) {
      cfg.loopCount = atoi(argv[++i]);
    } else if (strcmp(arg, "-inline") == 0) {
      cfg.vm.jitConfig.maxInlineDepth = atoi(argv[++i]);
    } else if (strcmp(arg, "-verbose") == 0) {
      cfg.verbose = true;
      cfg.vm.verbose = true;
      cfg.vm.jitConfig.verbose = true;
    } else if (strcmp(arg, "-debug") == 0) {
      cfg.vm.debug = true;
      cfg.vm.jitConfig.debug = true;
    } else if (strcmp(arg, "-callstyle") == 0) {
      i += 1;
      auto callStyle = argv[i];
      if (strcmp("interpreter", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::interpreter;
      } else if (strcmp("direct", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::direct;
      } else if (strcmp("passparameter", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::passParameter;
      } else if (strcmp("operandstack", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::operandStack;
      }
    } else if (strcmp(arg, "--") == 0) {
      i++;
      break;
    } else if (strcmp(arg, "-") == 0) {
      std::cerr << "Unrecognized option: " << arg << std::endl;
      return false;
    } else {
      break;
    }
  }

  // positional

  if (i < argc) {
    cfg.moduleName = argv[i++];
  } else {
    std::cerr << "No module name given to b9run" << std::endl;
    return false;
  }

  return true;
}

static void run(const RunConfig& cfg) {
  b9::VirtualMachine vm{cfg.vm};
  vm.initialize();

  b9::DlLoader loader{true};
  auto module = loader.loadModule(cfg.moduleName);

  if (module->functions.size() == 0) {
    throw b9::DlException{"Empty module"};
  }

  vm.load(module);

  size_t functionIndex = module->findFunction(cfg.mainFunction);

  if (cfg.loopCount == 1) {
    b9::StackElement returnVal = vm.run(functionIndex);
    std::cout << cfg.mainFunction << " returned: " << returnVal << std::endl;
  } else {
    b9::StackElement returnVal;
    std::cout << "Running " << cfg.mainFunction << " " << cfg.loopCount
              << " times:" << std::endl;
    for (std::size_t i = 1; i <= cfg.loopCount; i++) {
      returnVal = vm.run(functionIndex);
      std::cout << "Return value of iteration " << i << ": " << returnVal
                << std::endl;
    }
  }
}

int main(int argc, char* argv[]) {
  RunConfig cfg;

  if (!parseArguments(cfg, argc, argv)) {
    std::cerr << usage << std::endl;
    exit(EXIT_FAILURE);
  }

  try {
    run(cfg);
  } catch (const b9::DlException& e) {
    std::cerr << "Failed to load module: " << e.what() << std::endl;
    exit(EXIT_FAILURE);
  } catch (const b9::FunctionNotFoundException& e) {
    std::cerr << "Failed to find function: " << e.what() << std::endl;
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}
<commit_msg>Add -function option / parse user specified arguments<commit_after>#include <b9.hpp>
#include <b9/loader.hpp>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

/// B9run's usage string. Printed when run with -help.
static const char* usage =
    "Usage: b9run [<option>...] [--] <module> [<main>]\n"
    "   Or: b9run -help\n"
    "Options:\n"
    "  -callstyle <style>: Set the calling style. One of:\n"
    "      interpreter:   Calls are made through the interpreter\n"
    "      direct:        Calls are made directly, but parameters are on the "
    "operand stack\n"
    "      passparameter: Direct calls, with parameters passed in CPU "
    "registers\n"
    "      operandstack:  Like passparam, but will keep the VM operand stack "
    "updated\n"
    "  -loop <n>:   Run the program <n> times\n"
    "  -inline <n>: Enable inlining\n"
    "  -debug:      Enable debug code\n"
    "  -verbose:    Run with verbose printing\n"
    "  -help:       Print this help message";

/// The b9run program's global configuration.
struct RunConfig {
  b9::VirtualMachineConfig vm;
  const char* moduleName = "";
  const char* mainFunction = "b9main";
  std::size_t loopCount = 1;
  bool verbose = false;
  std::vector<int> usrArgs;
};

/// Print the configuration summary.
std::ostream& operator<<(std::ostream& out, const RunConfig& cfg) {
  return out << "Loading:      " << cfg.moduleName << std::endl
             << "Executing:    " << cfg.mainFunction << std::endl
             << "Call Style:   " << cfg.vm.jitConfig.callStyle << std::endl
             << "Looping:      " << cfg.loopCount << " times" << std::endl
             << "Inline depth: " << cfg.vm.jitConfig.maxInlineDepth;
}

/// Parse CLI arguments and set up the config.
static bool parseArguments(RunConfig& cfg, const int argc, char* argv[]) {
  std::size_t i = 1;

  for (; i < argc; i++) {
    const char* arg = argv[i];

    if (strcmp(arg, "-help") == 0) {
      std::cout << usage << std::endl;
      exit(EXIT_SUCCESS);
    } else if (strcmp(arg, "-loop") == 0) {
      cfg.loopCount = atoi(argv[++i]);
    } else if (strcmp(arg, "-inline") == 0) {
      cfg.vm.jitConfig.maxInlineDepth = atoi(argv[++i]);
    } else if (strcmp(arg, "-verbose") == 0) {
      cfg.verbose = true;
      cfg.vm.verbose = true;
      cfg.vm.jitConfig.verbose = true;
    } else if (strcmp(arg, "-debug") == 0) {
      cfg.vm.debug = true;
      cfg.vm.jitConfig.debug = true;
    } else if (strcmp(arg, "-callstyle") == 0) {
      i += 1;
      auto callStyle = argv[i];
      if (strcmp("interpreter", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::interpreter;
      } else if (strcmp("direct", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::direct;
      } else if (strcmp("passparameter", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::passParameter;
      } else if (strcmp("operandstack", callStyle) == 0) {
        cfg.vm.jitConfig.callStyle = b9::CallStyle::operandStack;
      }
    } else if (strcmp(arg, "-function") == 0) {
      cfg.mainFunction=argv[++i];
    } else if (strcmp(arg, "--") == 0) {
      i++;
      break;
    } else if (strcmp(arg, "-") == 0) {
      std::cerr << "Unrecognized option: " << arg << std::endl;
      return false;
    } else {
      break;
    }
  }

  // check for user defined module
  if (i < argc) {
    cfg.moduleName = argv[i++];
  } else {
    std::cerr << "No module name given to b9run" << std::endl;
    return false;
  }

  // check for user defined arguments
  for (; i < argc; i++) {
    cfg.usrArgs.push_back(std::atoi(argv[i]));
  }

  return true;
}

static void run(const RunConfig& cfg) {
  b9::VirtualMachine vm{cfg.vm};
  vm.initialize();

  b9::DlLoader loader{true};
  auto module = loader.loadModule(cfg.moduleName);

  if (module->functions.size() == 0) {
    throw b9::DlException{"Empty module"};
  }

  vm.load(module);

  size_t functionIndex = module->findFunction(cfg.mainFunction);
  if (cfg.loopCount == 1) {
    b9::StackElement returnVal = vm.run(functionIndex);
    std::cout << cfg.mainFunction << " returned: " << returnVal << std::endl;
  } else {
    b9::StackElement returnVal;
    std::cout << "Running " << cfg.mainFunction << " " << cfg.loopCount
              << " times:" << std::endl;
    for (std::size_t i = 1; i <= cfg.loopCount; i++) {
      returnVal = vm.run(functionIndex);
      std::cout << "Return value of iteration " << i << ": " << returnVal
                << std::endl;
    }
  }
}

int main(int argc, char* argv[]) {
  RunConfig cfg;

  if (!parseArguments(cfg, argc, argv)) {
    std::cerr << usage << std::endl;
    exit(EXIT_FAILURE);
  }

  try {
    run(cfg);
  } catch (const b9::DlException& e) {
    std::cerr << "Failed to load module: " << e.what() << std::endl;
    exit(EXIT_FAILURE);
  } catch (const b9::FunctionNotFoundException& e) {
    std::cerr << "Failed to find function: " << e.what() << std::endl;
    exit(EXIT_FAILURE);
  }

  exit(EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>// 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.

#ifndef __STOUT_FLAGS_PARSE_HPP__
#define __STOUT_FLAGS_PARSE_HPP__

#include <sstream> // For istringstream.
#include <string>

#include <stout/bytes.hpp>
#include <stout/duration.hpp>
#include <stout/error.hpp>
#include <stout/json.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

#include <stout/os/read.hpp>

namespace flags {

template <typename T>
Try<T> parse(const std::string& value)
{
  T t;
  std::istringstream in(value);
  in >> t;
  if (!in.good() && !in.eof()) {
    return Error("Failed to convert into required type");
  }
  return t;
}

template <>
inline Try<std::string> parse(const std::string& value)
{
  return value;
}

template <>
inline Try<bool> parse(const std::string& value)
{
  if (value == "true" || value == "1") {
    return true;
  } else if (value == "false" || value == "0") {
    return false;
  }
  return Error("Expecting a boolean (e.g., true or false)");
}

template <>
inline Try<Duration> parse(const std::string& value)
{
  return Duration::parse(value);
}

template <>
inline Try<Bytes> parse(const std::string& value)
{
  return Bytes::parse(value);
}

template <>
inline Try<JSON::Object> parse(const std::string& value)
{
  // A value that already starts with 'file://' will properly be
  // loaded from the file and put into 'value' but if it starts with
  // '/' we need to explicitly handle it for backwards compatibility
  // reasons (because we used to handle it before we introduced the
  // 'fetch' mechanism for flags that first fetches the data from URIs
  // such as 'file://').
  if (strings::startsWith(value, "/")) {
    LOG(WARNING) << "Specifying an absolute filename to read a command line "
                    "option out of without using 'file:// is deprecated and "
                    "will be removed in a future release. Simply adding "
                    "'file://' to the beginning of the path should eliminate "
                    "this warning.";

    Try<std::string> read = os::read(value);
    if (read.isError()) {
      return Error("Error reading file '" + value + "': " + read.error());
    }
    return JSON::parse<JSON::Object>(read.get());
  }
  return JSON::parse<JSON::Object>(value);
}

template <>
inline Try<Path> parse(const std::string& value)
{
  return Path(value);
}

} // namespace flags {

#endif // __STOUT_FLAGS_PARSE_HPP__
<commit_msg>Added a missing include to a stout header.<commit_after>// 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.

#ifndef __STOUT_FLAGS_PARSE_HPP__
#define __STOUT_FLAGS_PARSE_HPP__

#include <sstream> // For istringstream.
#include <string>

#include <stout/bytes.hpp>
#include <stout/duration.hpp>
#include <stout/error.hpp>
#include <stout/json.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>

#include <stout/os/read.hpp>

namespace flags {

template <typename T>
Try<T> parse(const std::string& value)
{
  T t;
  std::istringstream in(value);
  in >> t;
  if (!in.good() && !in.eof()) {
    return Error("Failed to convert into required type");
  }
  return t;
}

template <>
inline Try<std::string> parse(const std::string& value)
{
  return value;
}

template <>
inline Try<bool> parse(const std::string& value)
{
  if (value == "true" || value == "1") {
    return true;
  } else if (value == "false" || value == "0") {
    return false;
  }
  return Error("Expecting a boolean (e.g., true or false)");
}

template <>
inline Try<Duration> parse(const std::string& value)
{
  return Duration::parse(value);
}

template <>
inline Try<Bytes> parse(const std::string& value)
{
  return Bytes::parse(value);
}

template <>
inline Try<JSON::Object> parse(const std::string& value)
{
  // A value that already starts with 'file://' will properly be
  // loaded from the file and put into 'value' but if it starts with
  // '/' we need to explicitly handle it for backwards compatibility
  // reasons (because we used to handle it before we introduced the
  // 'fetch' mechanism for flags that first fetches the data from URIs
  // such as 'file://').
  if (strings::startsWith(value, "/")) {
    LOG(WARNING) << "Specifying an absolute filename to read a command line "
                    "option out of without using 'file:// is deprecated and "
                    "will be removed in a future release. Simply adding "
                    "'file://' to the beginning of the path should eliminate "
                    "this warning.";

    Try<std::string> read = os::read(value);
    if (read.isError()) {
      return Error("Error reading file '" + value + "': " + read.error());
    }
    return JSON::parse<JSON::Object>(read.get());
  }
  return JSON::parse<JSON::Object>(value);
}

template <>
inline Try<Path> parse(const std::string& value)
{
  return Path(value);
}

} // namespace flags {

#endif // __STOUT_FLAGS_PARSE_HPP__
<|endoftext|>