<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.3  2003/11/26 16:20:37  neilg
 * more complete implementation of PSVIAttributeList; remove some problematic const-ness
 *
 * Revision 1.2  2003/11/06 15:30:04  neilg
 * first part of PSVI/schema component model implementation, thanks to David Cargill.  This covers setting the PSVIHandler on parser objects, as well as implementing XSNotation, XSSimpleTypeDefinition, XSIDCDefinition, and most of XSWildcard, XSComplexTypeDefinition, XSElementDeclaration, XSAttributeDeclaration and XSAttributeUse.
 *
 * Revision 1.1  2003/09/16 14:33:36  neilg
 * PSVI/schema component model classes, with Makefile/configuration changes necessary to build them
 *
 */

#if !defined(PSVIATTRIBUTEDERIVATION_LIST_HPP)
#define PSVIATTRIBUTEDERIVATION_LIST_HPP

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/psvi/PSVIAttribute.hpp>
#include <xercesc/util/ValueVectorOf.hpp>

XERCES_CPP_NAMESPACE_BEGIN

/**
 * A container for the PSVI contributions to attributes that occur
 * on a particular element.
 * This is always owned by the parser/validator from
 * which it is obtained.  The parser/validator will specify
 * under what conditions it may be relied upon to have meaningful contents.
 */

class XMLPARSER_EXPORT PSVIAttributeList : public XMemory
{
public:

    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    /** @name Constructors */
    //@{

    /**
      * The default constructor
      *
      * @param  manager     The configurable memory manager
      */
    PSVIAttributeList( MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);

    //@};

    /** @name Destructor */
    //@{
    ~PSVIAttributeList();
    //@}

    //---------------------
    /** @name PSVIAttributeList methods */

    //@{

    /*
     * Get the number of attributes whose PSVI contributions
     * are contained in this list.
     */
    const unsigned int getLength() const;

    /*
     * Get the PSVI contribution of attribute at position i
     * in this list.  Indeces start from 0.
     * @param index index from which the attribute PSVI contribution
     * is to come.
     * @return PSVIAttribute containing the attributes PSVI contributions;
     * null is returned if the index is out of range.
     */
    PSVIAttribute *getAttributePSVIAtIndex(const unsigned int index);

    /*
     * Get local part of attribute name at position index in the list.
     * Indeces start from 0.
     * @param index index from which the attribute name
     * is to come.
     * @return local part of the attribute's name; null is returned if the index
     * is out of range.
     */
    const XMLCh *getAttributeNameAtIndex(const unsigned int index);

    /*
     * Get namespace of attribute at position index in the list.
     * Indeces start from 0.
     * @param index index from which the attribute namespace
     * is to come.
     * @return namespace of the attribute;
     * null is returned if the index is out of range.
     */
    const XMLCh *getAttributeNamespaceAtIndex(const unsigned int index);

    /*
     * Get the PSVI contribution of attribute with given
     * local name and namespace.
     * @param attrName  local part of the attribute's name
     * @param attrNamespace  namespace of the attribute
     * @return null if the attribute PSVI does not exist
     */
    PSVIAttribute *getAttributePSVIByName(const XMLCh *attrName
                    , const XMLCh * attrNamespace);

    //@}

    //----------------------------------
    /** methods needed by implementation */

    //@{

    /**
      * returns a PSVI attribute of undetermined state and
      * makes that object part of the internal list.  Intended to be called
      * during validation of an element.
      */
    PSVIAttribute *getPSVIAttributeToFill();

    /**
      * reset the list
      */
    void reset();

    //@}

private:

    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    PSVIAttributeList(const PSVIAttributeList&);
    PSVIAttributeList & operator=(const PSVIAttributeList &);

    // -----------------------------------------------------------------------
    //  data members
    // -----------------------------------------------------------------------
    // fMemoryManager
    //  handler to provide dynamically-need memory
    // fAttrList
    //  list of PSVIAttributes contained by this object
    // fAttrPos
    //  current number of valid PSVIAttributes in fAttrList
    MemoryManager*                  fMemoryManager;
    ValueVectorOf<PSVIAttribute*>*  fAttrList;
    unsigned int                    fAttrPos;
};
inline PSVIAttributeList::~PSVIAttributeList()
{
    delete fAttrList;
}

inline PSVIAttribute *PSVIAttributeList::getPSVIAttributeToFill()
{
    PSVIAttribute *retAttr = 0;
    if(fAttrPos+1 == fAttrList->size())
    {
        retAttr = new (fMemoryManager)PSVIAttribute(fMemoryManager);
        fAttrList->addElement(retAttr);
    }
    else
    {
        retAttr = fAttrList->elementAt(fAttrPos);
    }
    fAttrPos++;
    return retAttr;
}

inline void PSVIAttributeList::reset()
{
    fAttrPos = 0;
}

XERCES_CPP_NAMESPACE_END

#endif
<commit_msg>fix for ArrayIndexOutOfBoundsException in PSVIAttributeList; thanks to Pete Lloyd<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.4  2003/12/02 16:21:41  neilg
 * fix for ArrayIndexOutOfBoundsException in PSVIAttributeList; thanks to Pete Lloyd
 *
 * Revision 1.3  2003/11/26 16:20:37  neilg
 * more complete implementation of PSVIAttributeList; remove some problematic const-ness
 *
 * Revision 1.2  2003/11/06 15:30:04  neilg
 * first part of PSVI/schema component model implementation, thanks to David Cargill.  This covers setting the PSVIHandler on parser objects, as well as implementing XSNotation, XSSimpleTypeDefinition, XSIDCDefinition, and most of XSWildcard, XSComplexTypeDefinition, XSElementDeclaration, XSAttributeDeclaration and XSAttributeUse.
 *
 * Revision 1.1  2003/09/16 14:33:36  neilg
 * PSVI/schema component model classes, with Makefile/configuration changes necessary to build them
 *
 */

#if !defined(PSVIATTRIBUTEDERIVATION_LIST_HPP)
#define PSVIATTRIBUTEDERIVATION_LIST_HPP

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/psvi/PSVIAttribute.hpp>
#include <xercesc/util/ValueVectorOf.hpp>

XERCES_CPP_NAMESPACE_BEGIN

/**
 * A container for the PSVI contributions to attributes that occur
 * on a particular element.
 * This is always owned by the parser/validator from
 * which it is obtained.  The parser/validator will specify
 * under what conditions it may be relied upon to have meaningful contents.
 */

class XMLPARSER_EXPORT PSVIAttributeList : public XMemory
{
public:

    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    /** @name Constructors */
    //@{

    /**
      * The default constructor
      *
      * @param  manager     The configurable memory manager
      */
    PSVIAttributeList( MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager);

    //@};

    /** @name Destructor */
    //@{
    ~PSVIAttributeList();
    //@}

    //---------------------
    /** @name PSVIAttributeList methods */

    //@{

    /*
     * Get the number of attributes whose PSVI contributions
     * are contained in this list.
     */
    const unsigned int getLength() const;

    /*
     * Get the PSVI contribution of attribute at position i
     * in this list.  Indeces start from 0.
     * @param index index from which the attribute PSVI contribution
     * is to come.
     * @return PSVIAttribute containing the attributes PSVI contributions;
     * null is returned if the index is out of range.
     */
    PSVIAttribute *getAttributePSVIAtIndex(const unsigned int index);

    /*
     * Get local part of attribute name at position index in the list.
     * Indeces start from 0.
     * @param index index from which the attribute name
     * is to come.
     * @return local part of the attribute's name; null is returned if the index
     * is out of range.
     */
    const XMLCh *getAttributeNameAtIndex(const unsigned int index);

    /*
     * Get namespace of attribute at position index in the list.
     * Indeces start from 0.
     * @param index index from which the attribute namespace
     * is to come.
     * @return namespace of the attribute;
     * null is returned if the index is out of range.
     */
    const XMLCh *getAttributeNamespaceAtIndex(const unsigned int index);

    /*
     * Get the PSVI contribution of attribute with given
     * local name and namespace.
     * @param attrName  local part of the attribute's name
     * @param attrNamespace  namespace of the attribute
     * @return null if the attribute PSVI does not exist
     */
    PSVIAttribute *getAttributePSVIByName(const XMLCh *attrName
                    , const XMLCh * attrNamespace);

    //@}

    //----------------------------------
    /** methods needed by implementation */

    //@{

    /**
      * returns a PSVI attribute of undetermined state and
      * makes that object part of the internal list.  Intended to be called
      * during validation of an element.
      */
    PSVIAttribute *getPSVIAttributeToFill();

    /**
      * reset the list
      */
    void reset();

    //@}

private:

    // -----------------------------------------------------------------------
    //  Unimplemented constructors and operators
    // -----------------------------------------------------------------------
    PSVIAttributeList(const PSVIAttributeList&);
    PSVIAttributeList & operator=(const PSVIAttributeList &);

    // -----------------------------------------------------------------------
    //  data members
    // -----------------------------------------------------------------------
    // fMemoryManager
    //  handler to provide dynamically-need memory
    // fAttrList
    //  list of PSVIAttributes contained by this object
    // fAttrPos
    //  current number of valid PSVIAttributes in fAttrList
    MemoryManager*                  fMemoryManager;
    ValueVectorOf<PSVIAttribute*>*  fAttrList;
    unsigned int                    fAttrPos;
};
inline PSVIAttributeList::~PSVIAttributeList()
{
    delete fAttrList;
}

inline PSVIAttribute *PSVIAttributeList::getPSVIAttributeToFill()
{
    PSVIAttribute *retAttr = 0;
    if(fAttrPos == fAttrList->size())
    {
        retAttr = new (fMemoryManager)PSVIAttribute(fMemoryManager);
        fAttrList->addElement(retAttr);
    }
    else
    {
        retAttr = fAttrList->elementAt(fAttrPos);
    }
    fAttrPos++;
    return retAttr;
}

