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

#include "apphandler.hpp"
#include "channel_layer.hpp"

#include <ipmid/api.hpp>
#include <phosphor-logging/log.hpp>
#include <regex>

using namespace phosphor::logging;

namespace ipmi
{

/** @brief implements the set channel access command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved - skip 4 bits
 *  @ param accessMode - access mode for IPMI messaging
 *  @ param usrAuth - user level authentication (enable/disable)
 *  @ param msgAuth - per message authentication (enable/disable)
 *  @ param alertDisabled - PEF alerting (enable/disable)
 *  @ param chanAccess - channel access
 *  @ param channelPrivLimit - channel privilege limit
 *  @ param reserved - skip 3 bits
 *  @ param channelPrivMode - channel priviledge mode
 *
 *  @ returns IPMI completion code
 **/
RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel,
                               uint4_t reserved1, uint3_t accessMode,
                               bool usrAuth, bool msgAuth, bool alertDisabled,
                               uint2_t chanAccess, uint4_t channelPrivLimit,
                               uint2_t reserved2, uint2_t channelPrivMode)
{
    const uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);

    if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
    {
        log<level::DEBUG>("Set channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
    {
        log<level::DEBUG>("Set channel access - No support on channel");
        return responseInvalidFieldRequest();
    }

    ChannelAccess chActData;
    ChannelAccess chNVData;
    uint8_t setActFlag = 0;
    uint8_t setNVFlag = 0;
    Cc compCode;

    // cannot static cast directly from uint2_t to enum; must go via int
    uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess);
    switch (static_cast<EChannelActionType>(channelAccessAction))
    {
        case doNotSet:
            break;
        case nvData:
            chNVData.accessMode = static_cast<uint8_t>(accessMode);
            chNVData.userAuthDisabled = usrAuth;
            chNVData.perMsgAuthDisabled = msgAuth;
            chNVData.alertingDisabled = alertDisabled;
            setNVFlag |= (setAccessMode | setUserAuthEnabled |
                          setMsgAuthEnabled | setAlertingEnabled);
            break;

        case activeData:
            chActData.accessMode = static_cast<uint8_t>(accessMode);
            chActData.userAuthDisabled = usrAuth;
            chActData.perMsgAuthDisabled = msgAuth;
            chActData.alertingDisabled = alertDisabled;
            setActFlag |= (setAccessMode | setUserAuthEnabled |
                           setMsgAuthEnabled | setAlertingEnabled);
            break;

        case reserved:
        default:
            log<level::DEBUG>("Set channel access - Invalid access set mode");
            return responseInvalidFieldRequest();
    }

    // cannot static cast directly from uint2_t to enum; must go via int
    uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode);
    switch (static_cast<EChannelActionType>(channelPrivAction))
    {
        case doNotSet:
            break;
        case nvData:
            chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit);
            setNVFlag |= setPrivLimit;
            break;
        case activeData:
            chActData.privLimit = static_cast<uint8_t>(channelPrivLimit);

            setActFlag |= setPrivLimit;
            break;
        case reserved:
        default:
            log<level::DEBUG>("Set channel access - Invalid access priv mode");
            return responseInvalidFieldRequest();
    }

    if (setNVFlag != 0)
    {
        compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
        if (compCode != IPMI_CC_OK)
        {
            log<level::DEBUG>("Set channel access - Failed to set access data");
            return response(compCode);
        }
    }

    if (setActFlag != 0)
    {
        compCode = setChannelAccessData(chNum, chActData, setActFlag);
        if (compCode != IPMI_CC_OK)
        {
            log<level::DEBUG>("Set channel access - Failed to set access data");
            return response(compCode);
        }
    }

    return responseSuccess();
}

/** @brief implements the get channel access command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved1 - skip 4 bits
 *  @ param reserved2 - skip 6 bits
 *  @ param accessMode - get access mode
 *
 *  @returns ipmi completion code plus response data
 *  - accessMode - get access mode
 *  - usrAuthDisabled - user level authentication status
 *  - msgAuthDisabled - message level authentication status
 *  - alertDisabled - alerting status
 *  - reserved - skip 2 bits
 *  - privLimit - channel privilege limit
 *  - reserved - skip 4 bits
 * */
ipmi ::RspType<uint3_t, // access mode,
               bool,    // user authentication status,
               bool,    // message authentication status,
               bool,    // alerting status,
               uint2_t, // reserved,

               uint4_t, // channel privilege,
               uint4_t  // reserved
               >
    ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1,
                         uint6_t reserved2, uint2_t accessSetMode)
{
    const uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);

    if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    if ((accessSetMode == doNotSet) || (accessSetMode == reserved))
    {
        log<level::DEBUG>("Get channel access - Invalid Access mode");
        return responseInvalidFieldRequest();
    }

    if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
    {
        log<level::DEBUG>("Get channel access - No support on channel");
        return response(IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL);
    }

    ChannelAccess chAccess;

    Cc compCode;

    if (accessSetMode == nvData)
    {
        compCode = getChannelAccessPersistData(chNum, chAccess);
    }
    else if (accessSetMode == activeData)
    {
        compCode = getChannelAccessData(chNum, chAccess);
    }

    if (compCode != IPMI_CC_OK)
    {
        return response(compCode);
    }

    constexpr uint2_t reservedOut1 = 0;
    constexpr uint4_t reservedOut2 = 0;

    return responseSuccess(
        static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled,
        chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1,
        static_cast<uint4_t>(chAccess.privLimit), reservedOut2);
}

/** @brief implements the get channel info command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved - skip 4 bits
 *
 *  @returns ipmi completion code plus response data
 *  - chNum - the channel number for this request
 *  - mediumType - see Table 6-3, Channel Medium Type Numbers
 *  - protocolType - Table 6-2, Channel Protocol Type Numbers
 *  - activeSessionCount - number of active sessions
 *  - sessionType - channel support for sessions
 *  - vendorId - vendor for this channel protocol (IPMI - 7154)
 *  - auxChInfo - auxiliary info for channel
 * */
RspType<uint4_t,  // chNum
        uint4_t,  // reserved
        uint7_t,  // mediumType
        bool,     // reserved
        uint5_t,  // protocolType
        uint3_t,  // reserved
        uint6_t,  // activeSessionCount
        uint2_t,  // sessionType
        uint24_t, // Vendor IANA
        uint16_t  // aux info
        >
    ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved)
{
    uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
    if (!isValidChannel(chNum) || reserved)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    ChannelInfo chInfo;
    Cc compCode = getChannelInfo(chNum, chInfo);
    if (compCode != ccSuccess)
    {
        log<level::ERR>("Failed to get channel info",
                        entry("CHANNEL=%x", chNum),
                        entry("ERRNO=%x", compCode));
        return response(compCode);
    }

    constexpr uint4_t reserved1 = 0;
    constexpr bool reserved2 = false;
    constexpr uint3_t reserved3 = 0;
    uint8_t mediumType = chInfo.mediumType;
    uint8_t protocolType = chInfo.protocolType;
    uint2_t sessionType = chInfo.sessionSupported;
    uint6_t activeSessionCount = getChannelActiveSessions(chNum);
    // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
    constexpr uint24_t vendorId = 7154;
    constexpr uint16_t auxChInfo = 0;

    return responseSuccess(chNum, reserved1, mediumType, reserved2,
                           protocolType, reserved3, activeSessionCount,
                           sessionType, vendorId, auxChInfo);
}

namespace
{
constexpr uint16_t standardPayloadBit(PayloadType p)
{
    return (1 << static_cast<size_t>(p));
}

constexpr uint16_t sessionPayloadBit(PayloadType p)
{
    constexpr size_t sessionShift =
        static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST);
    return ((1 << static_cast<size_t>(p)) >> sessionShift);
}
} // namespace

/** @brief implements get channel payload support command
 *  @ param ctx - ipmi context pointer
 *  @ param chNum - channel number
 *  @ param reserved - skip 4 bits
 *
 *  @ returns IPMI completion code plus response data
 *  - stdPayloadType - bitmask of supported standard payload types
 *  - sessSetupPayloadType - bitmask of supported session setup payload types
 *  - OEMPayloadType - bitmask of supported OEM payload types
 *  - reserved - 2 bytes of 0
 **/
RspType<uint16_t, // stdPayloadType
        uint16_t, // sessSetupPayloadType
        uint16_t, // OEMPayloadType
        uint16_t  // reserved
        >
    ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel,
                                 uint4_t reserved)
{
    uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
    if (!isValidChannel(chNum) || reserved)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    // Session support is available in active LAN channels.
    if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) ||
        !(doesDeviceExist(chNum)))
    {
        log<level::DEBUG>("Get channel payload - Device not exist");
        return responseInvalidFieldRequest();
    }

    constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) |
                                        standardPayloadBit(PayloadType::SOL);
    constexpr uint16_t sessSetupPayloadType =
        sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) |
        sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) |
        sessionPayloadBit(PayloadType::RAKP1) |
        sessionPayloadBit(PayloadType::RAKP2) |
        sessionPayloadBit(PayloadType::RAKP3) |
        sessionPayloadBit(PayloadType::RAKP4);
    constexpr uint16_t OEMPayloadType = 0;
    constexpr uint16_t rspRsvd = 0;
    return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType,
                           rspRsvd);
}

/** @brief implements the get channel payload version command
 *  @param ctx - IPMI context pointer (for channel)
 *  @param chNum - channel number to get info about
 *  @param reserved - skip 4 bits
 *  @param payloadTypeNum - to get payload type info

 *  @returns IPMI completion code plus response data
 *   - formatVersion - BCD encoded format version info
 */

RspType<uint8_t> // formatVersion
    ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum,
                                 uint4_t reserved, uint8_t payloadTypeNum)
{
    uint8_t channel =
        convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);

    if (reserved || !isValidChannel(channel) ||
        (getChannelSessionSupport(channel)) == EChannelSessSupported::none)
    {
        return responseInvalidFieldRequest();
    }

    if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum)))
    {
        log<level::ERR>("Channel payload version - Payload type unavailable");

        constexpr uint8_t payloadTypeNotSupported = 0x80;
        return response(payloadTypeNotSupported);
    }

    // BCD encoded version representation - 1.0
    constexpr uint8_t formatVersion = 0x10;

    return responseSuccess(formatVersion);
}

void registerChannelFunctions() __attribute__((constructor));
void registerChannelFunctions()
{
    ipmiChannelInit();

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess,
                    Privilege::Admin, ipmiSetChannelAccess);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess,
                    Privilege::User, ipmiGetChannelAccess);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand,
                    Privilege::User, ipmiGetChannelInfo);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport,
                    Privilege::User, ipmiGetChannelPayloadSupport);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion,
                    Privilege::User, ipmiGetChannelPayloadVersion);
}

} // namespace ipmi
<commit_msg>channelcmds:fix set chnl access sessionless chnl<commit_after>/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/

#include "apphandler.hpp"
#include "channel_layer.hpp"

#include <ipmid/api.hpp>
#include <phosphor-logging/log.hpp>
#include <regex>

using namespace phosphor::logging;

namespace ipmi
{

static constexpr const uint8_t ccActionNotSupportedForChannel = 0x82;

/** @brief implements the set channel access command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved - skip 4 bits
 *  @ param accessMode - access mode for IPMI messaging
 *  @ param usrAuth - user level authentication (enable/disable)
 *  @ param msgAuth - per message authentication (enable/disable)
 *  @ param alertDisabled - PEF alerting (enable/disable)
 *  @ param chanAccess - channel access
 *  @ param channelPrivLimit - channel privilege limit
 *  @ param reserved - skip 3 bits
 *  @ param channelPrivMode - channel priviledge mode
 *
 *  @ returns IPMI completion code
 **/
RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel,
                               uint4_t reserved1, uint3_t accessMode,
                               bool usrAuth, bool msgAuth, bool alertDisabled,
                               uint2_t chanAccess, uint4_t channelPrivLimit,
                               uint2_t reserved2, uint2_t channelPrivMode)
{
    const uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);

    if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
    {
        log<level::DEBUG>("Set channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
    {
        log<level::DEBUG>("Set channel access - No support on channel");
        return response(ccActionNotSupportedForChannel);
    }

    ChannelAccess chActData;
    ChannelAccess chNVData;
    uint8_t setActFlag = 0;
    uint8_t setNVFlag = 0;
    Cc compCode;

    // cannot static cast directly from uint2_t to enum; must go via int
    uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess);
    switch (static_cast<EChannelActionType>(channelAccessAction))
    {
        case doNotSet:
            break;
        case nvData:
            chNVData.accessMode = static_cast<uint8_t>(accessMode);
            chNVData.userAuthDisabled = usrAuth;
            chNVData.perMsgAuthDisabled = msgAuth;
            chNVData.alertingDisabled = alertDisabled;
            setNVFlag |= (setAccessMode | setUserAuthEnabled |
                          setMsgAuthEnabled | setAlertingEnabled);
            break;

        case activeData:
            chActData.accessMode = static_cast<uint8_t>(accessMode);
            chActData.userAuthDisabled = usrAuth;
            chActData.perMsgAuthDisabled = msgAuth;
            chActData.alertingDisabled = alertDisabled;
            setActFlag |= (setAccessMode | setUserAuthEnabled |
                           setMsgAuthEnabled | setAlertingEnabled);
            break;

        case reserved:
        default:
            log<level::DEBUG>("Set channel access - Invalid access set mode");
            return responseInvalidFieldRequest();
    }

    // cannot static cast directly from uint2_t to enum; must go via int
    uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode);
    switch (static_cast<EChannelActionType>(channelPrivAction))
    {
        case doNotSet:
            break;
        case nvData:
            chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit);
            setNVFlag |= setPrivLimit;
            break;
        case activeData:
            chActData.privLimit = static_cast<uint8_t>(channelPrivLimit);

            setActFlag |= setPrivLimit;
            break;
        case reserved:
        default:
            log<level::DEBUG>("Set channel access - Invalid access priv mode");
            return responseInvalidFieldRequest();
    }

    if (setNVFlag != 0)
    {
        compCode = setChannelAccessPersistData(chNum, chNVData, setNVFlag);
        if (compCode != IPMI_CC_OK)
        {
            log<level::DEBUG>("Set channel access - Failed to set access data");
            return response(compCode);
        }
    }

    if (setActFlag != 0)
    {
        compCode = setChannelAccessData(chNum, chActData, setActFlag);
        if (compCode != IPMI_CC_OK)
        {
            log<level::DEBUG>("Set channel access - Failed to set access data");
            return response(compCode);
        }
    }

    return responseSuccess();
}

/** @brief implements the get channel access command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved1 - skip 4 bits
 *  @ param reserved2 - skip 6 bits
 *  @ param accessMode - get access mode
 *
 *  @returns ipmi completion code plus response data
 *  - accessMode - get access mode
 *  - usrAuthDisabled - user level authentication status
 *  - msgAuthDisabled - message level authentication status
 *  - alertDisabled - alerting status
 *  - reserved - skip 2 bits
 *  - privLimit - channel privilege limit
 *  - reserved - skip 4 bits
 * */
ipmi ::RspType<uint3_t, // access mode,
               bool,    // user authentication status,
               bool,    // message authentication status,
               bool,    // alerting status,
               uint2_t, // reserved,

               uint4_t, // channel privilege,
               uint4_t  // reserved
               >
    ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1,
                         uint6_t reserved2, uint2_t accessSetMode)
{
    const uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);

    if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    if ((accessSetMode == doNotSet) || (accessSetMode == reserved))
    {
        log<level::DEBUG>("Get channel access - Invalid Access mode");
        return responseInvalidFieldRequest();
    }

    if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
    {
        log<level::DEBUG>("Get channel access - No support on channel");
        return response(ccActionNotSupportedForChannel);
    }

    ChannelAccess chAccess;

    Cc compCode;

    if (accessSetMode == nvData)
    {
        compCode = getChannelAccessPersistData(chNum, chAccess);
    }
    else if (accessSetMode == activeData)
    {
        compCode = getChannelAccessData(chNum, chAccess);
    }

    if (compCode != IPMI_CC_OK)
    {
        return response(compCode);
    }

    constexpr uint2_t reservedOut1 = 0;
    constexpr uint4_t reservedOut2 = 0;

    return responseSuccess(
        static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled,
        chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1,
        static_cast<uint4_t>(chAccess.privLimit), reservedOut2);
}

/** @brief implements the get channel info command
 *  @ param ctx - context pointer
 *  @ param channel - channel number
 *  @ param reserved - skip 4 bits
 *
 *  @returns ipmi completion code plus response data
 *  - chNum - the channel number for this request
 *  - mediumType - see Table 6-3, Channel Medium Type Numbers
 *  - protocolType - Table 6-2, Channel Protocol Type Numbers
 *  - activeSessionCount - number of active sessions
 *  - sessionType - channel support for sessions
 *  - vendorId - vendor for this channel protocol (IPMI - 7154)
 *  - auxChInfo - auxiliary info for channel
 * */
RspType<uint4_t,  // chNum
        uint4_t,  // reserved
        uint7_t,  // mediumType
        bool,     // reserved
        uint5_t,  // protocolType
        uint3_t,  // reserved
        uint6_t,  // activeSessionCount
        uint2_t,  // sessionType
        uint24_t, // Vendor IANA
        uint16_t  // aux info
        >
    ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved)
{
    uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
    if (!isValidChannel(chNum) || reserved)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    ChannelInfo chInfo;
    Cc compCode = getChannelInfo(chNum, chInfo);
    if (compCode != ccSuccess)
    {
        log<level::ERR>("Failed to get channel info",
                        entry("CHANNEL=%x", chNum),
                        entry("ERRNO=%x", compCode));
        return response(compCode);
    }

    constexpr uint4_t reserved1 = 0;
    constexpr bool reserved2 = false;
    constexpr uint3_t reserved3 = 0;
    uint8_t mediumType = chInfo.mediumType;
    uint8_t protocolType = chInfo.protocolType;
    uint2_t sessionType = chInfo.sessionSupported;
    uint6_t activeSessionCount = getChannelActiveSessions(chNum);
    // IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
    constexpr uint24_t vendorId = 7154;
    constexpr uint16_t auxChInfo = 0;

    return responseSuccess(chNum, reserved1, mediumType, reserved2,
                           protocolType, reserved3, activeSessionCount,
                           sessionType, vendorId, auxChInfo);
}

namespace
{
constexpr uint16_t standardPayloadBit(PayloadType p)
{
    return (1 << static_cast<size_t>(p));
}

constexpr uint16_t sessionPayloadBit(PayloadType p)
{
    constexpr size_t sessionShift =
        static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST);
    return ((1 << static_cast<size_t>(p)) >> sessionShift);
}
} // namespace

/** @brief implements get channel payload support command
 *  @ param ctx - ipmi context pointer
 *  @ param chNum - channel number
 *  @ param reserved - skip 4 bits
 *
 *  @ returns IPMI completion code plus response data
 *  - stdPayloadType - bitmask of supported standard payload types
 *  - sessSetupPayloadType - bitmask of supported session setup payload types
 *  - OEMPayloadType - bitmask of supported OEM payload types
 *  - reserved - 2 bytes of 0
 **/
RspType<uint16_t, // stdPayloadType
        uint16_t, // sessSetupPayloadType
        uint16_t, // OEMPayloadType
        uint16_t  // reserved
        >
    ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel,
                                 uint4_t reserved)
{
    uint8_t chNum =
        convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
    if (!isValidChannel(chNum) || reserved)
    {
        log<level::DEBUG>("Get channel access - Invalid field in request");
        return responseInvalidFieldRequest();
    }

    // Session support is available in active LAN channels.
    if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) ||
        !(doesDeviceExist(chNum)))
    {
        log<level::DEBUG>("Get channel payload - Device not exist");
        return responseInvalidFieldRequest();
    }

    constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) |
                                        standardPayloadBit(PayloadType::SOL);
    constexpr uint16_t sessSetupPayloadType =
        sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) |
        sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) |
        sessionPayloadBit(PayloadType::RAKP1) |
        sessionPayloadBit(PayloadType::RAKP2) |
        sessionPayloadBit(PayloadType::RAKP3) |
        sessionPayloadBit(PayloadType::RAKP4);
    constexpr uint16_t OEMPayloadType = 0;
    constexpr uint16_t rspRsvd = 0;
    return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType,
                           rspRsvd);
}

/** @brief implements the get channel payload version command
 *  @param ctx - IPMI context pointer (for channel)
 *  @param chNum - channel number to get info about
 *  @param reserved - skip 4 bits
 *  @param payloadTypeNum - to get payload type info

 *  @returns IPMI completion code plus response data
 *   - formatVersion - BCD encoded format version info
 */

RspType<uint8_t> // formatVersion
    ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum,
                                 uint4_t reserved, uint8_t payloadTypeNum)
{
    uint8_t channel =
        convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);

    if (reserved || !isValidChannel(channel) ||
        (getChannelSessionSupport(channel)) == EChannelSessSupported::none)
    {
        return responseInvalidFieldRequest();
    }

    if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum)))
    {
        log<level::ERR>("Channel payload version - Payload type unavailable");

        constexpr uint8_t payloadTypeNotSupported = 0x80;
        return response(payloadTypeNotSupported);
    }

    // BCD encoded version representation - 1.0
    constexpr uint8_t formatVersion = 0x10;

    return responseSuccess(formatVersion);
}