inline void PSVIAttributeList::reset()
{
    fAttrPos = 0;
}

XERCES_CPP_NAMESPACE_END

#endif
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.11  2002/12/12 16:53:25  peiyongz
 * Message file name changed.
 *
 * Revision 1.10  2002/12/06 16:29:17  peiyongz
 * $XERCESCROOT/msg created as home directory for message files, and
 * set default locale.
 *
 * Revision 1.9  2002/12/04 18:11:23  peiyongz
 * use $XERCESCROOT to search for icu resource bundle if XERCESC_NLS_HOME
 * undefined
 *
 * Revision 1.8  2002/11/20 20:28:17  peiyongz
 * fix to warning C4018: '>' : signed/unsigned mismatch
 *
 * Revision 1.7  2002/11/12 17:27:49  tng
 * DOM Message: add new domain for DOM Messages.
 *
 * Revision 1.6  2002/11/04 22:24:43  peiyongz
 * Locale setting for message loader
 *
 * Revision 1.5  2002/11/04 15:10:40  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/10/10 21:07:55  peiyongz
 * load resource files using environement vars and base name
 *
 * Revision 1.3  2002/10/02 17:08:50  peiyongz
 * XMLString::equals() to replace XMLString::compareString()
 *
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/Janitor.hpp>
#include "ICUMsgLoader.hpp"
#include "unicode/uloc.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fLocaleBundle(0)
,fDomainBundle(0)
{
    /***
	    Validate msgDomain
    ***/
    if (!XMLString::equals(msgDomain, XMLUni::fgXMLErrDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgExceptDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgXMLDOMMsgDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgValidityDomain)   )
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    /***
	Resolve domainName
    ***/
    int     index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
    char*   domainName = XMLString::transcode(&(msgDomain[index + 1]));
    ArrayJanitor<char> jan1(domainName);

    /***
	Resolve location

	REVISIT: another approach would be: through some system API
	         which returns the directory of the XercescLib and
	         that directory would be used to locate the resource bundle
    ***/
    char locationBuf[1024];
    memset(locationBuf, 0, sizeof locationBuf);
    char *nlsHome = getenv("XERCESC_NLS_HOME");

    if (nlsHome)
    {
    	strcpy(locationBuf, nlsHome);
        strcat(locationBuf, U_FILE_SEP_STRING);
    }
    else
    {
        char *altHome = getenv("XERCESCROOT");
        if (altHome)
        {
            strcpy(locationBuf, altHome);
            strcat(locationBuf, U_FILE_SEP_STRING);
            strcat(locationBuf, "msg");
            strcat(locationBuf, U_FILE_SEP_STRING);
        }
    }

    /***
	Open the locale-specific resource bundle
    ***/
    strcat(locationBuf, "XercesMessages");
    UErrorCode err = U_ZERO_ERROR;
    uloc_setDefault("en_US", &err);   // in case user-specified locale unavailable
    err = U_ZERO_ERROR;
    fLocaleBundle = ures_open(locationBuf, XMLMsgLoader::getLocale(), &err);
    if (!U_SUCCESS(err) || fLocaleBundle == NULL)
    {
         XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

    /***
	Open the domain specific resource bundle within
	the locale-specific resource bundle
    ***/
    err = U_ZERO_ERROR;
    fDomainBundle = ures_getByKey(fLocaleBundle, domainName, NULL, &err);
    if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fLocaleBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > (int32_t)maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}

XERCES_CPP_NAMESPACE_END
<commit_msg>Re-prioritize search order for error message files.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.12  2003/02/17 19:56:03  peiyongz
 * Re-prioritize search order for error message files.
 *
 * Revision 1.11  2002/12/12 16:53:25  peiyongz
 * Message file name changed.
 *
 * Revision 1.10  2002/12/06 16:29:17  peiyongz
 * $XERCESCROOT/msg created as home directory for message files, and
 * set default locale.
 *
 * Revision 1.9  2002/12/04 18:11:23  peiyongz
 * use $XERCESCROOT to search for icu resource bundle if XERCESC_NLS_HOME
 * undefined
 *
 * Revision 1.8  2002/11/20 20:28:17  peiyongz
 * fix to warning C4018: '>' : signed/unsigned mismatch
 *
 * Revision 1.7  2002/11/12 17:27:49  tng
 * DOM Message: add new domain for DOM Messages.
 *
 * Revision 1.6  2002/11/04 22:24:43  peiyongz
 * Locale setting for message loader
 *
 * Revision 1.5  2002/11/04 15:10:40  tng
 * C++ Namespace Support.
 *
 * Revision 1.4  2002/10/10 21:07:55  peiyongz
 * load resource files using environement vars and base name
 *
 * Revision 1.3  2002/10/02 17:08:50  peiyongz
 * XMLString::equals() to replace XMLString::compareString()
 *
 * Revision 1.2  2002/09/30 22:20:40  peiyongz
 * Build with ICU MsgLoader
 *
 * Revision 1.1.1.1  2002/02/01 22:22:19  peiyongz
 * sane_include
 *
 * Revision 1.7  2002/01/21 14:52:25  tng
 * [Bug 5847] ICUMsgLoader can't be compiled with gcc 3.0.3 and ICU2.  And also fix the memory leak introduced by Bug 2730 fix.
 *
 * Revision 1.6  2001/11/01 23:39:18  jasons
 * 2001-11-01  Jason E. Stewart  <jason@openinformatics.com>
 *
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.hpp (Repository):
 * 	* src/util/MsgLoaders/ICU/ICUMsgLoader.cpp (Repository):
 * 	Updated to compile with ICU-1.8.1
 *
 * Revision 1.5  2000/03/02 19:55:14  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.4  2000/02/06 07:48:21  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.3  2000/01/19 00:58:38  roddey
 * Update to support new ICU 1.4 release.
 *
 * Revision 1.2  1999/11/19 21:24:03  aruna1
 * incorporated ICU 1.3.1 related changes int he file
 *
 * Revision 1.1.1.1  1999/11/09 01:07:23  twl
 * Initial checkin
 *
 * Revision 1.4  1999/11/08 20:45:26  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/Janitor.hpp>
#include "ICUMsgLoader.hpp"
#include "unicode/uloc.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  Local static methods
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
//  Public Constructors and Destructor
// ---------------------------------------------------------------------------
ICUMsgLoader::ICUMsgLoader(const XMLCh* const  msgDomain)
:fLocaleBundle(0)
,fDomainBundle(0)
{
    /***
	    Validate msgDomain
    ***/
    if (!XMLString::equals(msgDomain, XMLUni::fgXMLErrDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgExceptDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgXMLDOMMsgDomain)    &&
        !XMLString::equals(msgDomain, XMLUni::fgValidityDomain)   )
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_UnknownMsgDomain);
    }

    /***
	Resolve domainName
    ***/
    int     index = XMLString::lastIndexOf(msgDomain, chForwardSlash);
    char*   domainName = XMLString::transcode(&(msgDomain[index + 1]));
    ArrayJanitor<char> jan1(domainName);

    /***
        Location resolution priority

         1. XMLMsgLoader::getNLSHome(), set by user through
            XMLPlatformUtils::Initialize(), which provides user-specified
            location where the message loader shall retrieve error messages.

         2. envrionment var: XERCESC_NLS_HOME

         3. path $XERCESCROOT/msg
    ***/

    char locationBuf[1024];
    memset(locationBuf, 0, sizeof locationBuf);
    const char const *nlsHome = XMLMsgLoader::getNLSHome();

    if (nlsHome)
    {
    	strcpy(locationBuf, nlsHome);
        strcat(locationBuf, U_FILE_SEP_STRING);
    }
    else
    {
        nlsHome = getenv("XERCESC_NLS_HOME");
        if (nlsHome)
        {
            strcpy(locationBuf, nlsHome);
            strcat(locationBuf, U_FILE_SEP_STRING);
        }
        else
        {
            nlsHome = getenv("XERCESCROOT");
            if (nlsHome)
            {
                strcpy(locationBuf, nlsHome);
                strcat(locationBuf, U_FILE_SEP_STRING);
                strcat(locationBuf, "msg");
                strcat(locationBuf, U_FILE_SEP_STRING);
            }
            else
            {
                /***
                 leave it to ICU to decide where to search
                 for the error message.
                 ***/
            }
        }
    }

    /***
	Open the locale-specific resource bundle
    ***/
    strcat(locationBuf, "XercesMessages");
    UErrorCode err = U_ZERO_ERROR;
    uloc_setDefault("en_US", &err);   // in case user-specified locale unavailable
    err = U_ZERO_ERROR;
    fLocaleBundle = ures_open(locationBuf, XMLMsgLoader::getLocale(), &err);
    if (!U_SUCCESS(err) || fLocaleBundle == NULL)
    {
         XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

    /***
	Open the domain specific resource bundle within
	the locale-specific resource bundle
    ***/
    err = U_ZERO_ERROR;
    fDomainBundle = ures_getByKey(fLocaleBundle, domainName, NULL, &err);
    if (!U_SUCCESS(err) || fDomainBundle == NULL)
    {
        XMLPlatformUtils::panic(XMLPlatformUtils::Panic_CantLoadMsgDomain);
    }

}

ICUMsgLoader::~ICUMsgLoader()
{
    ures_close(fDomainBundle);
    ures_close(fLocaleBundle);
}

// ---------------------------------------------------------------------------
//  Implementation of the virtual message loader API
// ---------------------------------------------------------------------------
bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                          ,         XMLCh* const            toFill
                          , const   unsigned int            maxChars)
{
    UErrorCode   err = U_ZERO_ERROR;
    int32_t      strLen = 0;

    // Assuming array format
    const UChar *name = ures_getStringByIndex(fDomainBundle, (int32_t)msgToLoad-1, &strLen, &err);

    if (!U_SUCCESS(err) || (name == NULL))
    {
        return false;
    }

    int retStrLen = strLen > (int32_t)maxChars ? maxChars : strLen;

    if (sizeof(UChar)==sizeof(XMLCh))
    {
        XMLString::moveChars(toFill, (XMLCh*)name, retStrLen);
        toFill[retStrLen] = (XMLCh) 0;
    }
    else
    {
        XMLCh* retStr = toFill;
        const UChar *srcPtr = name;

        while (retStrLen--)
           *retStr++ = *srcPtr++;

        *retStr = 0;
    }

    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const XMLCh* const            repText1
                            , const XMLCh* const            repText2
                            , const XMLCh* const            repText3
                            , const XMLCh* const            repText4)
{
    // Call the other version to load up the message
    if (!loadMsg(msgToLoad, toFill, maxChars))
        return false;

    // And do the token replacement
    XMLString::replaceTokens(toFill, maxChars, repText1, repText2, repText3, repText4);
    return true;
}

bool ICUMsgLoader::loadMsg( const   XMLMsgLoader::XMLMsgId  msgToLoad
                            ,       XMLCh* const            toFill
                            , const unsigned int           maxChars
                            , const char* const             repText1
                            , const char* const             repText2
                            , const char* const             repText3
                            , const char* const             repText4)
{
    //
    //  Transcode the provided parameters and call the other version,
    //  which will do the replacement work.
    //
    XMLCh* tmp1 = 0;
    XMLCh* tmp2 = 0;
    XMLCh* tmp3 = 0;
    XMLCh* tmp4 = 0;

    bool bRet = false;
    if (repText1)
        tmp1 = XMLString::transcode(repText1);
    if (repText2)
        tmp2 = XMLString::transcode(repText2);
    if (repText3)
        tmp3 = XMLString::transcode(repText3);
    if (repText4)
        tmp4 = XMLString::transcode(repText4);

    bRet = loadMsg(msgToLoad, toFill, maxChars, tmp1, tmp2, tmp3, tmp4);

    if (tmp1)
        delete [] tmp1;
    if (tmp2)
        delete [] tmp2;
    if (tmp3)
        delete [] tmp3;
    if (tmp4)
        delete [] tmp4;

    return bRet;
}

XERCES_CPP_NAMESPACE_END
<|endoftext|>


<commit_before>#include <type_traits>
#include "Channel_BEC.hpp"

using namespace aff3ct::module;

template <typename R>
Channel_BEC<R>
::Channel_BEC(const int N, const int seed, const tools::Noise<R>& noise, const int n_frames)
: Channel<R>(N, noise, n_frames), uni_dist((R)0, (R)1)
{
	const std::string name = "Channel_BEC";
	this->set_name(name);

	mipp::vector<int> seeds(mipp::nElReg<int>());
	for (auto i = 0; i < mipp::nElReg<int>(); i++)
		seeds[i] = mt19937.rand();
	mt19937_simd.seed(seeds.data());

	rd_engine.seed(seed);
}

template <typename R>
Channel_BEC<R>
::~Channel_BEC()
{
}

template <typename R>
mipp::Reg<R> Channel_BEC<R>
::get_random_simd()
{
	throw tools::runtime_error(__FILE__, __LINE__, __func__, "The MT19937 random generator does not support this type.");
}

template <typename R>
R Channel_BEC<R>
::get_random()
{
	return this->uni_dist(this->rd_engine);
}

namespace aff3ct
{
namespace module
{
template <>
mipp::Reg<float> Channel_BEC<float>
::get_random_simd()
{
	// return a vector of numbers between [0,1]
	return mt19937_simd.randf_cc();
}
}
}

namespace aff3ct
{
namespace module
{
template <>
float Channel_BEC<float>
::get_random()
{
	// return a number between [0,1]
	return mt19937.randf_cc();
}
}
}

template <typename R>
void Channel_BEC<R>
::_add_noise(const R *X_N, R *Y_N, const int frame_id)
{
	const auto erasure_probability = this->n.get_ep();
	const auto erased_value        = std::numeric_limits<R>::infinity();

	const mipp::Reg<R> r_erased = erased_value;
	const mipp::Reg<R> r_ep     = erasure_probability;

	const auto vec_loop_size = (std::is_same<R,float>::value) ? ((this->N / mipp::nElReg<R>()) * mipp::nElReg<R>()) : 0;

	for (auto i = 0; i < vec_loop_size; i += mipp::nElReg<R>())
	{
		const auto r_in    = mipp::Reg<R>(X_N + i);
		const auto r_draw  = get_random_simd();
		const auto r_out   = mipp::blend(r_erased, r_in, r_draw <= r_ep);
		r_out.store(Y_N + i);
	}

	for (auto i = vec_loop_size; i < this->N; i++)
		Y_N[i] = get_random() <= erasure_probability ? erased_value : X_N[i];
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template class aff3ct::module::Channel_BEC<R_32>;
template class aff3ct::module::Channel_BEC<R_64>;
#else
template class aff3ct::module::Channel_BEC<R>;
#endif
// ==================================================================================== explicit template instantiation
<commit_msg>add using namespace aff3ct<commit_after>#include <type_traits>
#include "Channel_BEC.hpp"

using namespace aff3ct;
using namespace aff3ct::module;

template <typename R>
Channel_BEC<R>
::Channel_BEC(const int N, const int seed, const tools::Noise<R>& noise, const int n_frames)
: Channel<R>(N, noise, n_frames), uni_dist((R)0, (R)1)
{
	const std::string name = "Channel_BEC";
	this->set_name(name);

	mipp::vector<int> seeds(mipp::nElReg<int>());
	for (auto i = 0; i < mipp::nElReg<int>(); i++)
		seeds[i] = mt19937.rand();
	mt19937_simd.seed(seeds.data());

	rd_engine.seed(seed);
}

template <typename R>
Channel_BEC<R>
::~Channel_BEC()
{
}

template <typename R>
mipp::Reg<R> Channel_BEC<R>
::get_random_simd()
{
	throw tools::runtime_error(__FILE__, __LINE__, __func__, "The MT19937 random generator does not support this type.");
}

template <typename R>
R Channel_BEC<R>
::get_random()
{
	return this->uni_dist(this->rd_engine);
}

namespace aff3ct
{
namespace module
{
template <>
mipp::Reg<float> Channel_BEC<float>
::get_random_simd()
{
	// return a vector of numbers between [0,1]
	return mt19937_simd.randf_cc();
}
}
}

namespace aff3ct
{
namespace module
{
template <>
float Channel_BEC<float>
::get_random()
{
	// return a number between [0,1]
	return mt19937.randf_cc();
}
}
}

template <typename R>
void Channel_BEC<R>
::_add_noise(const R *X_N, R *Y_N, const int frame_id)
{
	const auto erasure_probability = this->n.get_ep();
	const auto erased_value        = std::numeric_limits<R>::infinity();

	const mipp::Reg<R> r_erased = erased_value;
	const mipp::Reg<R> r_ep     = erasure_probability;

	const auto vec_loop_size = (std::is_same<R,float>::value) ? ((this->N / mipp::nElReg<R>()) * mipp::nElReg<R>()) : 0;

	for (auto i = 0; i < vec_loop_size; i += mipp::nElReg<R>())
	{
		const auto r_in    = mipp::Reg<R>(X_N + i);
		const auto r_draw  = get_random_simd();
		const auto r_out   = mipp::blend(r_erased, r_in, r_draw <= r_ep);
		r_out.store(Y_N + i);
	}

	for (auto i = vec_loop_size; i < this->N; i++)
		Y_N[i] = get_random() <= erasure_probability ? erased_value : X_N[i];
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template class aff3ct::module::Channel_BEC<R_32>;
template class aff3ct::module::Channel_BEC<R_64>;
#else
template class aff3ct::module::Channel_BEC<R>;
#endif
// ==================================================================================== explicit template instantiation
<|endoftext|>


<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "pal_config.h"
#include "pal_mount.h"
#include "pal_utilities.h"
#include <assert.h>
#include <string.h>
#include <errno.h>

// Check if we should use getmntinfo or /proc/mounts
#if HAVE_MNTINFO
#include <sys/mount.h>
#else
#include <sys/statfs.h>
#include <mntent.h>
#define STRING_BUFFER_SIZE 8192
#endif

static int32_t GetMountInfo(MountPointFound onFound)
{
#if HAVE_MNTINFO
    // getmntinfo returns pointers to OS-internal structs, so we don't need to worry about free'ing the object
#if HAVE_STATFS
    struct statfs* mounts = nullptr;
#else
    struct statvfs* mounts = nullptr;
#endif
    int count = getmntinfo(&mounts, 0);
    for (int32_t i = 0; i < count; i++)
    {
        onFound(mounts[i].f_mntonname);
    }

    return 0;
}

#else

    int result = -1;
    FILE* fp = setmntent("/proc/mounts", MNTOPT_RO);
    if (fp != nullptr)
    {
        // The _r version of getmntent needs all buffers to be passed in; however, we don't know how big of a string
        // buffer we will need, so pick something that seems like it will be big enough.
        char buffer[STRING_BUFFER_SIZE] = {};
        mntent entry;
        while (getmntent_r(fp, &entry, buffer, STRING_BUFFER_SIZE) != nullptr)
        {
            onFound(entry.mnt_dir);
        }

        result = endmntent(fp);
        assert(result == 1); // documented to always return 1
        result =
            0; // We need to standardize a success return code between our implementations, so settle on 0 for success
    }

    return result;
}

#endif

extern "C" int32_t SystemNative_GetAllMountPoints(MountPointFound onFound)
{
    return GetMountInfo(onFound);
}

extern "C" int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi)
{
    assert(name != nullptr);
    assert(mpi != nullptr);

#if HAVE_STATFS
    struct statfs stats = {};
    int result = statfs(name, &stats);
#else
    struct statvfs stats = {};
    int result = statvfs(name, &stats);
#endif
    if (result == 0)
    {
        // Note that these have signed integer types on some platforms but musn't be negative.
        // Also, upcast here (some platforms have smaller types) to 64-bit before multiplying to
        // avoid overflow.
        uint64_t bsize = UnsignedCast(stats.f_bsize);
        uint64_t bavail = UnsignedCast(stats.f_bavail);
        uint64_t bfree = UnsignedCast(stats.f_bfree);
        uint64_t blocks = UnsignedCast(stats.f_blocks);

        mpi->AvailableFreeSpace = bsize * bavail;
        mpi->TotalFreeSpace = bsize * bfree;
        mpi->TotalSize = bsize * blocks;
    }
    else
    {
        *mpi = {};
    }

    return result;
}