void registerChannelFunctions() __attribute__((constructor));
void registerChannelFunctions()
{
    ipmiChannelInit();

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess,
                    Privilege::Admin, ipmiSetChannelAccess);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess,
                    Privilege::User, ipmiGetChannelAccess);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand,
                    Privilege::User, ipmiGetChannelInfo);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport,
                    Privilege::User, ipmiGetChannelPayloadSupport);

    registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion,
                    Privilege::User, ipmiGetChannelPayloadVersion);
}

} // namespace ipmi
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "cmd_enter.h"

#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sched.h>
#include <signal.h>
#include <sys/mount.h>
#include <sys/wait.h>
#include <unistd.h>

#include <cassert>
#include <cstdio>
#include <map>
#include <set>
#include <string>
#include <vector>

#include "logging.h"
#include "options.h"
#include "publish/except.h"
#include "util/posix.h"

using namespace std;  // NOLINT

namespace publish {

int CmdEnter::Main(const Options &options) {
  bool rvb;

  std::string fqrn = options.plain_args()[0].value_str;

  uid_t uid = geteuid();
  gid_t gid = getegid();
  printf("OUTER NS: uid %d   gid %d\n", uid, gid);

  string cwd = GetCurrentWorkingDirectory();
  string workspace = GetHomeDirectory() + "/.cvmfs/" + fqrn;
  const string path_usyslog = workspace + "/usyslog.log";
  const string path_cache = workspace + "/cache";
  const string path_config = workspace + "/client.config";
  const string path_mount_union = workspace + "/union";
  const string path_mount_rdonly = workspace + "/rdonly";
  const string path_mount_scratch = workspace + "/scratch";
  const string path_ovl_work = workspace + "/work";
  const string path_cvmfs2 =
    "/home/jakob/Documents/CERN/git/src/build-arch/cvmfs/cvmfs2";

  int rvi = unshare(CLONE_NEWUSER);
  LogCvmfs(kLogCvmfs, kLogStdout, "unshare %d (%d), I am %d",
           rvi, errno, getuid());
  if (rvi != 0) throw EPublish("cannot create namespace");
  printf("INNER NS after unshare: uid %d   gid %d\n", geteuid(), getegid());

  string str_pid = StringifyInt(getpid());
  string path_uid_map = string("/proc/") + str_pid + "/uid_map";
  string path_gid_map = string("/proc/") + str_pid + "/gid_map";
  string path_setgroups = string("/proc/") + str_pid + "/setgroups";

  rvb = SafeWriteToFile(string("0 ") + StringifyInt(uid) + " 1", path_uid_map,
                        kDefaultFileMode);
  if (!rvb) throw EPublish("cannot set uid map");
  rvb = SafeWriteToFile("deny", path_setgroups, kDefaultFileMode);
  if (!rvb) throw EPublish("cannot set setgroups");
  rvb = SafeWriteToFile(string("0 ") + StringifyInt(gid) + " 1", path_gid_map,
                        kDefaultFileMode);
  if (!rvb) throw EPublish("cannot set gid map");

  printf("INNER NS initialized: uid %d/%d   gid %d/%d\n",
         getuid(), geteuid(), getgid(), getegid());

  rvi = unshare(CLONE_NEWNS);
  if (rvi != 0) throw EPublish("cannot create mount namespace");

  rvi = chdir(cwd.c_str());
  if (rvi != 0) throw EPublish("cannot chdir to " + cwd);

  rvi = unshare(CLONE_NEWPID);
  if (rvi != 0) throw EPublish("cannot create pid namespace");

  printf("Initialize PID namespace, current pid %d\n", getpid());
  int status;
  pid_t pid = fork();
  switch (pid) {
    case -1:
      LogCvmfs(kLogCvmfs, kLogStdout, "fork error %d", errno);
      return 1;
    case 0:
      // New init process
      break;
    default:
      // Parent
      rvi = waitpid(pid, &status, 0);
      LogCvmfs(kLogCvmfs, kLogStdout, "pid ns bridge process out");
      return 0;
      //if (rvi == -1) {
      //  LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading return code (%d)", errno);
      //  return 32;
      //}
      //if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
      //  LogCvmfs(kLogCvmfs, kLogStderr, "Failure mounting");
      //  return 1;
      //}
  }
  char procpid[PATH_MAX + 1];
  int len = readlink("/proc/self", procpid, PATH_MAX);
  procpid[len] = '\0';
  printf("/proc/self --> %s\n", procpid);
  rvi = mount("", "/proc", "proc", 0, NULL);
  if (rvi != 0) throw EPublish("cannot remount /proc");
  len = readlink("/proc/self", procpid, PATH_MAX);
  procpid[len] = '\0';
  printf("Remounted PROC, /proc/self --> %s\n", procpid);

  LogCvmfs(kLogCvmfs, kLogStdout, "Create workspace %s", workspace.c_str());
  rvb = MkdirDeep(workspace, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create workspace " + workspace);
  rvb = MkdirDeep(path_cache, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_cache);
  rvb = MkdirDeep(path_mount_union, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_union);
  rvb = MkdirDeep(path_mount_rdonly, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_rdonly);
  rvb = MkdirDeep(path_mount_scratch, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_scratch);
  rvb = MkdirDeep(path_ovl_work, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_ovl_work);

  LogCvmfs(kLogCvmfs, kLogStdout, "Generating options for %s", fqrn.c_str());
  BashOptionsManager options_manager;
  options_manager.ParseDefault(fqrn);
  options_manager.SetValue("CVMFS_MOUNT_DIR", path_mount_rdonly);
  options_manager.SetValue("CVMFS_AUTO_UPDATE", "no");
  options_manager.SetValue("CVMFS_NFS_SOURCE", "no");
  options_manager.SetValue("CVMFS_HIDE_MAGIC_XATTRS", "yes");
  options_manager.SetValue("CVMFS_SERVER_CACHE_MODE", "yes");
  options_manager.SetValue("CVMFS_USYSLOG", path_usyslog);
  options_manager.SetValue("CVMFS_RELOAD_SOCKETS", path_cache);
  options_manager.SetValue("CVMFS_WORKSPACE", path_cache);
  options_manager.SetValue("CVMFS_CACHE_PRIMARY", "private");
  options_manager.SetValue("CVMFS_CACHE_private_TYPE", "posix");
  options_manager.SetValue("CVMFS_CACHE_private_BASE", path_cache);
  options_manager.SetValue("CVMFS_CACHE_private_SHARED", "on");
  options_manager.SetValue("CVMFS_CACHE_private_QUOTA_LIMIT", "4000");
  options_manager.SetValue("CVMFS_NFILES", "65538");
  options_manager.SetValue("CVMFS_HTTP_PROXY", "auto");
  options_manager.SetValue("CVMFS_PAC_URLS", "http://wlcg-wpad.cern.ch/wpad.dat;http://wlcg-wpad.fnal.gov/wpad.dat");
  options_manager.SetValue("CVMFS_SERVER_URL", "http://cvmfs-stratum-one.cern.ch/cvmfs/@fqrn@");
  options_manager.SetValue("CVMFS_KEYS_DIR", "/home/jakob/Documents/CERN/git/src/mount/keys");
  rvb = SafeWriteToFile(options_manager.Dump(), path_config, kPrivateFileMode);

  vector<string> args;
  args.push_back("-o");
  args.push_back("config=" + path_config);
  args.push_back(fqrn);
  args.push_back(path_mount_rdonly);
  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  pid_t pid_cvmfs;
  rvb = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr, path_cvmfs2, args,
                      false, &pid_cvmfs);
  if (!rvb) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s", path_cvmfs2.c_str());
    return 32;
  }
  close(fd_stdin);

  rvi = waitpid(pid_cvmfs, &status, 0);
  if (rvi == -1) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading return code (%d)", errno);
    return 32;
  }
  if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failure mounting");
    return 1;
  }
  LogCvmfs(kLogCvmfs, kLogStdout, "mounted read-only branch");

  LogCvmfs(kLogCvmfs, kLogStdout, "mounting union file system");
  vector<string> args_ovl;
  args_ovl.push_back("-o");
  args_ovl.push_back(string("lowerdir=") + path_mount_rdonly +
                     ",upperdir=" + path_mount_scratch +
                     ",workdir=" + path_ovl_work);
  args_ovl.push_back(path_mount_union);
  pid_t pid_ovl;
  rvb = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
                      "/home/jakob/Documents/CERN/git/fuse-overlayfs",
                      args_ovl, false, &pid_ovl);
  if (!rvb) EPublish("failed to mount ovl");
  rvi = waitpid(pid_ovl, &status, 0);
  if (rvi == -1) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading ovl return code (%d)",
             errno);
    return 1;
  }
  //if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
  //  LogCvmfs(kLogCvmfs, kLogStderr, "Failure mounting ovl");
  //  return 1;
  //}
  LogCvmfs(kLogCvmfs, kLogStdout, "union file system mounted");

//  LogCvmfs(kLogCvmfs, kLogStdout, "bind-mounting to /cvmfs");
//  rvi = mount(path_mount_union.c_str(), "/cvmfs", "", MS_BIND, NULL);
//  if (rvi != 0) throw EPublish("cannot bind mount to /cvmfs");

//  LogCvmfs(kLogCvmfs, kLogStdout,
//           "create grand-child user ns to switch back to original user");
//  rvi = unshare(CLONE_NEWUSER);
//  LogCvmfs(kLogCvmfs, kLogStdout, "unshare %d (%d), I am %d",
//           rvi, errno, getuid());
//  if (rvi != 0) throw EPublish("cannot create grand-child user ns");
//  printf("GRAND USER NS after unshare: uid %d   gid %d\n",
//         geteuid(), getegid());
//
//  rvb = SafeWriteToFile(StringifyInt(uid) + " 0 1", "/proc/1/uid_map",
//                        kDefaultFileMode);
//  if (!rvb) throw EPublish("cannot set uid map");
//  rvb = SafeWriteToFile("deny", "/proc/1/setgroups", kDefaultFileMode);
//  if (!rvb) throw EPublish("cannot set setgroups");
//  rvb = SafeWriteToFile(StringifyInt(gid) + " 0 1", "/proc/1/gid_map",
//                        kDefaultFileMode);
//  if (!rvb) throw EPublish("cannot set gid map");
//
//  printf("GRAND USER NS initialized: uid %d/%d   gid %d/%d\n",
//         getuid(), geteuid(), getgid(), getegid());
//
//  LogCvmfs(kLogCvmfs, kLogStdout, "dropping credentials to %d/%d", uid, gid);
//  rvb = SwitchCredentials(uid, gid, false);
//  if (!rvb) throw EPublish("cannot drop privileges");

  execl("/bin/bash", "", (char *)0);

  LogCvmfs(kLogCvmfs, kLogStdout,
           "exiting pid namespace including process cleanup");

  return 0;
}

}  // namespace publish
<commit_msg>use common infrastructure code in enter command<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "cmd_enter.h"

#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <sched.h>
#include <signal.h>
#include <sys/mount.h>
#include <unistd.h>

#include <cassert>
#include <cstdio>
#include <map>
#include <set>
#include <string>
#include <vector>