extern "C" int32_t
SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType)
{
    assert((formatNameBuffer != nullptr) && (formatType != nullptr));
    assert(bufferLength > 0);

#if HAVE_STATFS
    struct statfs stats;
    int result = statfs(name, &stats);
#else
    struct statvfs stats;
    int result = statvfs(name, &stats);
#endif
    if (result == 0)
    {

#if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME
#ifdef VFS_NAMELEN
        if (bufferLength < VFS_NAMELEN)
#else
        if (bufferLength < MFSNAMELEN)
#endif
        {
            result = ERANGE;
            *formatType = 0;
        }
        else
        {
            SafeStringCopy(formatNameBuffer, bufferLength, stats.f_fstypename);
            *formatType = -1;
        }
#else
        assert(formatType != nullptr);
        *formatType = stats.f_type;
        SafeStringCopy(formatNameBuffer, bufferLength, "");
#endif
    }
    else
    {
        *formatType = 0;
    }

    return result;
}
<commit_msg>Use cast helper for statfs::f_type In musl-libc, `statfs::f_type` is defined as `unsigned long`. This change makes use of `SignedCast` helper to overcome the disparity.<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#include "pal_config.h"
#include "pal_mount.h"
#include "pal_utilities.h"
#include <assert.h>
#include <string.h>
#include <errno.h>

// Check if we should use getmntinfo or /proc/mounts
#if HAVE_MNTINFO
#include <sys/mount.h>
#else
#include <sys/statfs.h>
#include <mntent.h>
#define STRING_BUFFER_SIZE 8192
#endif

static int32_t GetMountInfo(MountPointFound onFound)
{
#if HAVE_MNTINFO
    // getmntinfo returns pointers to OS-internal structs, so we don't need to worry about free'ing the object
#if HAVE_STATFS
    struct statfs* mounts = nullptr;
#else
    struct statvfs* mounts = nullptr;
#endif
    int count = getmntinfo(&mounts, 0);
    for (int32_t i = 0; i < count; i++)
    {
        onFound(mounts[i].f_mntonname);
    }

    return 0;
}

#else

    int result = -1;
    FILE* fp = setmntent("/proc/mounts", MNTOPT_RO);
    if (fp != nullptr)
    {
        // The _r version of getmntent needs all buffers to be passed in; however, we don't know how big of a string
        // buffer we will need, so pick something that seems like it will be big enough.
        char buffer[STRING_BUFFER_SIZE] = {};
        mntent entry;
        while (getmntent_r(fp, &entry, buffer, STRING_BUFFER_SIZE) != nullptr)
        {
            onFound(entry.mnt_dir);
        }

        result = endmntent(fp);
        assert(result == 1); // documented to always return 1
        result =
            0; // We need to standardize a success return code between our implementations, so settle on 0 for success
    }

    return result;
}

#endif

extern "C" int32_t SystemNative_GetAllMountPoints(MountPointFound onFound)
{
    return GetMountInfo(onFound);
}

extern "C" int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi)
{
    assert(name != nullptr);
    assert(mpi != nullptr);

#if HAVE_STATFS
    struct statfs stats = {};
    int result = statfs(name, &stats);
#else
    struct statvfs stats = {};
    int result = statvfs(name, &stats);
#endif
    if (result == 0)
    {
        // Note that these have signed integer types on some platforms but musn't be negative.
        // Also, upcast here (some platforms have smaller types) to 64-bit before multiplying to
        // avoid overflow.
        uint64_t bsize = UnsignedCast(stats.f_bsize);
        uint64_t bavail = UnsignedCast(stats.f_bavail);
        uint64_t bfree = UnsignedCast(stats.f_bfree);
        uint64_t blocks = UnsignedCast(stats.f_blocks);

        mpi->AvailableFreeSpace = bsize * bavail;
        mpi->TotalFreeSpace = bsize * bfree;
        mpi->TotalSize = bsize * blocks;
    }
    else
    {
        *mpi = {};
    }

    return result;
}

extern "C" int32_t
SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType)
{
    assert((formatNameBuffer != nullptr) && (formatType != nullptr));
    assert(bufferLength > 0);

#if HAVE_STATFS
    struct statfs stats;
    int result = statfs(name, &stats);
#else
    struct statvfs stats;
    int result = statvfs(name, &stats);
#endif
    if (result == 0)
    {

#if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME
#ifdef VFS_NAMELEN
        if (bufferLength < VFS_NAMELEN)
#else
        if (bufferLength < MFSNAMELEN)
#endif
        {
            result = ERANGE;
            *formatType = 0;
        }
        else
        {
            SafeStringCopy(formatNameBuffer, bufferLength, stats.f_fstypename);
            *formatType = -1;
        }
#else
        assert(formatType != nullptr);
        *formatType = SignedCast(stats.f_type);
        SafeStringCopy(formatNameBuffer, bufferLength, "");
#endif
    }
    else
    {
        *formatType = 0;
    }

    return result;
}
<|endoftext|>


<commit_before>#include <cstdlib>

#include <QString>
#include <QLabel>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QApplication>

#include "qt_window.hpp"

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  QWidget *window = new QWidget();
  setMainWindow(window);

  QVBoxLayout *main_layout = new QVBoxLayout();

  QString text = "";
  for (int i = 1; i < argc; i++) {
    if (i > 1) {
      text.append(" ");
    }
    text.append(argv[i]);
  }

  QLabel *label = new QLabel(text);
  label->setAlignment(Qt::AlignTop);
  main_layout->addWidget(label);

  QPushButton *btn = new QPushButton();
#ifdef __aarch64__
  btn->setText("Reboot");
  QObject::connect(btn, &QPushButton::released, [=]() {
    std::system("sudo reboot");
  });
#else
  btn->setText("Exit");
  QObject::connect(btn, SIGNAL(released()), &a, SLOT(quit()));
#endif
  main_layout->addWidget(btn);

  window->setLayout(main_layout);
  window->setStyleSheet(R"(
    QWidget {
      margin: 60px;
      background-color: black;
    }
    QLabel {
      color: white;
      font-size: 60px;
    }
    QPushButton {
      color: white;
      font-size: 50px;
      padding: 60px;
      margin-left: 1500px;
      border-color: white;
      border-width: 2px;
      border-style: solid;
      border-radius: 20px;
    }
  )");

  return a.exec();
}
<commit_msg>new and improved text window<commit_after>#include <QLabel>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QApplication>

#include "qt_window.hpp"

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  QWidget window;
  setMainWindow(&window);

  QVBoxLayout *layout = new QVBoxLayout();
  layout->setContentsMargins(30, 30, 30, 30);

  // TODO: make this scroll
  layout->addWidget(new QLabel(argv[1]), 0, Qt::AlignTop);

  QPushButton *btn = new QPushButton();
#ifdef __aarch64__
  btn->setText("Reboot");
  QObject::connect(btn, &QPushButton::released, [=]() {
    std::system("sudo reboot");
  });
#else
  btn->setText("Exit");
  QObject::connect(btn, SIGNAL(released()), &a, SLOT(quit()));
#endif
  layout->addWidget(btn, 0, Qt::AlignRight);

  window.setLayout(layout);
  window.setStyleSheet(R"(
    * {
      color: white;
      background-color: black;
      font-size: 60px;
    }
    QPushButton {
      padding: 50px;
      padding-right: 100px;
      padding-left: 100px;
      border: 2px solid white;
      border-radius: 20px;
    }
  )");

  return a.exec();
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017 Chris Feyerchak
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <iostream>
#include <unistd.h>
#include <math.h>
#include <algorithm>

#include <cfeyer/cpp_lib_dwf/Library.hpp>
#include <cfeyer/cpp_api_dwf/Device_Enumerator_Interface.hpp>
#include <cfeyer/cpp_api_dwf/Device_Interface.hpp>
#include <cfeyer/cpp_api_dwf/Open_Device_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Channels_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Channel_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Carrier_Component_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Waveform_Shape_Enum.hpp>