#include "logging.h"
#include "options.h"
#include "publish/except.h"
#include "util/namespace.h"
#include "util/posix.h"

using namespace std;  // NOLINT

namespace publish {

int CmdEnter::Main(const Options &options) {
  bool rvb;
  int rvi;

  std::string fqrn = options.plain_args()[0].value_str;

  uid_t uid = geteuid();
  gid_t gid = getegid();

  string cwd = GetCurrentWorkingDirectory();
  string workspace = GetHomeDirectory() + "/.cvmfs/" + fqrn;
  const string path_usyslog = workspace + "/usyslog.log";
  const string path_cache = workspace + "/cache";
  const string path_config = workspace + "/client.config";
  const string path_mount_union = workspace + "/union";
  const string path_mount_rdonly = workspace + "/rdonly";
  const string path_mount_scratch = workspace + "/scratch";
  const string path_ovl_work = workspace + "/work";
  const string path_cvmfs2 =
    "/home/jakob/Documents/CERN/git/src/build-arch/cvmfs/cvmfs2";

  rvb = CreateUserNamespace(0, 0);
  if (!rvb) throw EPublish("cannot create user namespace");
  rvb = CreateMountNamespace();
  if (!rvb) throw EPublish("cannot create mount namespace");
  rvb = CreatePidNamespace(NULL);
  if (!rvb) throw EPublish("cannot create pid namespace");

  LogCvmfs(kLogCvmfs, kLogStdout, "Create workspace %s", workspace.c_str());
  rvb = MkdirDeep(workspace, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create workspace " + workspace);
  rvb = MkdirDeep(path_cache, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_cache);
  rvb = MkdirDeep(path_mount_union, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_union);
  rvb = MkdirDeep(path_mount_rdonly, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_rdonly);
  rvb = MkdirDeep(path_mount_scratch, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_mount_scratch);
  rvb = MkdirDeep(path_ovl_work, kPrivateDirMode);
  if (!rvb) throw EPublish("cannot create " + path_ovl_work);

  LogCvmfs(kLogCvmfs, kLogStdout, "Generating options for %s", fqrn.c_str());
  BashOptionsManager options_manager;
  options_manager.ParseDefault(fqrn);
  options_manager.SetValue("CVMFS_MOUNT_DIR", path_mount_rdonly);
  options_manager.SetValue("CVMFS_AUTO_UPDATE", "no");
  options_manager.SetValue("CVMFS_NFS_SOURCE", "no");
  options_manager.SetValue("CVMFS_HIDE_MAGIC_XATTRS", "yes");
  options_manager.SetValue("CVMFS_SERVER_CACHE_MODE", "yes");
  options_manager.SetValue("CVMFS_USYSLOG", path_usyslog);
  options_manager.SetValue("CVMFS_RELOAD_SOCKETS", path_cache);
  options_manager.SetValue("CVMFS_WORKSPACE", path_cache);
  options_manager.SetValue("CVMFS_CACHE_PRIMARY", "private");
  options_manager.SetValue("CVMFS_CACHE_private_TYPE", "posix");
  options_manager.SetValue("CVMFS_CACHE_private_BASE", path_cache);
  options_manager.SetValue("CVMFS_CACHE_private_SHARED", "on");
  options_manager.SetValue("CVMFS_CACHE_private_QUOTA_LIMIT", "4000");
  options_manager.SetValue("CVMFS_NFILES", "65538");
  options_manager.SetValue("CVMFS_HTTP_PROXY", "auto");
  options_manager.SetValue("CVMFS_PAC_URLS", "http://wlcg-wpad.cern.ch/wpad.dat;http://wlcg-wpad.fnal.gov/wpad.dat");
  options_manager.SetValue("CVMFS_SERVER_URL", "http://cvmfs-stratum-one.cern.ch/cvmfs/@fqrn@");
  options_manager.SetValue("CVMFS_KEYS_DIR", "/home/jakob/Documents/CERN/git/src/mount/keys");
  rvb = SafeWriteToFile(options_manager.Dump(), path_config, kPrivateFileMode);

  vector<string> args;
  args.push_back("-o");
  args.push_back("config=" + path_config);
  args.push_back(fqrn);
  args.push_back(path_mount_rdonly);
  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  pid_t pid_cvmfs;
  rvb = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr, path_cvmfs2, args,
                      false, &pid_cvmfs);
  if (!rvb) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s", path_cvmfs2.c_str());
    return 32;
  }
  close(fd_stdin);

  int exit_code = WaitForChild(pid_cvmfs);
  if (exit_code != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failure mounting");
    return 1;
  }
  LogCvmfs(kLogCvmfs, kLogStdout, "mounted read-only branch");

  LogCvmfs(kLogCvmfs, kLogStdout, "mounting union file system");
  vector<string> args_ovl;
  args_ovl.push_back("-o");
  args_ovl.push_back(string("lowerdir=") + path_mount_rdonly +
                     ",upperdir=" + path_mount_scratch +
                     ",workdir=" + path_ovl_work);
  args_ovl.push_back(path_mount_union);
  pid_t pid_ovl;
  rvb = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
                      "/home/jakob/Documents/CERN/git/fuse-overlayfs",
                      args_ovl, false, &pid_ovl);
  if (!rvb) EPublish("failed to mount ovl");
  exit_code = WaitForChild(pid_ovl);
  if (exit_code != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failure mounting ovl");
    //return 1;
  }

  LogCvmfs(kLogCvmfs, kLogStdout, "union file system mounted");

  rvb = BindMount(path_mount_union, "/cvmfs");
  if (!rvb) throw EPublish("cannot bind mount to /cvmfs");

  rvb = CreateUserNamespace(uid, gid);
  if (!rvb) throw EPublish("cannot create user namespace");

  LogCvmfs(kLogCvmfs, kLogStdout, "dropping credentials to %d/%d", uid, gid);
  rvb = SwitchCredentials(uid, gid, false);
  if (!rvb) throw EPublish("cannot drop privileges");

  rvi = setenv("PS1", "[CernVM-FS Transaction] ", 1 /* overwrite */);
  assert(rvi == 0);
  std::vector<std::string> cmdline;
  cmdline.push_back(GetShell());
  std::set<int> preserved_fds;
  preserved_fds.insert(0);
  preserved_fds.insert(1);
  preserved_fds.insert(2);
  pid_t pid_child;
  rvb = ManagedExec(cmdline, preserved_fds, std::map<int, int>(),
                    false /* drop_credentials */, false /* double_fork*/,
                    &pid_child);
  exit_code = WaitForChild(pid_child);

  LogCvmfs(kLogCvmfs, kLogStdout,
           "exiting pid namespace including process cleanup (%d)", exit_code);

  return 0;
}

}  // namespace publish
<|endoftext|>