int main( int argc, char * argv[] )
{
   ::cfeyer::cpp_lib_dwf::Library cpp_lib_dwf;

   ::cfeyer::cpp_api_dwf::Device_Enumerator_Interface & device_enumerator = cpp_lib_dwf.get_device_enumerator();

   const int device_index = 0;
   ::cfeyer::cpp_api_dwf::Device_Interface & device =
         device_enumerator.get_device( device_index );

   std::cerr << "name: " << device.get_name() << "\n"
             << "user: "<< device.get_user_name() << "\n"
             << "serial: " << device.get_serial_number() << "\n"
             << "busy: " << device.is_busy()
             << std::endl;

   ::cfeyer::cpp_api_dwf::Open_Device_Interface * p_open_device = device.open();

   ::cfeyer::cpp_api_dwf::analog_output::Channel_Interface & ao1 =
      p_open_device->get_analog_outputs().get_channel(0);

   ::cfeyer::cpp_api_dwf::analog_output::Carrier_Component_Interface & ao1_carrier =
      *(ao1.get_carrier_component());

   ao1_carrier.enable();
   ao1_carrier.set_waveform_shape( ::cfeyer::cpp_api_dwf::analog_output::Waveform_Shape::play );

   // Play f(t) = sin(t/(2*pi)) for t=[0,1) seconds at 500,000 samples / sec (500,000 samples total)
   const int sample_count = 500000;
   double samples[sample_count] = {0.0};

   const double t_initial_sec = 0.0;
   const double t_final_sec = 1.0;
   const double t_sample = (t_final_sec - t_initial_sec) / sample_count;
   const double pi = 3.14159;

   for( int n = 0; n < sample_count; n++ )
   {
      double t = static_cast<double>(n) * t_sample;
      samples[n] = sin( 2.0 * pi * t );
   }

   ao1_carrier.set_frequency_hz( 500e3 );
   ao1_carrier.set_amplitude_volts( 2.0 );

   int sent_samples_count = 0;
   int next_send_samples_count = 0;

   //next_send_samples_count = std::min( ao1_carrier.get_max_data_samples(), sample_count - sent_samples_count );
   //std::cout << "set_data( " << next_send_samples_count << " )" << std::endl;
   //ao1_carrier.set_data( &samples[sent_samples_count], next_send_samples_count );
   //sent_samples_count += next_send_samples_count;

   ao1.start();

   while( sample_count > sent_samples_count )
   {
      int free_sample_count = 0;
      int lost_sample_count = 0;
      int corrupted_sample_count = 0;

      ao1.get_status();
      ao1_carrier.get_play_status( free_sample_count, lost_sample_count, corrupted_sample_count );

      if( lost_sample_count > 0 )
      {
         std::cout << "Lost " << lost_sample_count << " samples" << std::endl;
      }

      if( corrupted_sample_count > 0 )
      {
         std::cout << "Corrupted " << corrupted_sample_count << " samples" << std::endl;
      }

      next_send_samples_count = std::min( free_sample_count, sample_count - sent_samples_count );

      if( next_send_samples_count > 0 )
      {
//         std::cout << "write_play_samples( " << next_send_samples_count << " )" << std::endl;
         ao1_carrier.write_play_samples( &samples[sent_samples_count], next_send_samples_count );
      }

      sent_samples_count += next_send_samples_count;
   }

   delete p_open_device;
   p_open_device = 0;

   return 0;
}
<commit_msg>Pre-buffer data before starting play<commit_after>// MIT License
//
// Copyright (c) 2017 Chris Feyerchak
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <iostream>
#include <unistd.h>
#include <math.h>
#include <algorithm>

#include <cfeyer/cpp_lib_dwf/Library.hpp>
#include <cfeyer/cpp_api_dwf/Device_Enumerator_Interface.hpp>
#include <cfeyer/cpp_api_dwf/Device_Interface.hpp>
#include <cfeyer/cpp_api_dwf/Open_Device_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Channels_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Channel_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Carrier_Component_Interface.hpp>
#include <cfeyer/cpp_api_dwf/analog_output/Waveform_Shape_Enum.hpp>

int main( int argc, char * argv[] )
{
   ::cfeyer::cpp_lib_dwf::Library cpp_lib_dwf;

   ::cfeyer::cpp_api_dwf::Device_Enumerator_Interface & device_enumerator = cpp_lib_dwf.get_device_enumerator();

   const int device_index = 0;
   ::cfeyer::cpp_api_dwf::Device_Interface & device =
         device_enumerator.get_device( device_index );

   std::cerr << "name: " << device.get_name() << "\n"
             << "user: "<< device.get_user_name() << "\n"
             << "serial: " << device.get_serial_number() << "\n"
             << "busy: " << device.is_busy()
             << std::endl;

   ::cfeyer::cpp_api_dwf::Open_Device_Interface * p_open_device = device.open();

   ::cfeyer::cpp_api_dwf::analog_output::Channel_Interface & ao1 =
      p_open_device->get_analog_outputs().get_channel(0);

   ::cfeyer::cpp_api_dwf::analog_output::Carrier_Component_Interface & ao1_carrier =
      *(ao1.get_carrier_component());

   ao1_carrier.enable();
   ao1_carrier.set_waveform_shape( ::cfeyer::cpp_api_dwf::analog_output::Waveform_Shape::play );

   // Play f(t) = sin(t/(2*pi)) for t=[0,1) seconds at 500,000 samples / sec (500,000 samples total)
   const int sample_count = 500000;
   double samples[sample_count] = {0.0};

   const double t_initial_sec = 0.0;
   const double t_final_sec = 1.0;
   const double t_sample = (t_final_sec - t_initial_sec) / sample_count;
   const double pi = 3.14159;

   for( int n = 0; n < sample_count; n++ )
   {
      double t = static_cast<double>(n) * t_sample;
      samples[n] = sin( 2.0 * pi * t );
   }

   ao1_carrier.set_frequency_hz( 500e3 );
   ao1_carrier.set_amplitude_volts( 2.0 );

   int sent_samples_count = 0;
   int next_send_samples_count = 0;

   next_send_samples_count = std::min( ao1_carrier.get_max_data_samples(), sample_count - sent_samples_count );
   std::cout << "set_data( " << next_send_samples_count << " )" << std::endl;
   ao1_carrier.set_data( &samples[sent_samples_count], next_send_samples_count );
   sent_samples_count += next_send_samples_count;

   ao1.start();

   while( sample_count > sent_samples_count )
   {
      int free_sample_count = 0;
      int lost_sample_count = 0;
      int corrupted_sample_count = 0;

      ao1.get_status();
      ao1_carrier.get_play_status( free_sample_count, lost_sample_count, corrupted_sample_count );

      if( lost_sample_count > 0 )
      {
         std::cout << "Lost " << lost_sample_count << " samples" << std::endl;
      }

      if( corrupted_sample_count > 0 )
      {
         std::cout << "Corrupted " << corrupted_sample_count << " samples" << std::endl;
      }

      next_send_samples_count = std::min( free_sample_count, sample_count - sent_samples_count );

      if( next_send_samples_count > 0 )
      {
//         std::cout << "write_play_samples( " << next_send_samples_count << " )" << std::endl;
         ao1_carrier.write_play_samples( &samples[sent_samples_count], next_send_samples_count );
      }

      sent_samples_count += next_send_samples_count;
   }

   delete p_open_device;
   p_open_device = 0;

   return 0;
}
<|endoftext|>


<commit_before>#ifndef K3_RUNTIME_IOHANDLE_HPP
#define K3_RUNTIME_IOHANDLE_HPP

#include <memory>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/line.hpp>
#include <runtime/cpp/Common.hpp>
#include <runtime/cpp/Network.hpp>

namespace K3
{
  using namespace std;
  using namespace boost::iostreams;

  //--------------------------
  // IO handles

  class IOHandle : public virtual LogMT
  {
  public:
    typedef tuple<shared_ptr<Codec>, shared_ptr<Net::NEndpoint> > SourceDetails;
    typedef tuple<shared_ptr<Codec>, shared_ptr<Net::NConnection> > SinkDetails;

    IOHandle(shared_ptr<Codec> cdec) : LogMT("IOHandle"), codec(cdec) {}

    virtual bool hasRead() = 0;
    virtual shared_ptr<Value> doRead() = 0;

    virtual bool hasWrite() = 0;
    virtual void doWrite(Value& v) = 0;

    virtual void close() = 0;

    virtual bool builtin() = 0;
    virtual bool file() = 0;

    virtual SourceDetails networkSource() = 0;
    virtual SinkDetails networkSink() = 0;

  protected:
    shared_ptr<Codec> codec;
  };

  class IStreamHandle : public virtual LogMT
  {
  public:
    template<typename Source>
    IStreamHandle(shared_ptr<Codec> cdec, Source& src)
      : LogMT("IStreamHandle"), codec(cdec)
    {
      input = shared_ptr<filtering_istream>(new filtering_istream());
      input->push(src);
    }

    bool hasRead() {
      return input?
        ((input->good() && codec->good()) || codec->decode_ready())
        : false;
    }

    shared_ptr<string> doRead() {
      shared_ptr<string> result;
      while ( !result && input->good() ) {
        char * buffer = new char[1024];
        input->read(buffer,sizeof(buffer));
        result = codec->decode(string(buffer));
        delete[] buffer;
      }
      return result;
    }

    bool hasWrite() {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
      return false;
    }

    void doWrite(string& data) {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
    }

    // Invoke the destructor on the filtering_istream, which in
    // turn closes all associated iostream filters and devices.
    void close() { if ( input ) { input.reset(); } }

  protected:
    shared_ptr<filtering_istream> input;
    shared_ptr<Codec> codec;
  };

  class OStreamHandle : public virtual LogMT
  {
  public:
    template<typename Sink>
    OStreamHandle(shared_ptr<Codec> cdec, Sink& sink)
      : LogMT("OStreamHandle"), codec(cdec)
    {
      output = shared_ptr<filtering_ostream>(new filtering_ostream());
      output->push(sink);
    }

    bool hasRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return false;
    }

    shared_ptr<string> doRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return shared_ptr<string>();
    }

    bool hasWrite() { return output? output->good() : false; }

    void doWrite(string& data) { if ( output ) { (*output) << data << std::endl; } }

    void close() { if ( output ) { output.reset(); } }

  protected:
    shared_ptr<filtering_ostream> output;
    shared_ptr<Codec> codec;
  };

  class StreamHandle : public IOHandle
  {
  public:
    struct Input  {};
    struct Output {};

    template<typename Source>
    StreamHandle(shared_ptr<Codec> cdec, Input i, Source& src)
      : LogMT("StreamHandle"), IOHandle(cdec)
    {
      inImpl = shared_ptr<IStreamHandle>(new IStreamHandle(cdec, src));
    }

    template<typename Sink>
    StreamHandle(shared_ptr<Codec>  cdec, Output o, Sink& sink)
      : LogMT("StreamHandle"), IOHandle(cdec)
    {
      outImpl = shared_ptr<OStreamHandle>(new OStreamHandle(cdec, sink));
    }

    bool hasRead()  {
      bool r = false;
      if ( inImpl ) { r = inImpl->hasRead(); }
      else { BOOST_LOG(*this) << "Invalid hasRead on LineBasedHandle"; }
      return r;
    }

    bool hasWrite() {
      bool r = false;
      if ( outImpl ) { r = outImpl->hasWrite(); }
      else { BOOST_LOG(*this) << "Invalid hasWrite on LineBasedHandle"; }
      return r;
    }

    shared_ptr<Value> doRead() {
      shared_ptr<Value> data;
      if ( inImpl ) {
        data = inImpl->doRead();
      }
      else { BOOST_LOG(*this) << "Invalid doRead on LineBasedHandle"; }
      return data;
    }

    void doWrite(Value& v) {
      if ( outImpl) {
        outImpl->doWrite(v);
      }
      else { BOOST_LOG(*this) << "Invalid doWrite on LineBasedHandle"; }
    }

    void close() {
      if ( inImpl ) { inImpl->close(); }
      else if ( outImpl ) { outImpl->close(); }
    }

  protected:
    shared_ptr<IStreamHandle> inImpl;
    shared_ptr<OStreamHandle> outImpl;
  };

  class LineInputHandle : public virtual LogMT
  {
  public:
    template<typename Source>
    LineInputHandle(Source& src) : LogMT("LineInputHandle"), pending(shared_ptr<string>())
    {
      input = shared_ptr<filtering_istream>(new filtering_istream());
      input->push(src);
    }

    bool hasRead() { return input? input->good() : false; }

    shared_ptr<string> doRead() {
      if ( !input ) { return shared_ptr<string>(); }

      bool success = true;
      shared_ptr<string> v = shared_ptr<string>(new string());

      std::getline(*input, *v);

      if ( !input && v && v->size() == v->max_size() ) {
        if ( !pending ) { pending = make_shared<string>(""); }
        *pending = *pending + *v;
        v.reset();
      }
      else if ( pending ) { *v = *pending + *v; pending.reset(); }
      else if ( v->empty() ) { v.reset(); }

      return v;
    }

    bool hasWrite() {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
      return false;
    }

    void doWrite(string& data) {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
    }

    // Invoke the destructor on the filtering_istream, which in
    // turn closes all associated iostream filters and devices.
    void close() { if ( input ) { input->reset(); } }

  protected:
    shared_ptr<filtering_istream> input;
    shared_ptr<string> pending;
  };

  class LineOutputHandle : public virtual LogMT
  {
  public:
    template<typename Sink>
    LineOutputHandle(Sink& sink) : LogMT("LineOutputHandle")
    {
      output = shared_ptr<filtering_ostream>(new filtering_ostream());
      output->push(sink);
    }

    bool hasRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return false;
    }

    shared_ptr<string> doRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return shared_ptr<string>();
    }

    bool hasWrite() { return output? output->good() : false; }

    void doWrite(string& data) { if ( output ) { (*output) << data << std::endl; } }

    void close() { if ( output ) { output->reset(); } }

  protected:
    shared_ptr<filtering_ostream> output;
  };

  class LineBasedHandle : public IOHandle
  {
  public:
    struct Input  {};
    struct Output {};

    template<typename Source>
    LineBasedHandle(shared_ptr<Codec> cdec, Input i, Source& src)
      : LogMT("LineBasedHandle"), IOHandle(cdec)
    {
      inImpl = shared_ptr<LineInputHandle>(new LineInputHandle(src));
    }

    template<typename Sink>
    LineBasedHandle(shared_ptr<Codec>  cdec, Output o, Sink& sink)
      : LogMT("LineBasedHandle"), IOHandle(cdec)
    {
      outImpl = shared_ptr<LineOutputHandle>(new LineOutputHandle(sink));
    }

    bool hasRead()  {
      bool r = false;
      if ( inImpl ) { r = inImpl->hasRead(); }
      else { BOOST_LOG(*this) << "Invalid hasRead on LineBasedHandle"; }
      return r;
    }

    bool hasWrite() {
      bool r = false;
      if ( outImpl ) { r = outImpl->hasWrite(); }
      else { BOOST_LOG(*this) << "Invalid hasWrite on LineBasedHandle"; }
      return r;
    }

    shared_ptr<Value> doRead() {
      shared_ptr<Value> r;
      if ( inImpl && this->codec ) {
        shared_ptr<string> data = inImpl->doRead();
        if ( data ) { r = this->codec->decode(*data); }
      }
      else { BOOST_LOG(*this) << "Invalid doRead on LineBasedHandle"; }
      return r;
    }

    void doWrite(Value& v) {
      if ( outImpl && this->codec ) {
        string data = this->codec->encode(v);
        outImpl->doWrite(data);
      }
      else { BOOST_LOG(*this) << "Invalid doWrite on LineBasedHandle"; }
    }

    void close() {
      if ( inImpl ) { inImpl->close(); }
      else if ( outImpl ) { outImpl->close(); }
    }

  protected:
    shared_ptr<LineInputHandle> inImpl;
    shared_ptr<LineOutputHandle> outImpl;
  };

  // TODO
  //class MultiLineHandle;
  //class FrameBasedHandle;

  class BuiltinHandle : public StreamHandle
  {
  public:
    struct Stdin  {};
    struct Stdout {};
    struct Stderr {};

    BuiltinHandle(shared_ptr<Codec> cdec, Stdin s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Input(), cin)
    {}

    BuiltinHandle(shared_ptr<Codec> cdec, Stdout s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Output(), cout)
    {}

    BuiltinHandle(shared_ptr<Codec> cdec, Stderr s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Output(), cerr)
    {}

    bool builtin () { return true; }
    bool file() { return false; }

    IOHandle::SourceDetails networkSource()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NEndpoint>());
    }

    IOHandle::SinkDetails networkSink()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NConnection>());
    }
  };

  class FileHandle : public StreamHandle
  {
  public:
    FileHandle(shared_ptr<Codec> cdec, shared_ptr<file_source> fs, StreamHandle::Input i)
      :  StreamHandle(cdec, i, *fs), LogMT("FileHandle")
    {}

    FileHandle(shared_ptr<Codec> cdec, shared_ptr<file_sink> fs, StreamHandle::Output o)
      :  LogMT("FileHandle"), StreamHandle(cdec, o, *fs)
    {}

    bool builtin () { return false; }
    bool file() { return true; }

    IOHandle::SourceDetails networkSource()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NEndpoint>());
    }

    IOHandle::SinkDetails networkSink()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NConnection>());
    }

  private:
    shared_ptr<file_source> fileSrc;
    shared_ptr<file_sink>   fileSink;
  };

  class NetworkHandle : public IOHandle
  {
  public:
    NetworkHandle(shared_ptr<Codec> cdec, shared_ptr<Net::NConnection> c)
      : LogMT("NetworkHandle"), connection(c), IOHandle(cdec)
    {}

    NetworkHandle(shared_ptr<Codec> cdec, shared_ptr<Net::NEndpoint> e)
      : LogMT("NetworkHandle"), endpoint(e), IOHandle(cdec)
    {}

    bool hasRead()  {
      BOOST_LOG(*this) << "Invalid hasRead on NetworkHandle";
      return false;
    }

    bool hasWrite() {
      bool r = false;
      if ( connection ) { r = connection->connected(); }
      else { BOOST_LOG(*this) << "Invalid hasWrite on NetworkHandle"; }
      return r;
    }

    shared_ptr<Value> doRead() {
      BOOST_LOG(*this) << "Invalid doRead on NetworkHandle";
      return shared_ptr<Value>();
    }

    void doWrite(Value& v) {
      if ( connection && this->codec ) {
        string data = this->codec->encode(v);
        connection->write(data);
      }
      else { BOOST_LOG(*this) << "Invalid doWrite on NetworkHandle"; }
    }

    void close() {
      if ( connection ) { connection->close(); }
      else if ( endpoint ) { endpoint->close(); }
    }

    bool builtin () { return false; }
    bool file() { return false; }

    IOHandle::SourceDetails networkSource()
    {
      shared_ptr<Codec> cdec = endpoint? this->codec : shared_ptr<Codec>();
      return make_tuple(cdec, endpoint);
    }

    IOHandle::SinkDetails networkSink()
    {
      shared_ptr<Codec> cdec = connection? this->codec : shared_ptr<Codec>();
      return make_tuple(cdec, connection);
    }

  protected:
    shared_ptr<Net::NConnection> connection;
    shared_ptr<Net::NEndpoint> endpoint;
  };
}

#endif
<commit_msg>Removed LineBasedHandle<commit_after>#ifndef K3_RUNTIME_IOHANDLE_HPP
#define K3_RUNTIME_IOHANDLE_HPP

#include <memory>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/line.hpp>
#include <runtime/cpp/Common.hpp>
#include <runtime/cpp/Network.hpp>

namespace K3
{
  using namespace std;
  using namespace boost::iostreams;

  //--------------------------
  // IO handles

  class IOHandle : public virtual LogMT
  {
  public:
    typedef tuple<shared_ptr<Codec>, shared_ptr<Net::NEndpoint> > SourceDetails;
    typedef tuple<shared_ptr<Codec>, shared_ptr<Net::NConnection> > SinkDetails;