<commit_before>/* Copyright (c) 2011-2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>

#include "Core/Debug.h"
#include "Core/Util.h"
#include "Storage/FilesystemUtil.h"

namespace LogCabin {
namespace Storage {
namespace FilesystemUtil {

std::vector<std::string>
ls(const std::string& path)
{
    DIR* dir = opendir(path.c_str());
    if (dir == NULL) {
        PANIC("Could not list contents of %s: %s",
              path.c_str(), strerror(errno));
    }

    std::vector<std::string> contents;
    while (true) {
        struct dirent entry;
        struct dirent* entryp;
        if (readdir_r(dir, &entry, &entryp) != 0) {
            PANIC("readdir(%s) failed: %s",
                  path.c_str(), strerror(errno));
        }
        if (entryp == NULL) // no more entries
            break;
        const std::string name = entry.d_name;
        if (name == "." || name == "..")
            continue;
        contents.push_back(name);
    }

    if (closedir(dir) != 0) {
        WARNING("closedir(%s) failed: %s",
                path.c_str(), strerror(errno));
    }

    return contents;
}

void
remove(const std::string& path)
{
    while (true) {
        if (::remove(path.c_str()) == 0)
            return;
        if (errno == ENOENT) {
            return;
        } else if (errno == EEXIST || errno == ENOTEMPTY) {
            std::vector<std::string> children = ls(path);
            for (auto it = children.begin(); it != children.end(); ++it)
                remove(path + "/" + *it);
            continue;
        } else {
            PANIC("Could not remove %s: %s", path.c_str(), strerror(errno));
        }
    }
}

void
syncDir(const std::string& path)
{
    int fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) {
        PANIC("Could not open %s: %s",
              path.c_str(), strerror(errno));
    }
    if (fsync(fd) != 0) {
        PANIC("Could not fsync %s: %s",
              path.c_str(), strerror(errno));
    }
    if (close(fd) != 0) {
        WARNING("Failed to close file %s: %s",
                path.c_str(), strerror(errno));
    }
}

std::string
tmpnam()
{
    char d[L_tmpnam];
    std::string path = ::tmpnam(d);
    assert(path != "" && path != "/");
    return path;
}

namespace System {
#if DEBUG
// This is mocked out in some unit tests.
ssize_t (*writev)(int fildes,
                  const struct iovec* iov,
                  int iovcnt) = ::writev;
#else
using ::writev;
#endif
}

ssize_t
write(int fildes, const void* data, uint32_t dataLen)
{
    return write(fildes, {{data, dataLen}});
}

ssize_t
write(int fildes,
       std::initializer_list<std::pair<const void*, uint32_t>> data)
{
    size_t totalBytes = 0;
    uint32_t iovcnt = Core::Util::downCast<uint32_t>(data.size());
    struct iovec iov[iovcnt];
    uint32_t i = 0;
    for (auto it = data.begin(); it != data.end(); ++it) {
        iov[i].iov_base = const_cast<void*>(it->first);
        iov[i].iov_len = it->second;
        totalBytes += it->second;
        ++i;
    }

    size_t bytesRemaining = totalBytes;
    while (true) {
         ssize_t written = System::writev(fildes, iov, iovcnt);
         if (written == -1) {
             if (errno == EINTR)
                 continue;
             return -1;
         }
         bytesRemaining -= written;
         if (bytesRemaining == 0)
             return totalBytes;
         for (uint32_t i = 0; i < iovcnt; ++i) {
             if (iov[i].iov_len < static_cast<size_t>(written)) {
                 written -= iov[i].iov_len;
                 iov[i].iov_len = 0;
             } else if (iov[i].iov_len >= static_cast<size_t>(written)) {
                 iov[i].iov_len -= written;
                 iov[i].iov_base = (static_cast<char*>(iov[i].iov_base) +
                                    written);
                 break;
             }
         }
    }
}

// class FileContents

FileContents::FileContents(const std::string& path)
    : path(path)
    , fd(-1)
    , fileLen(0)
    , map(NULL)
{
    fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) {
        PANIC("Could not open %s: %s",
              path.c_str(), strerror(errno));
    }
    struct stat stat;
    if (fstat(fd, &stat) != 0) {
        PANIC("Could not stat %s: %s",
              path.c_str(), strerror(errno));
    }
    if (stat.st_size > ~0U) {
        PANIC("File %s too big",
              path.c_str());
    }
    fileLen = Core::Util::downCast<uint32_t>(stat.st_size);

    map = mmap(NULL, fileLen, PROT_READ, MAP_SHARED, fd, 0);
    if (map == NULL) {
        PANIC("Could not map %s: %s",
              path.c_str(), strerror(errno));
    }
}

FileContents::~FileContents()
{
    if (munmap(const_cast<void*>(map), fileLen) != 0) {
        WARNING("Failed to munmap file %s: %s",
                path.c_str(), strerror(errno));
    }
    if (close(fd) != 0) {
        WARNING("Failed to close file %s: %s",
                path.c_str(), strerror(errno));
    }
}

void
FileContents::copy(uint32_t offset, void* buf, uint32_t length)
{
    if (copyPartial(offset, buf, length) != length) {
        PANIC("File %s too short or corrupt",
              path.c_str());
    }
}

uint32_t
FileContents::copyPartial(uint32_t offset, void* buf, uint32_t maxLength)
{
    if (offset >= fileLen)
        return 0;
    uint32_t length = std::min(fileLen - offset, maxLength);
    memcpy(buf, static_cast<const char*>(map) + offset, length);
    return length;
}

const void*
FileContents::getHelper(uint32_t offset, uint32_t length)
{
    if (length != 0 && offset + length > fileLen) {
        PANIC("File %s too short or corrupt",
              path.c_str());
    }
    return static_cast<const char*>(map) + offset;
}

} // namespace LogCabin::Storage::FilesystemUtil
} // namespace LogCabin::Storage
} // namespace LogCabin
<commit_msg>Fix non-debug build<commit_after>/* Copyright (c) 2011-2012 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>

#include "Core/Debug.h"
#include "Core/Util.h"
#include "Storage/FilesystemUtil.h"

namespace LogCabin {
namespace Storage {
namespace FilesystemUtil {

std::vector<std::string>
ls(const std::string& path)
{
    DIR* dir = opendir(path.c_str());
    if (dir == NULL) {
        PANIC("Could not list contents of %s: %s",
              path.c_str(), strerror(errno));
    }

    std::vector<std::string> contents;
    while (true) {
        struct dirent entry;
        struct dirent* entryp;
        if (readdir_r(dir, &entry, &entryp) != 0) {
            PANIC("readdir(%s) failed: %s",
                  path.c_str(), strerror(errno));
        }
        if (entryp == NULL) // no more entries
            break;
        const std::string name = entry.d_name;
        if (name == "." || name == "..")
            continue;
        contents.push_back(name);
    }

    if (closedir(dir) != 0) {
        WARNING("closedir(%s) failed: %s",
                path.c_str(), strerror(errno));
    }

    return contents;
}

void
remove(const std::string& path)
{
    while (true) {
        if (::remove(path.c_str()) == 0)
            return;
        if (errno == ENOENT) {
            return;
        } else if (errno == EEXIST || errno == ENOTEMPTY) {
            std::vector<std::string> children = ls(path);
            for (auto it = children.begin(); it != children.end(); ++it)
                remove(path + "/" + *it);
            continue;
        } else {
            PANIC("Could not remove %s: %s", path.c_str(), strerror(errno));
        }
    }
}

void
syncDir(const std::string& path)
{
    int fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) {
        PANIC("Could not open %s: %s",
              path.c_str(), strerror(errno));
    }
    if (fsync(fd) != 0) {
        PANIC("Could not fsync %s: %s",
              path.c_str(), strerror(errno));
    }
    if (close(fd) != 0) {
        WARNING("Failed to close file %s: %s",
                path.c_str(), strerror(errno));
    }
}

std::string
tmpnam()
{
    char d[L_tmpnam];
    std::string path = ::tmpnam(d);
    assert(path != "" && path != "/");
    return path;
}

namespace System {
// This is mocked out in some unit tests.
ssize_t (*writev)(int fildes,
                  const struct iovec* iov,
                  int iovcnt) = ::writev;
}

ssize_t
write(int fildes, const void* data, uint32_t dataLen)
{
    return write(fildes, {{data, dataLen}});
}

ssize_t
write(int fildes,
       std::initializer_list<std::pair<const void*, uint32_t>> data)
{
    size_t totalBytes = 0;
    uint32_t iovcnt = Core::Util::downCast<uint32_t>(data.size());
    struct iovec iov[iovcnt];
    uint32_t i = 0;
    for (auto it = data.begin(); it != data.end(); ++it) {
        iov[i].iov_base = const_cast<void*>(it->first);
        iov[i].iov_len = it->second;
        totalBytes += it->second;
        ++i;
    }

    size_t bytesRemaining = totalBytes;
    while (true) {
         ssize_t written = System::writev(fildes, iov, iovcnt);
         if (written == -1) {
             if (errno == EINTR)
                 continue;
             return -1;
         }
         bytesRemaining -= written;
         if (bytesRemaining == 0)
             return totalBytes;
         for (uint32_t i = 0; i < iovcnt; ++i) {
             if (iov[i].iov_len < static_cast<size_t>(written)) {
                 written -= iov[i].iov_len;
                 iov[i].iov_len = 0;
             } else if (iov[i].iov_len >= static_cast<size_t>(written)) {
                 iov[i].iov_len -= written;
                 iov[i].iov_base = (static_cast<char*>(iov[i].iov_base) +
                                    written);
                 break;
             }
         }
    }
}

// class FileContents

FileContents::FileContents(const std::string& path)
    : path(path)
    , fd(-1)
    , fileLen(0)
    , map(NULL)
{
    fd = open(path.c_str(), O_RDONLY);
    if (fd == -1) {
        PANIC("Could not open %s: %s",
              path.c_str(), strerror(errno));
    }
    struct stat stat;
    if (fstat(fd, &stat) != 0) {
        PANIC("Could not stat %s: %s",
              path.c_str(), strerror(errno));
    }
    if (stat.st_size > ~0U) {
        PANIC("File %s too big",
              path.c_str());
    }
    fileLen = Core::Util::downCast<uint32_t>(stat.st_size);

    map = mmap(NULL, fileLen, PROT_READ, MAP_SHARED, fd, 0);
    if (map == NULL) {
        PANIC("Could not map %s: %s",
              path.c_str(), strerror(errno));
    }
}

FileContents::~FileContents()
{
    if (munmap(const_cast<void*>(map), fileLen) != 0) {
        WARNING("Failed to munmap file %s: %s",
                path.c_str(), strerror(errno));
    }
    if (close(fd) != 0) {
        WARNING("Failed to close file %s: %s",
                path.c_str(), strerror(errno));
    }
}

void
FileContents::copy(uint32_t offset, void* buf, uint32_t length)
{
    if (copyPartial(offset, buf, length) != length) {
        PANIC("File %s too short or corrupt",
              path.c_str());
    }
}

uint32_t
FileContents::copyPartial(uint32_t offset, void* buf, uint32_t maxLength)
{
    if (offset >= fileLen)
        return 0;
    uint32_t length = std::min(fileLen - offset, maxLength);
    memcpy(buf, static_cast<const char*>(map) + offset, length);
    return length;
}

const void*
FileContents::getHelper(uint32_t offset, uint32_t length)
{
    if (length != 0 && offset + length > fileLen) {
        PANIC("File %s too short or corrupt",
              path.c_str());
    }
    return static_cast<const char*>(map) + offset;
}

} // namespace LogCabin::Storage::FilesystemUtil
} // namespace LogCabin::Storage
} // namespace LogCabin
<|endoftext|>


<commit_before>// cc_lang.cc            see license.txt for copyright and terms of use
// code for cc_lang.h

#include "cc_lang.h"     // this module

#include <string.h>      // memset

void CCLang::ANSI_C()
{
  // just in case I forget to initialize something....
  memset(this, 0, sizeof(*this));

  tagsAreTypes = false;
  recognizeCppKeywords = false;
  implicitFuncVariable = false;
  gccFuncBehavior = GFB_none;
  noInnerClasses = true;
  uninitializedGlobalDataIsCommon = true;
  emptyParamsMeansPureVarargFunc = false;
  complainUponBadDeref = true;
  strictArraySizeRequirements = false;
  allowOverloading = false;
  compoundSelfName = false;
  allowCallToUndeclFunc = false;
  allow_KR_ParamOmit = false;
  allowImplicitInt = true;
  allowDynamicallySizedArrays = false;
  allowIncompleteEnums = false;
  declareGNUBuiltins = false;

  isCplusplus = false;
  isC99 = false;
}

void CCLang::KandR_C()
{
  ANSI_C();

  emptyParamsMeansPureVarargFunc = true;
  allowCallToUndeclFunc = true;
  allow_KR_ParamOmit = true;
  allowImplicitInt = true;
}

void CCLang::ANSI_C99()
{
  ANSI_C();

  implicitFuncVariable = true;
  allowImplicitInt = false;
  isC99 = true;
}

void CCLang::GNU_C()
{
  ANSI_C99();

  allowImplicitInt = true;
  gccFuncBehavior = GFB_string;
  allowDynamicallySizedArrays = true;
  declareGNUBuiltins = true;

  // I'm just guessing this is GNU only.... yep:
  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Incomplete-Enums.html
  allowIncompleteEnums = true;
}

void CCLang::GNU_KandR_C()
{
  KandR_C();

  implicitFuncVariable = true;
  gccFuncBehavior = GFB_string;
  allowDynamicallySizedArrays = true;

  // this seems wrong, but Oink's tests want it this way...
  isC99 = true;
}

void CCLang::ANSI_Cplusplus()
{
  tagsAreTypes = true;
  recognizeCppKeywords = true;
  implicitFuncVariable = false;
  gccFuncBehavior = GFB_none;
  noInnerClasses = false;
  uninitializedGlobalDataIsCommon = false;
  emptyParamsMeansPureVarargFunc = false;

  // these aren't exactly ANSI C++; they might be "pragmatic C++"
  // for the current state of the parser
  complainUponBadDeref = false;
  strictArraySizeRequirements = false;

  allowOverloading = true;
  compoundSelfName = true;

  allowCallToUndeclFunc = false;
  allow_KR_ParamOmit = false;
  allowImplicitInt = false;
  allowDynamicallySizedArrays = false;
  allowIncompleteEnums = false;
  declareGNUBuiltins = false;

  isCplusplus = true;
  isC99 = false;
}

void CCLang::GNU_Cplusplus()
{
  ANSI_Cplusplus();

  gccFuncBehavior = GFB_variable;

  // is this really right?  Oink tests it like it is ...
  allowDynamicallySizedArrays = true;

  declareGNUBuiltins = true;
}

// EOF
<commit_msg>I guess K&R is GNU K&R<commit_after>// cc_lang.cc            see license.txt for copyright and terms of use
// code for cc_lang.h

#include "cc_lang.h"     // this module

#include <string.h>      // memset

void CCLang::ANSI_C()
{
  // just in case I forget to initialize something....
  memset(this, 0, sizeof(*this));

  tagsAreTypes = false;
  recognizeCppKeywords = false;
  implicitFuncVariable = false;
  gccFuncBehavior = GFB_none;
  noInnerClasses = true;
  uninitializedGlobalDataIsCommon = true;
  emptyParamsMeansPureVarargFunc = false;
  complainUponBadDeref = true;
  strictArraySizeRequirements = false;
  allowOverloading = false;
  compoundSelfName = false;
  allowCallToUndeclFunc = false;
  allow_KR_ParamOmit = false;
  allowImplicitInt = true;
  allowDynamicallySizedArrays = false;
  allowIncompleteEnums = false;
  declareGNUBuiltins = false;

  isCplusplus = false;
  isC99 = false;
}

void CCLang::KandR_C()
{
  ANSI_C();

  emptyParamsMeansPureVarargFunc = true;
  allowCallToUndeclFunc = true;
  allow_KR_ParamOmit = true;
  allowImplicitInt = true;

  // our K&R is really GNU K&R ...
  declareGNUBuiltins = true;
}

void CCLang::ANSI_C99()
{
  ANSI_C();

  implicitFuncVariable = true;
  allowImplicitInt = false;
  isC99 = true;
}

void CCLang::GNU_C()
{
  ANSI_C99();

  allowImplicitInt = true;
  gccFuncBehavior = GFB_string;
  allowDynamicallySizedArrays = true;
  declareGNUBuiltins = true;

  // I'm just guessing this is GNU only.... yep:
  // http://gcc.gnu.org/onlinedocs/gcc-3.1/gcc/Incomplete-Enums.html
  allowIncompleteEnums = true;
}

void CCLang::GNU_KandR_C()
{
  KandR_C();

  implicitFuncVariable = true;
  gccFuncBehavior = GFB_string;
  allowDynamicallySizedArrays = true;

  // this seems wrong, but Oink's tests want it this way...
  isC99 = true;
}

void CCLang::ANSI_Cplusplus()
{
  tagsAreTypes = true;
  recognizeCppKeywords = true;
  implicitFuncVariable = false;
  gccFuncBehavior = GFB_none;
  noInnerClasses = false;
  uninitializedGlobalDataIsCommon = false;
  emptyParamsMeansPureVarargFunc = false;

  // these aren't exactly ANSI C++; they might be "pragmatic C++"
  // for the current state of the parser
  complainUponBadDeref = false;
  strictArraySizeRequirements = false;

  allowOverloading = true;
  compoundSelfName = true;

  allowCallToUndeclFunc = false;
  allow_KR_ParamOmit = false;
  allowImplicitInt = false;
  allowDynamicallySizedArrays = false;
  allowIncompleteEnums = false;
  declareGNUBuiltins = false;

  isCplusplus = true;
  isC99 = false;
}

void CCLang::GNU_Cplusplus()
{
  ANSI_Cplusplus();

  gccFuncBehavior = GFB_variable;

  // is this really right?  Oink tests it like it is ...
  allowDynamicallySizedArrays = true;

  declareGNUBuiltins = true;
}

// EOF
<|endoftext|>


<commit_before>#include "parser.hh"
#include "test.hh"
#include <string>

TEST_SUITE(
    nolang::Parser parser;

    TEST_CASE(basic_parser,
        std::string data = "";

        data += "main =>\n";
        data += "    40 + 2";

        parser.parse("test.nolang", data);

        TEST_ASSERT_TRUE(parser.success())
    )

)
<commit_msg>Fix test<commit_after>#include "parser.hh"
#include "test.hh"
#include <string>

TEST_SUITE(
    nolang::Parser parser;

    TEST_CASE(basic_parser,
        std::string data = "";

        data += "main =>\n";
        data += "    40 + 2\n";

        parser.parse("test.nolang", data);

        TEST_ASSERT_TRUE(parser.success())
    )

)
<|endoftext|>


<commit_before>#ifndef UTILITY_HPP
#define UTILITY_HPP

#include <iterator>
#include <sstream>
#include <utility>
#include <vector>

#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Window/Keyboard.hpp>

namespace sf
{
    class Sprite;
    class Text;
}

namespace utils
{

// Since std::to_string doesn't work on MinGW we have to implement
// our own to support all platforms.

template <typename T>
std::string        toString(const T& value);

// Convert enumerators to strings.

std::string        toString(sf::Keyboard::Key key);

// Call setOrigin() with the center of the object.

void               centerOrigin(sf::Sprite& sprite);
void               centerOrigin(sf::Text& text);

// Degree/radian conversion.

float              toDegree(const float radian);
float              toRadian(const float degree);

// Random number generation.

int                randomInt(const int exclusiveMax);

// Mathematic cector operations.

float              length(const sf::Vector2f vector);
sf::Vector2f       unitVector(const sf::Vector2f vector);

// Debug operations.

sf::RectangleShape buildBorderLines(const sf::Vector2f position, const sf::Vector2f size,
                                    const sf::Color fillColor, const sf::Color outlineColor,
                                    const float outlineThickness);

sf::RectangleShape buildBorderLines(const sf::FloatRect rect, const sf::Color fillColor,
                                    const sf::Color outlineColor, const float outlineThickness);

// Copy for smart pointers.

template <class T>
std::unique_ptr<T> copyUnique(const std::unique_ptr<T>& source);

// Copy and move operation with std::vector's.

template <typename T>
typename std::vector<T>::iterator append(std::vector<T>& dest, const std::vector<T>& src);

template <typename T>
typename std::vector<T>::iterator append(std::vector<T>& dest, std::vector<T>&& src);

} // namespace utils

#include "utility.inl"

#endif // UTILITY_HPP
<commit_msg>Fix missed <memory> header in utility<commit_after>#ifndef UTILITY_HPP
#define UTILITY_HPP

#include <iterator>
#include <memory>
#include <sstream>
#include <utility>
#include <vector>

#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Window/Keyboard.hpp>

namespace sf
{
    class Sprite;
    class Text;
}

namespace utils
{

// Since std::to_string doesn't work on MinGW we have to implement
// our own to support all platforms.

template <typename T>
std::string        toString(const T& value);

// Convert enumerators to strings.

std::string        toString(sf::Keyboard::Key key);

// Call setOrigin() with the center of the object.

void               centerOrigin(sf::Sprite& sprite);
void               centerOrigin(sf::Text& text);

// Degree/radian conversion.

float              toDegree(const float radian);
float              toRadian(const float degree);

// Random number generation.

int                randomInt(const int exclusiveMax);

// Mathematic cector operations.

float              length(const sf::Vector2f vector);
sf::Vector2f       unitVector(const sf::Vector2f vector);

// Debug operations.

sf::RectangleShape buildBorderLines(const sf::Vector2f position, const sf::Vector2f size,
                                    const sf::Color fillColor, const sf::Color outlineColor,
                                    const float outlineThickness);

sf::RectangleShape buildBorderLines(const sf::FloatRect rect, const sf::Color fillColor,
                                    const sf::Color outlineColor, const float outlineThickness);

// Copy for smart pointers.

template <class T>
std::unique_ptr<T> copyUnique(const std::unique_ptr<T>& source);

// Copy and move operation with std::vector's.

template <typename T>
typename std::vector<T>::iterator append(std::vector<T>& dest, const std::vector<T>& src);

template <typename T>
typename std::vector<T>::iterator append(std::vector<T>& dest, std::vector<T>&& src);

} // namespace utils

#include "utility.inl"

#endif // UTILITY_HPP
<|endoftext|>


<commit_before>#include <Track.h>
#include <iostream>
#include <string>

using namespace SoundCity;
using namespace std;

int main()
{
  Artist artist(1, "The White Stripes", 0.4, 1.0);
  //cout << artist.getName() << endl;
  Album album(1, "Elephant", "The White Stripes", 2012);
  //cout << album.getArtist() << endl;
  ContextData data(artist, album, 0.5);
  //cout << data.getArtistName() << endl;
  SignalData sign(0.2,0.3,0.4);
  Track test(1, sign ,data);
  cout << "Track id : " << test.getId() << endl;
  cout << "Artist id : " << test.getContextData().getArtist().getId() << endl;
  cout << "Artist name : " <<  test.getContextData().getArtist().getName() << endl;
  cout << "Artist familiarity : " << test.getContextData().getArtist().getFamiliarity() << endl;
  cout << "Artist popularity : " << test.getContextData().getArtist().getPopularity() << endl;
  cout << "Album Title : " << test.getContextData().getAlbum().getTitle() << endl;
  cout << "Album Artist : " << test.getContextData().getAlbum().getArtist() << endl;
  cout << "Album Release : " << test.getContextData().getAlbum().getReleaseDate() << endl;
  cout << "Track Popularity : " << test.getContextData().getPopularity() << endl;
  cout << "Track Rhythm : " << test.getSignalData().getRhythm() << endl;
  cout << "Track Energy : " << test.getSignalData().getEnergy() << endl;
  cout << "Track Tonality : " << test.getSignalData().getTonality() << endl;
}
<commit_msg>Mise à jour du test avec le titre du morceau<commit_after>#include <Track.h>
#include <iostream>
#include <string>

using namespace SoundCity;
using namespace std;

int main()
{
  Artist artist(1, "The White Stripes", 0.4, 1.0);
  //cout << artist.getName() << endl;
  Album album(1, "Elephant", "The White Stripes", 2012);
  //cout << album.getArtist() << endl;
  ContextData data(artist, album, 0.5);
  //cout << data.getArtistName() << endl;
  SignalData sign(0.2,0.3,0.4);
  Track test(1, "Seven Nations Army", sign ,data);
  cout << "Track id : " << test.getId() << endl;
  cout << "Track Title : " << test.getTitle() << endl;
  cout << "Artist id : " << test.getContextData().getArtist().getId() << endl;
  cout << "Artist name : " <<  test.getContextData().getArtist().getName() << endl;
  cout << "Artist familiarity : " << test.getContextData().getArtist().getFamiliarity() << endl;
  cout << "Artist popularity : " << test.getContextData().getArtist().getPopularity() << endl;
  cout << "Album Title : " << test.getContextData().getAlbum().getTitle() << endl;
  cout << "Album Artist : " << test.getContextData().getAlbum().getArtist() << endl;
  cout << "Album Release : " << test.getContextData().getAlbum().getReleaseDate() << endl;
  cout << "Track Popularity : " << test.getContextData().getPopularity() << endl;
  cout << "Track Rhythm : " << test.getSignalData().getRhythm() << endl;
  cout << "Track Energy : " << test.getSignalData().getEnergy() << endl;
  cout << "Track Tonality : " << test.getSignalData().getTonality() << endl;
}
<|endoftext|>


<commit_before>/***********************************************************************************
**
** WalkData.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "WalkData.h"
//----------------------------------------------------------------------------------
void CWalkData::GetOffset(float &x, float &y, float &steps)
{
	uchar dir = m_Direction + 1;

	float step_NESW_D = 44.0f / steps; //NW NE SW SE
	float step_NESW = 22.0f / steps; //N E S W

	switch (dir & 7)
	{
		case 0: //NW
		{
			x = 0.0f;
			y *= -step_NESW_D;
			break;
		}
		case 1: //N
		{
			x *= step_NESW;
			y *= -step_NESW;
			break;
		}
		case 2: //NE
		{
			x *= step_NESW_D;
			y = 0.0f;
			break;
		}
		case 3: //E
		{
			x *= step_NESW;
			y *= step_NESW;
			break;
		}
		case 4: //SE
		{
			x = 0.0f;
			y *= step_NESW_D;
			break;
		}
		case 5: //S
		{
			x *= -step_NESW;
			y *= step_NESW;
			break;
		}
		case 6: //SW
		{
			x *= -step_NESW_D;
			y = 0.0f;
			break;
		}
		case 7: //W
		{
			x *= -step_NESW;
			y *= -step_NESW;
			break;
		}
		default:
			break;
	}
}
//----------------------------------------------------------------------------------
<commit_msg>Привел в нормальное состояние функцию для расчета смещений анимации персонажей при перемещении.<commit_after>/***********************************************************************************
**
** WalkData.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "WalkData.h"
//----------------------------------------------------------------------------------
void CWalkData::GetOffset(float &x, float &y, float &steps)
{
	float step_NESW_D = 44.0f / steps; //NW NE SW SE
	float step_NESW = 22.0f / steps; //N E S W

	switch (m_Direction & 7)
	{
		case 0: //W
		{
			x *= step_NESW;
			y *= -step_NESW;
			break;
		}
		case 1: //NW
		{
			x *= step_NESW_D;
			y = 0.0f;
			break;
		}
		case 2: //N
		{
			x *= step_NESW;
			y *= step_NESW;
			break;
		}
		case 3: //NE
		{
			x = 0.0f;
			y *= step_NESW_D;
			break;
		}
		case 4: //E
		{
			x *= -step_NESW;
			y *= step_NESW;
			break;
		}
		case 5: //SE
		{
			x *= -step_NESW_D;
			y = 0.0f;
			break;
		}
		case 6: //S
		{
			x *= -step_NESW;
			y *= -step_NESW;
			break;
		}
		case 7: //SW
		{
			x = 0.0f;
			y *= -step_NESW_D;
			break;
		}
		default:
			break;
	}
}
//----------------------------------------------------------------------------------
<|endoftext|>


<commit_before>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        unit_tests.cpp
 * @brief       iutest test
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2013-2018, Takazumi Shirayanagi\n
 * The new BSD License is applied to this software.
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include "iutest.hpp"
#include "internal/iutest_filepath.hpp"

class Base {};
class Derived : public Base {};
class Hoge {};

typedef int inttype;

IUTEST(UnitTest, is_class)
{
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_class<int>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_class<Base>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_class<Derived>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_class<void (*)()>::value );
}

IUTEST(UnitTest, is_same)
{
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_same<int, char>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_same<int, int>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_same<int, inttype>::value) );
}

IUTEST(UnitTest, is_void)
{
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_void<void*>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_void<void>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_void<int>::value );
}

IUTEST(UnitTest, is_base_of)
{
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_base_of<int, Base>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Base, Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Base, const Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<const volatile Base, Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<volatile Base, volatile Derived const>::value) );
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_base_of<Base, Hoge>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Derived, Derived>::value) );
}

#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)

struct X
{
    int a, b, c;
};
struct Y
{
    int a, b, c;
    bool operator == (const Y&) { return true; }
};

struct Z
{
    int a, b, c;
};

bool operator == (const Z&, const Z&) { return true; }

IUTEST(UnitTest, has_equal_to)
{
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<int>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<float>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::has_equal_to<X>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Y>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Z>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to< ::std::vector<int> >::value );
}

#if IUTEST_HAS_TUPLE
typedef ::iutest::tuples::tuple<bool, int, int> Tuple;

IUTEST(UnitTest, has_equal_to_tuple)
{
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Tuple>::value );
}
#endif

#endif

IUTEST(UnitTest, StringStrip)
{
    ::std::string str = "   a1 a2  ";
    IUTEST_EXPECT_STREQ("a1 a2  " , ::iutest::detail::StripLeadingSpace(str));
    IUTEST_EXPECT_STREQ("   a1 a2", ::iutest::detail::StripTrailingSpace(str));
    IUTEST_EXPECT_STREQ("a1 a2"   , ::iutest::detail::StripSpace(str));
}

IUTEST(UnitTest, StringReplace)
{
    ::std::string str = "a1a2a3a4b5";
    ::iutest::detail::StringReplace(str, 'a', "ii");
    IUTEST_EXPECT_STREQ("ii1ii2ii3ii4b5", str);
}

IUTEST(UnitTest, StringReplaceToLF)
{
    ::std::string str = "a\r\nb\r\rc\r\n\nd";
    ::iutest::detail::StringReplaceToLF(str);
    IUTEST_EXPECT_STREQ("a\nb\n\nc\n\nd", str);
}

IUTEST(UnitTest, AddDefaultPackageName)
{
    IUTEST_EXPECT_STREQ("Test.a1a2a3a4b5", ::iutest::TestEnv::AddDefaultPackageName("a1a2a3a4b5"));
    IUTEST_EXPECT_STREQ("Hoge.a1a2a3a4b5", ::iutest::TestEnv::AddDefaultPackageName("Hoge.a1a2a3a4b5"));
}

class HackXmlGeneratorListener : public ::iutest::DefaultXmlGeneratorListener
{
public:
    using DefaultXmlGeneratorListener::EscapeXmlAttribute;
    using DefaultXmlGeneratorListener::EscapeXmlText;
};

IUTEST(UnitTest, XmlEscape)
{
    IUTEST_EXPECT_STREQ("a<>	b& '"c
"
        , HackXmlGeneratorListener::EscapeXmlAttribute("a<>	b& \'\"c\r\n"));// NOLINT
    IUTEST_EXPECT_STREQ("a<>	b& \'\"c\r\n"                       // NOLINT
        , HackXmlGeneratorListener::EscapeXmlText("a<>	b& \'\"c\r\n"));    // NOLINT
}

IUTEST(UnitTest, FileLocation)
{
    ::iutest::IUTEST_FLAG(file_location_style_msvc) = false;
    IUTEST_EXPECT_STREQ("main.cpp:1"
        , ::iutest::detail::FormatFileLocation("main.cpp", 1) );
    IUTEST_EXPECT_STREQ("unknown file:1"
        , ::iutest::detail::FormatFileLocation(NULL, 1) );
    IUTEST_EXPECT_STREQ("main.cpp"
        , ::iutest::detail::FormatFileLocation("main.cpp", -1) );

    ::iutest::IUTEST_FLAG(file_location_style_msvc) = true;
    IUTEST_EXPECT_STREQ("main.cpp(1)"
        , ::iutest::detail::FormatFileLocation("main.cpp", 1) );
    IUTEST_EXPECT_STREQ("unknown file(1)"
        , ::iutest::detail::FormatFileLocation(NULL, 1) );
    IUTEST_EXPECT_STREQ("main.cpp"
        , ::iutest::detail::FormatFileLocation("main.cpp", -1) );
}

IUTEST(UnitTest, GetEnvironmentVariable)
{
    char buf[2];
    IUTEST_EXPECT_FALSE( ::iutest::detail::GetEnvironmentVariable("PATH", buf, sizeof(buf)) );
    IUTEST_EXPECT_FALSE( ::iutest::detail::GetEnvironmentVariable("PATH", NULL, 0) );
}

#if IUTEST_HAS_FILENO && IUTEST_HAS_FOPEN

IUTEST(StdFileUnitTest, AppendOpenedFileSize)
{
    ::iutest::StdioFile file;
    ::iutest::internal::FilePath filename(__FILE__);
    IUTEST_ASSUME_TRUE( filename.FileOrDirectoryExists() );
    IUTEST_ASSERT_TRUE( file.Open(filename.c_str(), iutest::IFile::OpenAppend) );
    IUTEST_ASSERT_LT(0u, file.GetSize());
}

#endif

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    ::iutest::IUTEST_FLAG(default_package_name) = "Test";
    return IUTEST_RUN_ALL_TESTS();
}

<commit_msg>fix warning<commit_after>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        unit_tests.cpp
 * @brief       iutest test
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2013-2018, Takazumi Shirayanagi\n
 * The new BSD License is applied to this software.
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include "iutest.hpp"
#include "internal/iutest_filepath.hpp"

class Base {};
class Derived : public Base {};
class Hoge {};

typedef int inttype;

IUTEST(UnitTest, is_class)
{
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_class<int>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_class<Base>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_class<Derived>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_class<void (*)()>::value );
}

IUTEST(UnitTest, is_same)
{
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_same<int, char>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_same<int, int>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_same<int, inttype>::value) );
}

IUTEST(UnitTest, is_void)
{
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_void<void*>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::is_void<void>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::is_void<int>::value );
}

IUTEST(UnitTest, is_base_of)
{
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_base_of<int, Base>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Base, Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Base, const Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<const volatile Base, Derived>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<volatile Base, volatile Derived const>::value) );
    IUTEST_STATIC_ASSERT( !(::iutest_type_traits::is_base_of<Base, Hoge>::value) );
    IUTEST_STATIC_ASSERT(  (::iutest_type_traits::is_base_of<Derived, Derived>::value) );
}

#if !defined(IUTEST_NO_ARGUMENT_DEPENDENT_LOOKUP)

struct X
{
    int a, b, c;
};
struct Y
{
    int a, b, c;
    bool operator == (const Y&) { return true; }
};

struct Z
{
    int a, b, c;
};

bool operator == (const Z&, const Z&) { return true; }

IUTEST(UnitTest, has_equal_to)
{
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<int>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<float>::value );
    IUTEST_STATIC_ASSERT( !::iutest_type_traits::has_equal_to<X>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Y>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Z>::value );
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to< ::std::vector<int> >::value );
}

#if IUTEST_HAS_TUPLE
typedef ::iutest::tuples::tuple<bool, int, int> Tuple;

IUTEST(UnitTest, has_equal_to_tuple)
{
    IUTEST_STATIC_ASSERT(  ::iutest_type_traits::has_equal_to<Tuple>::value );
}
#endif

#endif

IUTEST(UnitTest, StringStrip)
{
    ::std::string str = "   a1 a2  ";
    IUTEST_EXPECT_STREQ("a1 a2  " , ::iutest::detail::StripLeadingSpace(str));
    IUTEST_EXPECT_STREQ("   a1 a2", ::iutest::detail::StripTrailingSpace(str));
    IUTEST_EXPECT_STREQ("a1 a2"   , ::iutest::detail::StripSpace(str));
}

IUTEST(UnitTest, StringReplace)
{
    ::std::string str = "a1a2a3a4b5";
    ::iutest::detail::StringReplace(str, 'a', "ii");
    IUTEST_EXPECT_STREQ("ii1ii2ii3ii4b5", str);
}

IUTEST(UnitTest, StringReplaceToLF)
{
    ::std::string str = "a\r\nb\r\rc\r\n\nd";
    ::iutest::detail::StringReplaceToLF(str);
    IUTEST_EXPECT_STREQ("a\nb\n\nc\n\nd", str);
}

IUTEST(UnitTest, AddDefaultPackageName)
{
    IUTEST_EXPECT_STREQ("Test.a1a2a3a4b5", ::iutest::TestEnv::AddDefaultPackageName("a1a2a3a4b5"));
    IUTEST_EXPECT_STREQ("Hoge.a1a2a3a4b5", ::iutest::TestEnv::AddDefaultPackageName("Hoge.a1a2a3a4b5"));
}

class HackXmlGeneratorListener : public ::iutest::DefaultXmlGeneratorListener
{
    HackXmlGeneratorListener() : ::iutest::DefaultXmlGeneratorListener("") {}
public:
    using DefaultXmlGeneratorListener::EscapeXmlAttribute;
    using DefaultXmlGeneratorListener::EscapeXmlText;
};

IUTEST(UnitTest, XmlEscape)
{
    IUTEST_EXPECT_STREQ("a<>	b& '"c
"
        , HackXmlGeneratorListener::EscapeXmlAttribute("a<>	b& \'\"c\r\n"));// NOLINT
    IUTEST_EXPECT_STREQ("a<>	b& \'\"c\r\n"                       // NOLINT
        , HackXmlGeneratorListener::EscapeXmlText("a<>	b& \'\"c\r\n"));    // NOLINT
}

IUTEST(UnitTest, FileLocation)
{
    ::iutest::IUTEST_FLAG(file_location_style_msvc) = false;
    IUTEST_EXPECT_STREQ("main.cpp:1"
        , ::iutest::detail::FormatFileLocation("main.cpp", 1) );
    IUTEST_EXPECT_STREQ("unknown file:1"
        , ::iutest::detail::FormatFileLocation(NULL, 1) );
    IUTEST_EXPECT_STREQ("main.cpp"
        , ::iutest::detail::FormatFileLocation("main.cpp", -1) );

    ::iutest::IUTEST_FLAG(file_location_style_msvc) = true;
    IUTEST_EXPECT_STREQ("main.cpp(1)"
        , ::iutest::detail::FormatFileLocation("main.cpp", 1) );
    IUTEST_EXPECT_STREQ("unknown file(1)"
        , ::iutest::detail::FormatFileLocation(NULL, 1) );
    IUTEST_EXPECT_STREQ("main.cpp"
        , ::iutest::detail::FormatFileLocation("main.cpp", -1) );
}

IUTEST(UnitTest, GetEnvironmentVariable)
{
    char buf[2];
    IUTEST_EXPECT_FALSE( ::iutest::detail::GetEnvironmentVariable("PATH", buf, sizeof(buf)) );
    IUTEST_EXPECT_FALSE( ::iutest::detail::GetEnvironmentVariable("PATH", NULL, 0) );
}

#if IUTEST_HAS_FILENO && IUTEST_HAS_FOPEN

IUTEST(StdFileUnitTest, AppendOpenedFileSize)
{
    ::iutest::StdioFile file;
    ::iutest::internal::FilePath filename(__FILE__);
    IUTEST_ASSUME_TRUE( filename.FileOrDirectoryExists() );
    IUTEST_ASSERT_TRUE( file.Open(filename.c_str(), iutest::IFile::OpenAppend) );
    IUTEST_ASSERT_LT(0u, file.GetSize());
}

#endif

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    ::iutest::IUTEST_FLAG(default_package_name) = "Test";
    return IUTEST_RUN_ALL_TESTS();
}

<|endoftext|>


<commit_before>// "Walk Of Life" Data Structure Test
//Only ever include the data structure - insures only registered plugins work
#include "dataStructure.h"
#include <random>
#include <iostream>
using namespace std;

int main()
{
    //Random number stuff
    random_device seed;
    mt19937 gen(seed());
    uniform_real_distribution<double> randRange(0.0, 500.0);

    cout << "/////////////////////// Bin tests ///////////////////////\n";
    cout << "byType tests:\n";
    Bin bin(500, 500, 50);

    //Make 100 random dogs and flowers
    for(int numOfNodes = 0; numOfNodes < 100; ++numOfNodes)
    {
        bin.insert(new Flower(randRange(gen), randRange(gen)));
        bin.insert(new Dog(randRange(gen), randRange(gen)));
    }

    //Make every dog bark
    cout << "Doggie Chior:\n";
    for(const Dog& dog : bin.getAllOfType<Dog>())
        dog.bark();

    //Change somethings about every flower
    for(Flower& flower : bin.getAllOfType<Flower>())
    {
        flower.thingy = 1;
        flower.otherThingy();
        //bin.remove(&flower);
    }

    //Check all flowers
    cout << "\nFlower values:\n";
    for(const Flower& flower : bin.getAllOfType<Flower>())
    {
        cout << flower.thingy << " ";
        cout << flower.thingy2 << " ";
    }
    cout << endl;

    cout << "\nbyLocal tests:\n";

    Flower* myHeapFlower = new Flower(100, 100);
    bin.insert(myHeapFlower);
    //bin.remove(myHeapFlower);

    //Make 100 random dogs and flowers
    for(int numOfNodes = 0; numOfNodes < 100; ++numOfNodes)
    {
        bin.insert(new Flower(randRange(gen), randRange(gen)));
        bin.insert(new Dog(randRange(gen), randRange(gen)));
    }

    auto thingything = bin.getNear(myHeapFlower);
    cout << "Nearby flowers: " << thingything.size() << endl;

    cout << "All done!\n";
}
<commit_msg>Removed datTest.cpp From Main/<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pyuno_gc.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 16:52:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include <osl/thread.hxx>
#include <pyuno_impl.hxx>
namespace pyuno
{

bool g_destructorsOfStaticObjectsHaveBeenCalled;
class StaticDestructorGuard
{
public:
    ~StaticDestructorGuard()
    {
        g_destructorsOfStaticObjectsHaveBeenCalled = true;
    }
};
StaticDestructorGuard guard;

class GCThread : public ::osl::Thread
{
    PyObject *mPyObject;
    PyInterpreterState *mPyInterpreter;
    GCThread( const GCThread & ); // not implemented
    GCThread &operator =( const GCThread & ); // not implemented

public:
    GCThread( PyInterpreterState *interpreter, PyObject * object );
    virtual void SAL_CALL run();
    virtual void SAL_CALL onTerminated();
};

GCThread::GCThread( PyInterpreterState *interpreter, PyObject * object ) :
    mPyInterpreter( interpreter ), mPyObject( object )
{}

void GCThread::run()
{
    //  otherwise we crash here, when main has been left already
    if( g_destructorsOfStaticObjectsHaveBeenCalled )
        return;
    try
    {
        PyThreadAttach guard( (PyInterpreterState*)mPyInterpreter );
        {
            Runtime runtime;

            // remove the reference from the pythonobject2adapter map
            PyRef2Adapter::iterator ii =
                runtime.getImpl()->cargo->mappedObjects.find( mPyObject );
            if( ii != runtime.getImpl()->cargo->mappedObjects.end() )
            {
                runtime.getImpl()->cargo->mappedObjects.erase( ii );
            }

            Py_XDECREF( mPyObject );
        }
    }
    catch( com::sun::star::uno::RuntimeException & e )
    {
        rtl::OString msg;
        msg = rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US );
        fprintf( stderr, "Leaking python objects bridged to UNO for reason %s\n",msg.getStr());
    }
}

void GCThread::onTerminated()
{
    delete this;
}

void decreaseRefCount( PyInterpreterState *interpreter, PyObject *object )
{
    //  otherwise we crash in the last after main ...
    if( g_destructorsOfStaticObjectsHaveBeenCalled )
        return;

    // delegate to a new thread, because there does not seem
    // to be a method, which tells, whether the global
    // interpreter lock is held or not
    // TODO: Look for a more efficient solution
    osl::Thread *t = new GCThread( interpreter, object );
    t->create();
}

}
<commit_msg>INTEGRATION: CWS warnings01 (1.3.16); FILE MERGED 2005/09/23 02:08:41 sb 1.3.16.2: RESYNC: (1.3-1.4); FILE MERGED 2005/09/09 15:31:19 sb 1.3.16.1: #i53898# Made code warning-free.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pyuno_gc.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 05:03:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include <pyuno_impl.hxx>
#include <osl/thread.hxx>
namespace pyuno
{

bool g_destructorsOfStaticObjectsHaveBeenCalled;
class StaticDestructorGuard
{
public:
    ~StaticDestructorGuard()
    {
        g_destructorsOfStaticObjectsHaveBeenCalled = true;
    }
};
StaticDestructorGuard guard;

class GCThread : public ::osl::Thread
{
    PyObject *mPyObject;
    PyInterpreterState *mPyInterpreter;
    GCThread( const GCThread & ); // not implemented
    GCThread &operator =( const GCThread & ); // not implemented

public:
    GCThread( PyInterpreterState *interpreter, PyObject * object );
    virtual void SAL_CALL run();
    virtual void SAL_CALL onTerminated();
};

GCThread::GCThread( PyInterpreterState *interpreter, PyObject * object ) :
    mPyObject( object ), mPyInterpreter( interpreter )
{}

void GCThread::run()
{
    //  otherwise we crash here, when main has been left already
    if( g_destructorsOfStaticObjectsHaveBeenCalled )
        return;
    try
    {
        PyThreadAttach g( (PyInterpreterState*)mPyInterpreter );
        {
            Runtime runtime;

            // remove the reference from the pythonobject2adapter map
            PyRef2Adapter::iterator ii =
                runtime.getImpl()->cargo->mappedObjects.find( mPyObject );
            if( ii != runtime.getImpl()->cargo->mappedObjects.end() )
            {
                runtime.getImpl()->cargo->mappedObjects.erase( ii );
            }

            Py_XDECREF( mPyObject );
        }
    }
    catch( com::sun::star::uno::RuntimeException & e )
    {
        rtl::OString msg;
        msg = rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US );
        fprintf( stderr, "Leaking python objects bridged to UNO for reason %s\n",msg.getStr());
    }
}

void GCThread::onTerminated()
{
    delete this;
}

void decreaseRefCount( PyInterpreterState *interpreter, PyObject *object )
{
    //  otherwise we crash in the last after main ...
    if( g_destructorsOfStaticObjectsHaveBeenCalled )
        return;

    // delegate to a new thread, because there does not seem
    // to be a method, which tells, whether the global
    // interpreter lock is held or not
    // TODO: Look for a more efficient solution
    osl::Thread *t = new GCThread( interpreter, object );
    t->create();
}

}
<|endoftext|>