    IOHandle(shared_ptr<Codec> cdec) : LogMT("IOHandle"), codec(cdec) {}

    virtual bool hasRead() = 0;
    virtual shared_ptr<Value> doRead() = 0;

    virtual bool hasWrite() = 0;
    virtual void doWrite(Value& v) = 0;

    virtual void close() = 0;

    virtual bool builtin() = 0;
    virtual bool file() = 0;

    virtual SourceDetails networkSource() = 0;
    virtual SinkDetails networkSink() = 0;

  protected:
    shared_ptr<Codec> codec;
  };

  class IStreamHandle : public virtual LogMT
  {
  public:
    template<typename Source>
    IStreamHandle(shared_ptr<Codec> cdec, Source& src)
      : LogMT("IStreamHandle"), codec(cdec)
    {
      input = shared_ptr<filtering_istream>(new filtering_istream());
      input->push(src);
    }

    bool hasRead() {
      return input?
        ((input->good() && codec->good()) || codec->decode_ready())
        : false;
    }

    shared_ptr<string> doRead() {
      shared_ptr<string> result;
      while ( !result && input->good() ) {
        char * buffer = new char[1024];
        input->read(buffer,sizeof(buffer));
        result = codec->decode(string(buffer));
        delete[] buffer;
      }
      return result;
    }

    bool hasWrite() {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
      return false;
    }

    void doWrite(string& data) {
      BOOST_LOG(*this) << "Invalid write operation on input handle";
    }

    // Invoke the destructor on the filtering_istream, which in
    // turn closes all associated iostream filters and devices.
    void close() { if ( input ) { input.reset(); } }

  protected:
    shared_ptr<filtering_istream> input;
    shared_ptr<Codec> codec;
  };

  class OStreamHandle : public virtual LogMT
  {
  public:
    template<typename Sink>
    OStreamHandle(shared_ptr<Codec> cdec, Sink& sink)
      : LogMT("OStreamHandle"), codec(cdec)
    {
      output = shared_ptr<filtering_ostream>(new filtering_ostream());
      output->push(sink);
    }

    bool hasRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return false;
    }

    shared_ptr<string> doRead() {
      BOOST_LOG(*this) << "Invalid read operation on output handle";
      return shared_ptr<string>();
    }

    bool hasWrite() { return output? output->good() : false; }

    void doWrite(string& data) { if ( output ) { (*output) << data << std::endl; } }

    void close() { if ( output ) { output.reset(); } }

  protected:
    shared_ptr<filtering_ostream> output;
    shared_ptr<Codec> codec;
  };

  class StreamHandle : public IOHandle
  {
  public:
    struct Input  {};
    struct Output {};

    template<typename Source>
    StreamHandle(shared_ptr<Codec> cdec, Input i, Source& src)
      : LogMT("StreamHandle"), IOHandle(cdec)
    {
      inImpl = shared_ptr<IStreamHandle>(new IStreamHandle(cdec, src));
    }

    template<typename Sink>
    StreamHandle(shared_ptr<Codec>  cdec, Output o, Sink& sink)
      : LogMT("StreamHandle"), IOHandle(cdec)
    {
      outImpl = shared_ptr<OStreamHandle>(new OStreamHandle(cdec, sink));
    }

    bool hasRead()  {
      bool r = false;
      if ( inImpl ) { r = inImpl->hasRead(); }
      else { BOOST_LOG(*this) << "Invalid hasRead on LineBasedHandle"; }
      return r;
    }

    bool hasWrite() {
      bool r = false;
      if ( outImpl ) { r = outImpl->hasWrite(); }
      else { BOOST_LOG(*this) << "Invalid hasWrite on LineBasedHandle"; }
      return r;
    }

    shared_ptr<Value> doRead() {
      shared_ptr<Value> data;
      if ( inImpl ) {
        data = inImpl->doRead();
      }
      else { BOOST_LOG(*this) << "Invalid doRead on LineBasedHandle"; }
      return data;
    }

    void doWrite(Value& v) {
      if ( outImpl) {
        outImpl->doWrite(v);
      }
      else { BOOST_LOG(*this) << "Invalid doWrite on LineBasedHandle"; }
    }

    void close() {
      if ( inImpl ) { inImpl->close(); }
      else if ( outImpl ) { outImpl->close(); }
    }

  protected:
    shared_ptr<IStreamHandle> inImpl;
    shared_ptr<OStreamHandle> outImpl;
  };

  // TODO
  //class MultiLineHandle;
  //class FrameBasedHandle;

  class BuiltinHandle : public StreamHandle
  {
  public:
    struct Stdin  {};
    struct Stdout {};
    struct Stderr {};

    BuiltinHandle(shared_ptr<Codec> cdec, Stdin s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Input(), cin)
    {}

    BuiltinHandle(shared_ptr<Codec> cdec, Stdout s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Output(), cout)
    {}

    BuiltinHandle(shared_ptr<Codec> cdec, Stderr s)
      : LogMT("BuiltinHandle"), StreamHandle(cdec, StreamHandle::Output(), cerr)
    {}

    bool builtin () { return true; }
    bool file() { return false; }

    IOHandle::SourceDetails networkSource()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NEndpoint>());
    }

    IOHandle::SinkDetails networkSink()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NConnection>());
    }
  };

  class FileHandle : public StreamHandle
  {
  public:
    FileHandle(shared_ptr<Codec> cdec, shared_ptr<file_source> fs, StreamHandle::Input i)
      :  StreamHandle(cdec, i, *fs), LogMT("FileHandle")
    {}

    FileHandle(shared_ptr<Codec> cdec, shared_ptr<file_sink> fs, StreamHandle::Output o)
      :  LogMT("FileHandle"), StreamHandle(cdec, o, *fs)
    {}

    bool builtin () { return false; }
    bool file() { return true; }

    IOHandle::SourceDetails networkSource()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NEndpoint>());
    }

    IOHandle::SinkDetails networkSink()
    {
      return make_tuple(shared_ptr<Codec>(), shared_ptr<Net::NConnection>());
    }

  private:
    shared_ptr<file_source> fileSrc;
    shared_ptr<file_sink>   fileSink;
  };

  class NetworkHandle : public IOHandle
  {
  public:
    NetworkHandle(shared_ptr<Codec> cdec, shared_ptr<Net::NConnection> c)
      : LogMT("NetworkHandle"), connection(c), IOHandle(cdec)
    {}

    NetworkHandle(shared_ptr<Codec> cdec, shared_ptr<Net::NEndpoint> e)
      : LogMT("NetworkHandle"), endpoint(e), IOHandle(cdec)
    {}

    bool hasRead()  {
      BOOST_LOG(*this) << "Invalid hasRead on NetworkHandle";
      return false;
    }

    bool hasWrite() {
      bool r = false;
      if ( connection ) { r = connection->connected(); }
      else { BOOST_LOG(*this) << "Invalid hasWrite on NetworkHandle"; }
      return r;
    }

    shared_ptr<Value> doRead() {
      BOOST_LOG(*this) << "Invalid doRead on NetworkHandle";
      return shared_ptr<Value>();
    }

    void doWrite(Value& v) {
      if ( connection && this->codec ) {
        string data = this->codec->encode(v);
        connection->write(data);
      }
      else { BOOST_LOG(*this) << "Invalid doWrite on NetworkHandle"; }
    }

    void close() {
      if ( connection ) { connection->close(); }
      else if ( endpoint ) { endpoint->close(); }
    }

    bool builtin () { return false; }
    bool file() { return false; }

    IOHandle::SourceDetails networkSource()
    {
      shared_ptr<Codec> cdec = endpoint? this->codec : shared_ptr<Codec>();
      return make_tuple(cdec, endpoint);
    }

    IOHandle::SinkDetails networkSink()
    {
      shared_ptr<Codec> cdec = connection? this->codec : shared_ptr<Codec>();
      return make_tuple(cdec, connection);
    }

  protected:
    shared_ptr<Net::NConnection> connection;
    shared_ptr<Net::NEndpoint> endpoint;
  };
}

#endif
<|endoftext|>


<commit_before>#ifndef K3_RUNTIME_LITERALS_H
#define K3_RUNTIME_LITERALS_H

#include <list>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "boost/asio.hpp"
#include "boost/fusion/include/std_pair.hpp"
#include "boost/spirit/include/qi.hpp"

namespace K3 {
  namespace qi = boost::spirit::qi;

  using boost::asio::ip::address;

  using std::list;
  using std::make_shared;
  using std::map;
  using std::pair;
  using std::shared_ptr;
  using std::string;
  using std::tuple;
  using std::vector;

  template <class iterator>
  class shallow: public qi::grammar<iterator, qi::space_type, string()> {
   public:
    shallow(): shallow::base_type(start) {
      start = qi::raw[indirection | option | angles | braces | parens | quotes | other];

      indirection = qi::lit("ind") >> start;
      option = qi::lit("none") | qi::lit("some") >> start;

      angles = '<' >> *(qi::char_ - '>') >> '>';
      braces = '{' >> *(qi::char_ - '}') >> '}';
      parens = '(' >> *(qi::char_ - ')') >> ')';
      quotes = '"' >> *(escape - '"') >> '"';
      other = *(qi::char_ - ',');

      escape = '\\' >> qi::char_ | qi::char_;
    }

   private:
    qi::rule<iterator, qi::space_type, string()> start;

    qi::rule<iterator, qi::space_type> indirection;
    qi::rule<iterator, qi::space_type> option;

    qi::rule<iterator, qi::space_type> angles;
    qi::rule<iterator, qi::space_type> braces;
    qi::rule<iterator, qi::space_type> parens;
    qi::rule<iterator, qi::space_type> quotes;
    qi::rule<iterator, qi::space_type> other;

    qi::rule<iterator, qi::space_type> escape;
  };

  template <class iterator>
  class literal: public qi::grammar<iterator, map<string, string>(), qi::space_type> {
   public:
    literal(): literal::base_type(start) {

      start = binding % ',';
      binding = key >> ':' >> value;

      key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z0-9_");
    }

   private:
    qi::rule<iterator, map<string, string>(), qi::space_type> start;
    qi::rule<iterator, pair<string, string>(), qi::space_type> binding;
    qi::rule<iterator, string(), qi::space_type> key;
    shallow<iterator> value;
  };

  // Built-in type refresh specializations.

  template <class T> void refresh(string, T&);
  template <class T, size_t i, size_t n> struct refresh_many;

  template <> void refresh<bool>(string s, bool& b) {
    qi::parse(begin(s), end(s), qi::bool_[([&b] (bool b_) { b = b_; })]);
  }

  template <> void refresh<int>(string s, int& i) {
    qi::parse(begin(s), end(s), qi::int_[([&i] (int i_) { i = i_; })]);
  }

  template <> void refresh<double>(string s, double& d) {
    qi::parse(begin(s), end(s), qi::double_[([&d] (double d_) { d = d_; })]);
  }

  template <> void refresh<string>(string s, string& t) {
    string t_;
    bool result = qi::parse(begin(s), end(s), ('"' >> *(('\\' >> qi::char_) | (qi::char_ - '"')) >> '"'), t_);

    if (result) {
      t = t_;
    }
  }

  template <class T> void refresh(string s, shared_ptr<T>& p) {
    shallow<string::iterator> _shallow;
    qi::rule<string::iterator, qi::space_type> raw_rule = _shallow[([&p] (string s_) {
      if (!p) {
        p = make_shared<T>();
      }

      refresh(s_, *p);
    })];
    qi::rule<string::iterator, qi::space_type> nullptr_rule = qi::lit("none")[([&p] () { p = nullptr; })];
    qi::rule<string::iterator, qi::space_type> someptr_rule = (qi::lit("some") | qi::lit("ind")) >> raw_rule;
    qi::phrase_parse(begin(s), end(s), nullptr_rule | someptr_rule, qi::space);
  }

  template <> void refresh<address>(string s, address& a) {
    a = address::from_string(s);
  }

  template <> void refresh<unsigned short>(string s, unsigned short& i) {
    qi::parse(begin(s), end(s), qi::ushort_, i);
  }

  template <class ... Ts> void refresh(string s, tuple<Ts...>& t) {
    list<string> v;
    shallow<string::iterator> _shallow;

    qi::rule<string::iterator, qi::space_type, list<string>()> tuple_rule = '(' >> (_shallow % ',') >> ')';

    qi::rule<string::iterator, qi::space_type, string()> ip_rule = qi::raw[(qi::int_ % '.')];
    qi::rule<string::iterator, qi::space_type, string()> port_rule = qi::raw[qi::int_];
    qi::rule<string::iterator, qi::space_type, list<string>()> address_rule
      = '<' >> ip_rule >> ':' >> port_rule >> '>';

    qi::phrase_parse(begin(s), end(s), tuple_rule | address_rule, qi::space, v);
    refresh_many<tuple<Ts...>, 0, sizeof...(Ts)>()(v, t);
  }

  template <class T, size_t i> struct refresh_many<T, i, i> {
    void operator()(list<string>, T&) {
      return;
    }
  };

  template <class T, size_t i, size_t n> struct refresh_many {
    void operator()(list<string> v, T& t) {
      if (v.empty()) {
        return;
      }

      refresh<typename std::tuple_element<i, T>::type>(v.front(), std::get<i>(t));

      v.pop_front();
      refresh_many<T, i + 1, n>()(v, t);
    }
  };

  map<string, string> parse_bindings(string s) {
    map<string, string> bindings;
    literal<string::iterator> parser;
    qi::phrase_parse(begin(s), end(s), parser, qi::space, bindings);
    return bindings;
  }
}

#endif
<commit_msg>Avoid copies during refresh-many.<commit_after>#ifndef K3_RUNTIME_LITERALS_H
#define K3_RUNTIME_LITERALS_H

#include <list>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <vector>

#include "boost/asio.hpp"
#include "boost/fusion/include/std_pair.hpp"
#include "boost/spirit/include/qi.hpp"

namespace K3 {
  namespace qi = boost::spirit::qi;

  using boost::asio::ip::address;

  using std::list;
  using std::make_shared;
  using std::map;
  using std::pair;
  using std::shared_ptr;
  using std::string;
  using std::tuple;
  using std::vector;

  template <class iterator>
  class shallow: public qi::grammar<iterator, qi::space_type, string()> {
   public:
    shallow(): shallow::base_type(start) {
      start = qi::raw[indirection | option | angles | braces | parens | quotes | other];

      indirection = qi::lit("ind") >> start;
      option = qi::lit("none") | qi::lit("some") >> start;

      angles = '<' >> *(qi::char_ - '>') >> '>';
      braces = '{' >> *(qi::char_ - '}') >> '}';
      parens = '(' >> *(qi::char_ - ')') >> ')';
      quotes = '"' >> *(escape - '"') >> '"';
      other = *(qi::char_ - ',');

      escape = '\\' >> qi::char_ | qi::char_;
    }

   private:
    qi::rule<iterator, qi::space_type, string()> start;

    qi::rule<iterator, qi::space_type> indirection;
    qi::rule<iterator, qi::space_type> option;

    qi::rule<iterator, qi::space_type> angles;
    qi::rule<iterator, qi::space_type> braces;
    qi::rule<iterator, qi::space_type> parens;
    qi::rule<iterator, qi::space_type> quotes;
    qi::rule<iterator, qi::space_type> other;

    qi::rule<iterator, qi::space_type> escape;
  };

  template <class iterator>
  class literal: public qi::grammar<iterator, map<string, string>(), qi::space_type> {
   public:
    literal(): literal::base_type(start) {

      start = binding % ',';
      binding = key >> ':' >> value;

      key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z0-9_");
    }

   private:
    qi::rule<iterator, map<string, string>(), qi::space_type> start;
    qi::rule<iterator, pair<string, string>(), qi::space_type> binding;
    qi::rule<iterator, string(), qi::space_type> key;
    shallow<iterator> value;
  };

  // Built-in type refresh specializations.

  template <class T> void refresh(string, T&);
  template <class T, size_t i, size_t n> struct refresh_many;

  template <> void refresh<bool>(string s, bool& b) {
    qi::parse(begin(s), end(s), qi::bool_[([&b] (bool b_) { b = b_; })]);
  }

  template <> void refresh<int>(string s, int& i) {
    qi::parse(begin(s), end(s), qi::int_[([&i] (int i_) { i = i_; })]);
  }

  template <> void refresh<double>(string s, double& d) {
    qi::parse(begin(s), end(s), qi::double_[([&d] (double d_) { d = d_; })]);
  }

  template <> void refresh<string>(string s, string& t) {
    string t_;
    bool result = qi::parse(begin(s), end(s), ('"' >> *(('\\' >> qi::char_) | (qi::char_ - '"')) >> '"'), t_);

    if (result) {
      t = t_;
    }
  }

  template <class T> void refresh(string s, shared_ptr<T>& p) {
    shallow<string::iterator> _shallow;
    qi::rule<string::iterator, qi::space_type> raw_rule = _shallow[([&p] (string s_) {
      if (!p) {
        p = make_shared<T>();
      }

      refresh(s_, *p);
    })];
    qi::rule<string::iterator, qi::space_type> nullptr_rule = qi::lit("none")[([&p] () { p = nullptr; })];
    qi::rule<string::iterator, qi::space_type> someptr_rule = (qi::lit("some") | qi::lit("ind")) >> raw_rule;
    qi::phrase_parse(begin(s), end(s), nullptr_rule | someptr_rule, qi::space);
  }

  template <> void refresh<address>(string s, address& a) {
    a = address::from_string(s);
  }

  template <> void refresh<unsigned short>(string s, unsigned short& i) {
    qi::parse(begin(s), end(s), qi::ushort_, i);
  }

  template <class ... Ts> void refresh(string s, tuple<Ts...>& t) {
    list<string> v;
    shallow<string::iterator> _shallow;

    qi::rule<string::iterator, qi::space_type, list<string>()> tuple_rule = '(' >> (_shallow % ',') >> ')';

    qi::rule<string::iterator, qi::space_type, string()> ip_rule = qi::raw[(qi::int_ % '.')];
    qi::rule<string::iterator, qi::space_type, string()> port_rule = qi::raw[qi::int_];
    qi::rule<string::iterator, qi::space_type, list<string>()> address_rule
      = '<' >> ip_rule >> ':' >> port_rule >> '>';

    qi::phrase_parse(begin(s), end(s), tuple_rule | address_rule, qi::space, v);
    refresh_many<tuple<Ts...>, 0, sizeof...(Ts)>()(v, t);
  }

  template <class T, size_t i> struct refresh_many<T, i, i> {
    void operator()(list<string>&, T&) {}
  };

  template <class T, size_t i, size_t n> struct refresh_many {
    void operator()(list<string>& v, T& t) {
      if (v.empty()) {
        return;
      }

      refresh<typename std::tuple_element<i, T>::type>(v.front(), std::get<i>(t));

      v.pop_front();
      refresh_many<T, i + 1, n>()(v, t);
    }
  };

  map<string, string> parse_bindings(string s) {
    map<string, string> bindings;
    literal<string::iterator> parser;
    qi::phrase_parse(begin(s), end(s), parser, qi::space, bindings);
    return bindings;
  }
}

#endif
<|endoftext|>