<commit_before>
#include "pch.h"
#include "slackapp.h"
#include "utils.h"

using namespace utility;              // Common utilities like string conversions
using namespace web;                  // Common features like URIs.
using namespace web::http;            // Common HTTP functionality
using namespace web::http::client;    // HTTP client features
using namespace concurrency::streams; // Asynchronous streams

//web::http::client::http_client::~http_client() noexcept {}

pplx::task<bool> slack_app::test_access_token(const string_t &access_token)
{
    printf("authing\n");
    auto path = U("auth.test?token=") + access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        return json.as_object()
            .at(U("ok"))
            .as_bool();
    });
}

pplx::task<utility::string_t> slack_app::get_userid(const string_t &access_token)
{
    auto path = U("auth.test?token=") + access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        return json.as_object()
            .at(U("user_id"))
            .as_string();
    });
}

pplx::task<web::uri> slack_app::get_ws_url()
{
    auto path = U("rtm.connect?token=") + _bot_access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        auto obj = json.as_object();
        auto isok = obj.at(U("ok")).as_bool();

        if (isok)
        {
            auto url = obj.at(U("url")).as_string();
            return web::uri{ url };
        }
        else
        {
            throw std::runtime_error(N(obj.at(U("error")).as_string()));
        }
    });
}

pplx::task<void> slack_app::verify_access_tokens()
{
    printf("verifying\n");
    std::array<pplx::task<bool>, 2> tasks
    {
        test_access_token(_access_token),
        test_access_token(_bot_access_token)
    };

    pplx::task<void> combined = pplx::when_all(std::begin(tasks), std::end(tasks))
        .then([](std::vector<bool> results) {
        printf("checking\n");
        auto at_ok = results[0];
        auto bat_ok = results[1];
        if (!at_ok || !bat_ok)
        {
            std::string messages("Could not authenticate");

            if (!at_ok)
            {
                messages += "\n  Problem with access token";
            }
            if (!bat_ok)
            {
                messages += "\n  Problem with bot access token";
            }

            throw std::runtime_error(messages);
        }
    });

    return combined;
}

pplx::task<void> slack_app::listen()
{
    pplx::task_completion_event<void> tce;
    pplx::task<void> completed(tce);

    return async_do_while([=]() {
        return _rtm_client.receive().then([=](web::websockets::client::websocket_incoming_message in_msg) {

            return in_msg.extract_string().then([=](std::string msg_str) {

                string_t msg_str_t = W(msg_str);
                json::value json_val = json::value::parse(msg_str_t);
                handle_message(json_val);
            });

        }).then([=](pplx::task<void> end_task) {
            try
            {
                end_task.get();
                return true;
            }
            catch (std::exception &e)
            {
                printf("ws error: %s\n", e.what());
            }
            catch (...)
            {
                printf("unkown error\n");
            }

            // We are here means we encountered some exception.
            // Return false to break the asynchronous loop.

            return false;
        });
    });
}

pplx::task<void> slack_app::handle_message(web::json::value message)
{
    printf("message:\n%s\n", N(message.serialize()).c_str());
    auto vtype = message[U("type")];
    auto vreply = message[U("reply_to")];

    if(vtype.is_string())
    {
        auto type = message[U("type")].as_string();

        if (type == U("hello"))
        {
            printf("received hello message\n");
        }
        else if (type == U("reconnect_url"))
        {
            auto new_url = message[U("url")].as_string();
            _rtm_url = new_url;

            printf("received new connect URL\n");
        }
        else if (type == U("message"))
        {
            auto text = message[U("text")].as_string();
            auto channel = message[U("channel")].as_string();
            auto from = message[U("user")].as_string();

            printf("got message: %s from %s\n", N(text).c_str(), N(from).c_str());

            if(from != _bot_userid)
            {
                auto emojis = get_emojis_in_message(N(text));

                sequential_transform(emojis.begin(), emojis.end(),
                    [=] (std::string p) -> pplx::task<std::pair<std::string, std::string>>
                {
                    return get_emoji_url(p).then([=](std::string url)
                    {
                        return std::make_pair(p, url);
                    });
                })
                .then([=] (std::vector<std::pair<std::string, std::string>> urls) {
                    std::string replymsg;

                    if (urls.size())
                    {
                        replymsg = "you specified these emojis: \n";
                        for (auto&pair : urls)
                        {
                            std::string url;
                            if(pair.second.empty())
                            {
                                url = ":question:";
                            }
                            else
                            {
                                url = pair.second;
                            }

                            replymsg += "  " + pair.first + " -> " + url + "\n";
                        }
                    }
                    else
                    {
                        replymsg = "you did not specify any emojis";
                    }

                    return send_message(W(replymsg), channel);
                });
            }
        }
        else if (type == U("presence_change") || type == U("desktop_notification"))
        {

        }
        else
        {

        }
    }
    else if(vreply.is_number())
    {

    }

    return pplx::task_from_result();
}

pplx::task<void> slack_app::send_message(const utility::string_t &text, const utility::string_t &channel)
{
    auto obj = json::value::object();
    obj[U("id")] = json::value::number(++_messageid);
    obj[U("type")] = json::value::string(U("message"));
    obj[U("channel")] = json::value::string(channel);
    obj[U("text")] = json::value::string(text);

    websockets::client::websocket_outgoing_message message;
    message.set_utf8_message(N(obj.serialize()));

    return _rtm_client.send(message);
}

static std::regex rx_emoji(":([a-zA-Z0-9_-]+):");
std::vector<std::string> slack_app::get_emojis_in_message(const std::string &s) const
{
    std::vector<std::string> result;
    auto emojis_begin = std::sregex_iterator(s.begin(), s.end(), rx_emoji);
    auto emojis_end = std::sregex_iterator();

    for (std::sregex_iterator i = emojis_begin; i != emojis_end; ++i)
    {
        std::smatch match = *i;
        std::string match_str = match.str(1);
        result.push_back(match_str);
    }

    std::sort(result.begin(), result.end());
    auto last = std::unique(result.begin(), result.end());
    result.erase(last, result.end());

    return result;
}

pplx::task<std::map<std::string, std::string>> slack_app::get_custom_emojis()
{
    auto path = U("emoji.list?token=") + _access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    }).then([=](json::value json) {
        std::map<std::string, std::string> obj_emoji;
        auto emojis = json[U("emoji")].as_object();

        for(auto i = emojis.begin(); i != emojis.end(); ++i)
        {
            auto kvp = *i;
            auto key = N(kvp.first);
            auto val = N(kvp.second.as_string());

            obj_emoji[key] = val;
        }

        return obj_emoji;
    });
}

pplx::task<void> slack_app::process_loop()
{
    pplx::task<void> at_verified
    {
        _access_ok ? pplx::task_from_result() : verify_access_tokens()
    };

    // the task will resolve on disconnect
    return at_verified.then([=] {
        if(_bot_userid.empty())
        {
            return get_userid(_bot_access_token).then([=](string_t userid) {
                printf("my user id: %s\n", N(userid).c_str());
                _bot_userid = userid;
            });
        }
        else
        {
            return pplx::task_from_result();
        }
    }).then([=] {
        _access_ok = true;
        printf("verified\n");

        //get url
        if(_rtm_url.is_empty())
        {
            return get_ws_url().then([=](web::uri wsurl) {
                printf("got ws url\n");
                _rtm_url = wsurl;
            });
        }
        else
        {
            return pplx::task_from_result();
        }

    }).then([=] {

        //get emojis
        return get_custom_emojis().then([=](std::map<std::string, std::string> emojis) {
            for(auto &i : emojis)
            {
                _emojis.insert_or_assign(i.first, i.second);
            }
        });
    }).then([=] {

        //connect
        return _rtm_client.connect(_rtm_url);
    }).then([this](pplx::task<void> task) {

        try
        {
            task.get();
            printf("connected.\n");
        }
        catch (...)
        {
            printf("connection error.\n");

            // force re-getting url
            _rtm_url = U("");
            _access_ok = false;

            return pplx::task_from_result();
        }

        return listen();
    }).then([] {
        printf("listen over\n");
    });
}

pplx::task<const void*> slack_app::get_emoji_data(const std::string &emoji)
{
    return pplx::task_from_result<const void*>(nullptr);
}

pplx::task<std::string> slack_app::get_emoji_url(const std::string &emoji)
{
    //try cached emoji
    auto found = _emojis.find(emoji);
    if(found != _emojis.end())
    {
        return pplx::task_from_result(found->second);
    }
    else
    {
        //get emojis again
        return get_custom_emojis().then([this,emoji](std::map<std::string, std::string> emojis) {

            // cache new custom emojis
            for (auto &i : emojis)
            {
                _emojis.insert_or_assign(i.first, i.second);
            }

            // find from custom emojis
            auto found2 = _emojis.find(emoji);
            if (found2 != _emojis.end())
            {
                return found2->second;
            }
            else
            {
                return std::string();
            }
        });
    }
}

void slack_app::run()
{
    printf("enteing\n");

    auto task = async_do_while([=] {
        return process_loop().then([=] {
            return true;
        });
    });

    task.wait();

}<commit_msg>fixed emoji regex<commit_after>
#include "pch.h"
#include "slackapp.h"
#include "utils.h"

using namespace utility;              // Common utilities like string conversions
using namespace web;                  // Common features like URIs.
using namespace web::http;            // Common HTTP functionality
using namespace web::http::client;    // HTTP client features
using namespace concurrency::streams; // Asynchronous streams

//web::http::client::http_client::~http_client() noexcept {}

pplx::task<bool> slack_app::test_access_token(const string_t &access_token)
{
    printf("authing\n");
    auto path = U("auth.test?token=") + access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        return json.as_object()
            .at(U("ok"))
            .as_bool();
    });
}

pplx::task<utility::string_t> slack_app::get_userid(const string_t &access_token)
{
    auto path = U("auth.test?token=") + access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        return json.as_object()
            .at(U("user_id"))
            .as_string();
    });
}

pplx::task<web::uri> slack_app::get_ws_url()
{
    auto path = U("rtm.connect?token=") + _bot_access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    })
        .then([=](json::value json) {
        auto obj = json.as_object();
        auto isok = obj.at(U("ok")).as_bool();

        if (isok)
        {
            auto url = obj.at(U("url")).as_string();
            return web::uri{ url };
        }
        else
        {
            throw std::runtime_error(N(obj.at(U("error")).as_string()));
        }
    });
}

pplx::task<void> slack_app::verify_access_tokens()
{
    printf("verifying\n");
    std::array<pplx::task<bool>, 2> tasks
    {
        test_access_token(_access_token),
        test_access_token(_bot_access_token)
    };

    pplx::task<void> combined = pplx::when_all(std::begin(tasks), std::end(tasks))
        .then([](std::vector<bool> results) {
        printf("checking\n");
        auto at_ok = results[0];
        auto bat_ok = results[1];
        if (!at_ok || !bat_ok)
        {
            std::string messages("Could not authenticate");

            if (!at_ok)
            {
                messages += "\n  Problem with access token";
            }
            if (!bat_ok)
            {
                messages += "\n  Problem with bot access token";
            }

            throw std::runtime_error(messages);
        }
    });

    return combined;
}

pplx::task<void> slack_app::listen()
{
    pplx::task_completion_event<void> tce;
    pplx::task<void> completed(tce);

    return async_do_while([=]() {
        return _rtm_client.receive().then([=](web::websockets::client::websocket_incoming_message in_msg) {

            return in_msg.extract_string().then([=](std::string msg_str) {

                string_t msg_str_t = W(msg_str);
                json::value json_val = json::value::parse(msg_str_t);
                handle_message(json_val);
            });

        }).then([=](pplx::task<void> end_task) {
            try
            {
                end_task.get();
                return true;
            }
            catch (std::exception &e)
            {
                printf("ws error: %s\n", e.what());
            }
            catch (...)
            {
                printf("unkown error\n");
            }

            // We are here means we encountered some exception.
            // Return false to break the asynchronous loop.

            return false;
        });
    });
}

pplx::task<void> slack_app::handle_message(web::json::value message)
{
    printf("message:\n%s\n", N(message.serialize()).c_str());
    auto vtype = message[U("type")];
    auto vreply = message[U("reply_to")];

    if(vtype.is_string())
    {
        auto type = message[U("type")].as_string();

        if (type == U("hello"))
        {
            printf("received hello message\n");
        }
        else if (type == U("reconnect_url"))
        {
            auto new_url = message[U("url")].as_string();
            _rtm_url = new_url;

            printf("received new connect URL\n");
        }
        else if (type == U("message"))
        {
            auto text = message[U("text")].as_string();
            auto channel = message[U("channel")].as_string();
            auto from = message[U("user")].as_string();

            printf("got message: %s from %s\n", N(text).c_str(), N(from).c_str());

            if(from != _bot_userid)
            {
                auto emojis = get_emojis_in_message(N(text));

                sequential_transform(emojis.begin(), emojis.end(),
                    [=] (std::string p) -> pplx::task<std::pair<std::string, std::string>>
                {
                    return get_emoji_url(p).then([=](std::string url)
                    {
                        return std::make_pair(p, url);
                    });
                })
                .then([=] (std::vector<std::pair<std::string, std::string>> urls) {
                    std::string replymsg;

                    if (urls.size())
                    {
                        replymsg = "you specified these emojis: \n";
                        for (auto&pair : urls)
                        {
                            std::string url;
                            if(pair.second.empty())
                            {
                                url = ":question:";
                            }
                            else
                            {
                                url = pair.second;
                            }

                            replymsg += "  " + pair.first + " -> " + url + "\n";
                        }
                    }
                    else
                    {
                        replymsg = "you did not specify any emojis";
                    }

                    return send_message(W(replymsg), channel);
                });
            }
        }
        else if (type == U("presence_change") || type == U("desktop_notification"))
        {

        }
        else
        {

        }
    }
    else if(vreply.is_number())
    {

    }

    return pplx::task_from_result();
}

pplx::task<void> slack_app::send_message(const utility::string_t &text, const utility::string_t &channel)
{
    auto obj = json::value::object();
    obj[U("id")] = json::value::number(++_messageid);
    obj[U("type")] = json::value::string(U("message"));
    obj[U("channel")] = json::value::string(channel);
    obj[U("text")] = json::value::string(text);

    websockets::client::websocket_outgoing_message message;
    message.set_utf8_message(N(obj.serialize()));

    return _rtm_client.send(message);
}

static std::regex rx_emoji(":([-a-zA-Z0-9_+]+):");
std::vector<std::string> slack_app::get_emojis_in_message(const std::string &s) const
{
    std::vector<std::string> result;
    auto emojis_begin = std::sregex_iterator(s.begin(), s.end(), rx_emoji);
    auto emojis_end = std::sregex_iterator();

    for (std::sregex_iterator i = emojis_begin; i != emojis_end; ++i)
    {
        std::smatch match = *i;
        std::string match_str = match.str(1);
        result.push_back(match_str);
    }

    std::sort(result.begin(), result.end());
    auto last = std::unique(result.begin(), result.end());
    result.erase(last, result.end());

    return result;
}

pplx::task<std::map<std::string, std::string>> slack_app::get_custom_emojis()
{
    auto path = U("emoji.list?token=") + _access_token;

    return _client.request(methods::POST, path)
        .then([=](http_response response) {
        return response.extract_json();
    }).then([=](json::value json) {
        std::map<std::string, std::string> obj_emoji;
        auto emojis = json[U("emoji")].as_object();

        for(auto i = emojis.begin(); i != emojis.end(); ++i)
        {
            auto kvp = *i;
            auto key = N(kvp.first);
            auto val = N(kvp.second.as_string());

            obj_emoji[key] = val;
        }

        return obj_emoji;
    });
}

pplx::task<void> slack_app::process_loop()
{
    pplx::task<void> at_verified
    {
        _access_ok ? pplx::task_from_result() : verify_access_tokens()
    };

    // the task will resolve on disconnect
    return at_verified.then([=] {
        if(_bot_userid.empty())
        {
            return get_userid(_bot_access_token).then([=](string_t userid) {
                printf("my user id: %s\n", N(userid).c_str());
                _bot_userid = userid;
            });
        }
        else
        {
            return pplx::task_from_result();
        }
    }).then([=] {
        _access_ok = true;
        printf("verified\n");

        //get url
        if(_rtm_url.is_empty())
        {
            return get_ws_url().then([=](web::uri wsurl) {
                printf("got ws url\n");
                _rtm_url = wsurl;
            });
        }
        else
        {
            return pplx::task_from_result();
        }

    }).then([=] {

        //get emojis
        return get_custom_emojis().then([=](std::map<std::string, std::string> emojis) {
            for(auto &i : emojis)
            {
                _emojis.insert_or_assign(i.first, i.second);
            }
        });
    }).then([=] {

        //connect
        return _rtm_client.connect(_rtm_url);
    }).then([this](pplx::task<void> task) {

        try
        {
            task.get();
            printf("connected.\n");
        }
        catch (...)
        {
            printf("connection error.\n");

            // force re-getting url
            _rtm_url = U("");
            _access_ok = false;

            return pplx::task_from_result();
        }

        return listen();
    }).then([] {
        printf("listen over\n");
    });
}

pplx::task<const void*> slack_app::get_emoji_data(const std::string &emoji)
{
    return pplx::task_from_result<const void*>(nullptr);
}

pplx::task<std::string> slack_app::get_emoji_url(const std::string &emoji)
{
    //try cached emoji
    auto found = _emojis.find(emoji);
    if(found != _emojis.end())
    {
        return pplx::task_from_result(found->second);
    }
    else
    {
        //get emojis again
        return get_custom_emojis().then([this,emoji](std::map<std::string, std::string> emojis) {

            // cache new custom emojis
            for (auto &i : emojis)
            {
                _emojis.insert_or_assign(i.first, i.second);
            }

            // find from custom emojis
            auto found2 = _emojis.find(emoji);
            if (found2 != _emojis.end())
            {
                return found2->second;
            }
            else
            {
                return std::string();
            }
        });
    }
}

void slack_app::run()
{
    printf("enteing\n");

    auto task = async_do_while([=] {
        return process_loop().then([=] {
            return true;
        });
    });

    task.wait();

}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SwRewriter.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2007-04-25 09:11:37 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <algorithm>
#include <SwRewriter.hxx>

using namespace std;

bool operator == (const SwRewriteRule & a, const SwRewriteRule & b)
{
    return a.first == b.first;
}

SwRewriter::SwRewriter()
{
}

SwRewriter::SwRewriter(const SwRewriter & rSrc)
    : mRules(rSrc.mRules)
{
}

SwRewriter::~SwRewriter()
{
}

void SwRewriter::AddRule(const String & rWhat, const String & rWith)
{
    SwRewriteRule aRule(rWhat, rWith);

    vector<SwRewriteRule>::iterator aIt;

    aIt = find(mRules.begin(), mRules.end(), aRule);

    if (aIt != mRules.end())
        *aIt = aRule;
    else
        mRules.push_back(aRule);
}

String SwRewriter::Apply(const String & rStr) const
{
    String aResult = rStr;
    vector<SwRewriteRule>::const_iterator aIt;

    for (aIt = mRules.begin(); aIt != mRules.end(); aIt++)
        aResult.SearchAndReplaceAll(aIt->first, aIt->second);

    return aResult;
}

<commit_msg>INTEGRATION: CWS changefileheader (1.8.438); FILE MERGED 2008/03/31 16:55:00 rt 1.8.438.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: SwRewriter.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <algorithm>
#include <SwRewriter.hxx>

using namespace std;

bool operator == (const SwRewriteRule & a, const SwRewriteRule & b)
{
    return a.first == b.first;
}

SwRewriter::SwRewriter()
{
}

SwRewriter::SwRewriter(const SwRewriter & rSrc)
    : mRules(rSrc.mRules)
{
}

SwRewriter::~SwRewriter()
{
}

void SwRewriter::AddRule(const String & rWhat, const String & rWith)
{
    SwRewriteRule aRule(rWhat, rWith);

    vector<SwRewriteRule>::iterator aIt;

    aIt = find(mRules.begin(), mRules.end(), aRule);

    if (aIt != mRules.end())
        *aIt = aRule;
    else
        mRules.push_back(aRule);
}

String SwRewriter::Apply(const String & rStr) const
{
    String aResult = rStr;
    vector<SwRewriteRule>::const_iterator aIt;

    for (aIt = mRules.begin(); aIt != mRules.end(); aIt++)
        aResult.SearchAndReplaceAll(aIt->first, aIt->second);

    return aResult;
}

<|endoftext|>


<commit_before>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>

#include "event.h"

using namespace KCal;

Event::Event() :
  mHasEndDate( false ), mTransparency( Opaque )
{
}

Event::Event(const Event &e) : Incidence(e)
{
  mDtEnd = e.mDtEnd;
  mHasEndDate = e.mHasEndDate;
  mTransparency = e.mTransparency;
}

Event::~Event()
{
}

Event *Event::clone()
{
  kdDebug(5800) << "Event::clone()" << endl;
  return new Event(*this);
}

bool Event::operator==( const Event& e2 ) const
{
    return
        static_cast<const Incidence&>(*this) == static_cast<const Incidence&>(e2) &&
        dtEnd() == e2.dtEnd() &&
        hasEndDate() == e2.hasEndDate() &&
        transparency() == e2.transparency();
}

void Event::setDtEnd(const QDateTime &dtEnd)
{
  if (mReadOnly) return;

  mDtEnd = dtEnd;

  setHasEndDate(true);
  setHasDuration(false);

  updated();
}

QDateTime Event::dtEnd() const
{
  if (hasEndDate()) return mDtEnd;
  if (hasDuration()) return dtStart().addSecs(duration());

  kdDebug(5800) << "Warning! Event '" << summary()
            << "' does have neither end date nor duration." << endl;
  return dtStart();
}

QString Event::dtEndTimeStr() const
{
  return KGlobal::locale()->formatTime(mDtEnd.time());
}

QString Event::dtEndDateStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt);
}

QString Event::dtEndStr() const
{
  return KGlobal::locale()->formatDateTime(mDtEnd);
}

void Event::setHasEndDate(bool b)
{
  mHasEndDate = b;
}

bool Event::hasEndDate() const
{
  return mHasEndDate;
}

bool Event::isMultiDay() const
{
  bool multi = !(dtStart().date() == dtEnd().date());
  return multi;
}

void Event::setTransparency(Event::Transparency transparency)
{
  if (mReadOnly) return;
  mTransparency = transparency;
  updated();
}

Event::Transparency Event::transparency() const
{
  return mTransparency;
}

void Event::setDuration(int seconds)
{
  setHasEndDate(false);
  Incidence::setDuration(seconds);
}
<commit_msg>Remove debug output.<commit_after>/*
    This file is part of libkcal.
    Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>

#include "event.h"

using namespace KCal;

Event::Event() :
  mHasEndDate( false ), mTransparency( Opaque )
{
}

Event::Event(const Event &e) : Incidence(e)
{
  mDtEnd = e.mDtEnd;
  mHasEndDate = e.mHasEndDate;
  mTransparency = e.mTransparency;
}

Event::~Event()
{
//  kdDebug(5800) << "~Event() " << int( this ) << endl;
}

Event *Event::clone()
{
  kdDebug(5800) << "Event::clone()" << endl;
  return new Event(*this);
}

bool Event::operator==( const Event& e2 ) const
{
    return
        static_cast<const Incidence&>(*this) == static_cast<const Incidence&>(e2) &&
        dtEnd() == e2.dtEnd() &&
        hasEndDate() == e2.hasEndDate() &&
        transparency() == e2.transparency();
}

void Event::setDtEnd(const QDateTime &dtEnd)
{
  if (mReadOnly) return;

  mDtEnd = dtEnd;

  setHasEndDate(true);
  setHasDuration(false);

  updated();
}

QDateTime Event::dtEnd() const
{
  if (hasEndDate()) return mDtEnd;
  if (hasDuration()) return dtStart().addSecs(duration());

  kdDebug(5800) << "Warning! Event '" << summary()
            << "' does have neither end date nor duration." << endl;
  return dtStart();
}

QString Event::dtEndTimeStr() const
{
  return KGlobal::locale()->formatTime(mDtEnd.time());
}

QString Event::dtEndDateStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDate(mDtEnd.date(),shortfmt);
}

QString Event::dtEndStr() const
{
  return KGlobal::locale()->formatDateTime(mDtEnd);
}

void Event::setHasEndDate(bool b)
{
  mHasEndDate = b;
}

bool Event::hasEndDate() const
{
  return mHasEndDate;
}

bool Event::isMultiDay() const
{
  bool multi = !(dtStart().date() == dtEnd().date());
  return multi;
}

void Event::setTransparency(Event::Transparency transparency)
{
  if (mReadOnly) return;
  mTransparency = transparency;
  updated();
}

Event::Transparency Event::transparency() const
{
  return mTransparency;
}

void Event::setDuration(int seconds)
{
  setHasEndDate(false);
  Incidence::setDuration(seconds);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 odan
 * License: MIT License
 */
#ifndef INCLUDED_PARAMETERS_5GEN_HPP
#define INCLUDED_PARAMETERS_5GEN_HPP
#include <cstdint>

namespace RNGLib {
template<uint32_t nazo1_, uint32_t nazo2_, uint32_t nazo3_, uint32_t nazo4_, uint32_t nazo5_,
         uint32_t VCount_, uint32_t Timer0_, uint32_t GxStat_, uint32_t Frame_>
class Parameters5Gen {
private:
    uint32_t nazo1 = nazo1_;
    uint32_t nazo2 = nazo2_;
    uint32_t nazo3 = nazo3_;
    uint32_t nazo4 = nazo4_;
    uint32_t nazo5 = nazo5_;

    uint32_t VCount = VCount_;
    uint32_t Timer0 = Timer0_;
    uint32_t GxStat = GxStat_;
    uint32_t Frame  = Frame_;

    uint32_t MAC_add1;
    uint32_t MAC_add2;
    uint32_t MAC_add3;
    uint32_t MAC_add4;
    uint32_t MAC_add5;
    uint32_t MAC_add6;
    uint32_t year;
    uint32_t month;
    uint32_t day;
    uint32_t hour;
    uint32_t minute;
    uint32_t sec;

    uint32_t key;

public:
    void set_MAC_add(uint32_t m1, uint32_t m2, uint32_t m3,
            uint32_t m4, uint32_t m5, uint32_t m6) {
        MAC_add1 = m1;
        MAC_add2 = m2;
        MAC_add3 = m3;
        MAC_add4 = m4;
        MAC_add5 = m5;
        MAC_add6 = m6;
    }

    void set_year(uint32_t yy) { year = yy; }
    void set_month(uint32_t mm) { month = mm; }
    void set_day(uint32_t dd) { day = dd; }

    void set_hour(uint32_t hh) { hour = hh; }
    void set_minute(uint32_t mi) { minute = mi; }
    void set_sec(uint32_t se) { sec = se; }

    void set_key(uint32_t key_) { key = key_; }
    void set_Timer0(uint32_t tt) { Timer0 = tt; }

    uint32_t get_MAC_add1() const { return MAC_add1; }
    uint32_t get_MAC_add2() const { return MAC_add2; }
    uint32_t get_MAC_add3() const { return MAC_add3; }
    uint32_t get_MAC_add4() const { return MAC_add4; }
    uint32_t get_MAC_add5() const { return MAC_add5; }
    uint32_t get_MAC_add6() const { return MAC_add6; }

    uint32_t get_year() const { return year; }
    uint32_t get_month() const { return month; }
    uint32_t get_day() const { return day; }
    uint32_t get_hour() const { return hour; }
    uint32_t get_minute() const { return minute; }
    uint32_t get_sec() const { return sec; }
    uint32_t get_week() const {
        return  ((2000+year-(month<3)) + (2000+year-(month<3))/4 -
            (2000+year-(month<3))/100 + (2000+year-(month<3))/400 +
            (13*(month+(month<3)*12)+8)/5 + day) % 7;
    }

    uint32_t get_nazo1() const { return nazo1; }
    uint32_t get_nazo2() const { return nazo2; }
    uint32_t get_nazo3() const { return nazo3; }
    uint32_t get_nazo4() const { return nazo4; }
    uint32_t get_nazo5() const { return nazo5; }

    uint32_t get_VCount() const { return VCount; }
    uint32_t get_Timer0() const { return Timer0; }
    uint32_t get_GxStat() const { return GxStat; }
    uint32_t get_Frame() const { return Frame; }
    uint32_t get_key() const { return key; }

};
} // end RNGLib

#endif
<commit_msg>Parameters5GenのテンプレートパラメータからTimer0を削除<commit_after>/*
 * Copyright (c) 2014 odan
 * License: MIT License
 */
#ifndef INCLUDED_PARAMETERS_5GEN_HPP
#define INCLUDED_PARAMETERS_5GEN_HPP
#include <cstdint>

namespace RNGLib {
template<uint32_t nazo1_, uint32_t nazo2_, uint32_t nazo3_, uint32_t nazo4_, uint32_t nazo5_,
         uint32_t VCount_, uint32_t GxStat_, uint32_t Frame_>
class Parameters5Gen {
private:
    uint32_t nazo1 = nazo1_;
    uint32_t nazo2 = nazo2_;
    uint32_t nazo3 = nazo3_;
    uint32_t nazo4 = nazo4_;
    uint32_t nazo5 = nazo5_;

    uint32_t VCount = VCount_;
    uint32_t GxStat = GxStat_;
    uint32_t Frame  = Frame_;

    uint32_t Timer0;
    uint32_t MAC_add1;
    uint32_t MAC_add2;
    uint32_t MAC_add3;
    uint32_t MAC_add4;
    uint32_t MAC_add5;
    uint32_t MAC_add6;
    uint32_t year;
    uint32_t month;
    uint32_t day;
    uint32_t hour;
    uint32_t minute;
    uint32_t sec;

    uint32_t key;

public:
    void set_MAC_add(uint32_t m1, uint32_t m2, uint32_t m3,
            uint32_t m4, uint32_t m5, uint32_t m6) {
        MAC_add1 = m1;
        MAC_add2 = m2;
        MAC_add3 = m3;
        MAC_add4 = m4;
        MAC_add5 = m5;
        MAC_add6 = m6;
    }

    void set_year(uint32_t yy) { year = yy; }
    void set_month(uint32_t mm) { month = mm; }
    void set_day(uint32_t dd) { day = dd; }

    void set_hour(uint32_t hh) { hour = hh; }
    void set_minute(uint32_t mi) { minute = mi; }
    void set_sec(uint32_t se) { sec = se; }

    void set_key(uint32_t key_) { key = key_; }
    void set_Timer0(uint32_t tt) { Timer0 = tt; }

    uint32_t get_MAC_add1() const { return MAC_add1; }
    uint32_t get_MAC_add2() const { return MAC_add2; }
    uint32_t get_MAC_add3() const { return MAC_add3; }
    uint32_t get_MAC_add4() const { return MAC_add4; }
    uint32_t get_MAC_add5() const { return MAC_add5; }
    uint32_t get_MAC_add6() const { return MAC_add6; }

    uint32_t get_year() const { return year; }
    uint32_t get_month() const { return month; }
    uint32_t get_day() const { return day; }
    uint32_t get_hour() const { return hour; }
    uint32_t get_minute() const { return minute; }
    uint32_t get_sec() const { return sec; }
    uint32_t get_week() const {
        return  ((2000+year-(month<3)) + (2000+year-(month<3))/4 -
            (2000+year-(month<3))/100 + (2000+year-(month<3))/400 +
            (13*(month+(month<3)*12)+8)/5 + day) % 7;
    }

    uint32_t get_nazo1() const { return nazo1; }
    uint32_t get_nazo2() const { return nazo2; }
    uint32_t get_nazo3() const { return nazo3; }
    uint32_t get_nazo4() const { return nazo4; }
    uint32_t get_nazo5() const { return nazo5; }

    uint32_t get_VCount() const { return VCount; }
    uint32_t get_Timer0() const { return Timer0; }
    uint32_t get_GxStat() const { return GxStat; }
    uint32_t get_Frame() const { return Frame; }
    uint32_t get_key() const { return key; }

};
} // end RNGLib

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "SlotInformation.h"
#include "InterlockedExchange.h"
#include "Autowired.h"
#include "thread_specific_ptr.h"
#include MEMORY_HEADER

// Special file-level allocation with a no-op dtor, because all stack locations are stack-allocated
static autowiring::thread_specific_ptr<SlotInformationStackLocation> tss([](SlotInformationStackLocation*) {});

SlotInformationStackLocation::SlotInformationStackLocation(SlotInformationStumpBase* pStump, const void* pObj, size_t extent) :
  m_pPrior(tss.get()),
  m_pStump(pStump),
  m_pCur(nullptr),
  m_pObj(pObj),
  m_extent(extent)
{
  tss.reset(this);
}

SlotInformationStackLocation::~SlotInformationStackLocation(void) {
  if(!m_pStump)
    // Rvalue moved, end here
    return;

  // Replace the prior stack location, we were pushed
  tss.reset(m_pPrior);

  if(
    // Do not attempt the update if this stump is initialized already, it could
    // mean that our value is presently invalid
    !m_pStump->bInitialized &&

    // We can only end here if the swap succeeds, otherwise we're going to have
    // to leave the value that's here already and tear down our list
    !compare_exchange<SlotInformation>(&m_pStump->pHead, m_pCur, nullptr)
  ) {
    // No reason to CAS this boolean field--we're going to unconditionally make
    // this spot initialized.
    m_pStump->bInitialized = true;
    return;
  }

  // Stump already filled in, prevent leaks by destroying this stump entry:
  std::unique_ptr<const SlotInformation> prior;
  for(const auto* cur = m_pCur; cur; cur = cur->pFlink)
    prior.reset(cur);
}

SlotInformationStackLocation* SlotInformationStackLocation::CurrentStackLocation(void) {
  return tss.get();
}

SlotInformationStumpBase* SlotInformationStackLocation::CurrentStump(void) {
  // Trivial null defaulting:
  return tss.get() ? tss->m_pStump : nullptr;
}

void SlotInformationStackLocation::RegisterSlot(DeferrableAutowiring* pDeferrable) {
  if(!tss.get())
    // Nothing to do, this slot entry is missing
    return;

  if(tss->m_pStump->bInitialized)
    // No reason to continue, stump already initialized
    return;

  if(!tss->Encloses(pDeferrable))
    // Slot is extraneous, falling outside of the bounds of the original object--ignore
    return;

  tss->m_pCur = new SlotInformation(
    tss->m_pCur,
    pDeferrable->GetType(),
    reinterpret_cast<const unsigned char*>(pDeferrable) -
    reinterpret_cast<const unsigned char*>(tss->m_pObj),
    false
  );
}
<commit_msg>Clarifying some comments<commit_after>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "SlotInformation.h"
#include "InterlockedExchange.h"
#include "Autowired.h"
#include "thread_specific_ptr.h"
#include MEMORY_HEADER

// Special file-level allocation with a no-op dtor, because all stack locations are stack-allocated
static autowiring::thread_specific_ptr<SlotInformationStackLocation> tss([](SlotInformationStackLocation*) {});

SlotInformationStackLocation::SlotInformationStackLocation(SlotInformationStumpBase* pStump, const void* pObj, size_t extent) :
  m_pPrior(tss.get()),
  m_pStump(pStump),
  m_pCur(nullptr),
  m_pObj(pObj),
  m_extent(extent)
{
  tss.reset(this);
}

SlotInformationStackLocation::~SlotInformationStackLocation(void) {
  if(!m_pStump)
    // Rvalue moved, end here
    return;

  // Replace the prior stack location, we were pushed
  tss.reset(m_pPrior);

  if(
    // Do not attempt the update if this stump is initialized already, because it
    // means that someone else has already filled this in.
    !m_pStump->bInitialized &&

    // We can only end here if the swap succeeds, otherwise we're going to have
    // to leave the value that's here already and tear down our list
    !compare_exchange<SlotInformation>(&m_pStump->pHead, m_pCur, nullptr)
  ) {
    // No reason to CAS this boolean field--we're going to unconditionally make
    // this spot initialized.
    m_pStump->bInitialized = true;
    return;
  }

  // Stump already filled in by someone else before we could get to it.  We don't want
  // to leak memory, so we need to destroy our linked list of slot informations.
  std::unique_ptr<const SlotInformation> prior;
  for(const auto* cur = m_pCur; cur; cur = cur->pFlink)
    prior.reset(cur);
}

SlotInformationStackLocation* SlotInformationStackLocation::CurrentStackLocation(void) {
  return tss.get();
}

SlotInformationStumpBase* SlotInformationStackLocation::CurrentStump(void) {
  // Trivial null defaulting:
  return tss.get() ? tss->m_pStump : nullptr;
}

void SlotInformationStackLocation::RegisterSlot(DeferrableAutowiring* pDeferrable) {
  if(!tss.get())
    // Nothing to do, this slot entry is missing
    return;

  if(tss->m_pStump->bInitialized)
    // No reason to continue, stump already initialized
    return;

  if(!tss->Encloses(pDeferrable))
    // Slot is extraneous, falling outside of the bounds of the original object--ignore
    return;

  tss->m_pCur = new SlotInformation(
    tss->m_pCur,
    pDeferrable->GetType(),
    reinterpret_cast<const unsigned char*>(pDeferrable) -
    reinterpret_cast<const unsigned char*>(tss->m_pObj),
    false
  );
}
<|endoftext|>


<commit_before>// #include guards
#ifndef ICEFIELD_HPP
#define ICEFIELD_HPP

// Used for overloading << operator with an ostream
#include <iostream>

/* A class representing an ice rink that, like in Pac-Man and
 * Final Fantasy, has wraparound geography and finite dimensions.
 */
class IceField {
public:

    /* Creates a new IceField object
     * PARAMS
     **** rows: number of rows on the IceField
     **** cols: number of columns on the IceField
     **** startRow: initial row number of the zamboni, zero-indexed
     **** startCol: initial column number of the zamboni, zero-indexed
     **** numMoves: number of time the zamboni moves and changes color
     * RETURN
     **** IceField object created with the given parameters
     */
    IceField(int rows, int cols, int startRow, int startCol, int numMoves);

    /* Safely destroys the IceField object.
     */
    ~IceField();

    /* Cleans the ice according to the Pac-Man algorithm:
     * stepSize := 1
     * loop numMoves times
     *     Move stepSize steps in the current direction
     *     Rotate the direction of the zamboni 90 degrees clockwise
     *     Switch to the next color
     *     stepSize := stepSize + 1
     * end loop
     * The zamboni starts by facing up.
     */
    void clean();

    /* Outputs a visual representation of the ice field, with
     * the letters A-Z representing the different colors, the
     * character '.' representing white ice, and the character
     * '@' representing the current location of the Zamboni.
     */
    friend std::ostream& operator<<(std::ostream& o, const IceField ice);

private:

    /* The number of steps the zamboni should take the first time
     * it moves
     */
    static const int FIRST_STEP_SIZE;

    /* The number of colors the zamboni can paint. Since each
     * letter of the alphabet represents a different color,
     * there are 26 possible colors.
     */
    static const int NUMBER_OF_COLORS = 26;

    /* The character that represents the first color the zamboni
     * will paint. This is used to the field currentColor into
     * a character, since the expressions ZERO_COLOR + 0,
     * ZERO_COLOR + 1, and ZERO_COLOR + 2 will have the values
     * 'A', 'B', and 'C', respectively, and so on.
     */
    static const char ZERO_COLOR = 'A';

    /* The character that represents uncolored white ice.
     */
    static const char WHITE_ICE = '.';

    /* The character that represents the current location of the
     * zamboni on the ice.
     */
    static const char ZAMBONI = '@';

    /* Constants that represent the four directions in which the
     * zamboni can move.
     */
    static const int NORTH = 0;
    static const int EAST = 1;
    static const int SOUTH = 2;
    static const int WEST = 3;

    /* Number of rows in the ice field.
     */
    const int rows;

    /* Number of columns in the ice field
     */
    const int cols;

    /* Current row number of the zamboni, zero-indexed
     */
    int zamboniRow;

    /* Current column number of the zamboni, zero-indexed
     */
    int zamboniCol;

    /* Number of times the zamboni moves and changes color.
     */
    const int numMoves;

    /* Distance the zamboni should move in the next direction.
     */
    int stepSize;

    /* A 2D array that contains the colors of every square on the
     * ice field, with '.' representing white, A-Z representing colors,
     * and '@' representing the current location of the zamboni.
     */
    char** grid;

    /* An integer representing the color the zamboni is painting.
     * Always meets the condition 0 <= currentColor < NUMBER_OF_COLORS.
     * To guarantee this, it should always be modded by NUMBER_OF_COLORS
     * after incrementing.
     */
    int currentColor = 0;

    /* An integer representing the direction in which the zamboni is
     * moving. It should always have the value NORTH, EAST, SOUTH, or
     * WEST.
     */
    int currentDirection;

    /* Moves the zamboni in its current direction, coloring every square
     * it passes over, including the square it starts from, and not
     * including the square it finishes on. If it moves across one edge,
     * it wraps around to the opposite edge.
     */
    void moveZamboni();

    /* Turns the zamboni clockwise.
     */
    void turnZamboni();
};

// Closes #include guard.
#endif<commit_msg>Changed overloaded << operator with ostream& to pass the IceField object by reference since no copy constructor is declared.<commit_after>// #include guards
#ifndef ICEFIELD_HPP
#define ICEFIELD_HPP

// Used for overloading << operator with an ostream
#include <iostream>

/* A class representing an ice rink that, like in Pac-Man and
 * Final Fantasy, has wraparound geography and finite dimensions.
 */
class IceField {
public:

    /* Creates a new IceField object
     * PARAMS
     **** rows: number of rows on the IceField
     **** cols: number of columns on the IceField
     **** startRow: initial row number of the zamboni, zero-indexed
     **** startCol: initial column number of the zamboni, zero-indexed
     **** numMoves: number of time the zamboni moves and changes color
     * RETURN
     **** IceField object created with the given parameters
     */
    IceField(int rows, int cols, int startRow, int startCol, int numMoves);

    /* Safely destroys the IceField object.
     */
    ~IceField();

    /* Cleans the ice according to the Pac-Man algorithm:
     * stepSize := 1
     * loop numMoves times
     *     Move stepSize steps in the current direction
     *     Rotate the direction of the zamboni 90 degrees clockwise
     *     Switch to the next color
     *     stepSize := stepSize + 1
     * end loop
     * The zamboni starts by facing up.
     */
    void clean();

    /* Outputs a visual representation of the ice field, with
     * the letters A-Z representing the different colors, the
     * character '.' representing white ice, and the character
     * '@' representing the current location of the Zamboni.
     */
    friend std::ostream& operator<<(std::ostream& o, const IceField &ice);

private:

    /* The number of steps the zamboni should take the first time
     * it moves
     */
    static const int FIRST_STEP_SIZE;

    /* The number of colors the zamboni can paint. Since each
     * letter of the alphabet represents a different color,
     * there are 26 possible colors.
     */
    static const int NUMBER_OF_COLORS = 26;

    /* The character that represents the first color the zamboni
     * will paint. This is used to the field currentColor into
     * a character, since the expressions ZERO_COLOR + 0,
     * ZERO_COLOR + 1, and ZERO_COLOR + 2 will have the values
     * 'A', 'B', and 'C', respectively, and so on.
     */
    static const char ZERO_COLOR = 'A';

    /* The character that represents uncolored white ice.
     */
    static const char WHITE_ICE = '.';

    /* The character that represents the current location of the
     * zamboni on the ice.
     */
    static const char ZAMBONI = '@';

    /* Constants that represent the four directions in which the
     * zamboni can move.
     */
    static const int NORTH = 0;
    static const int EAST = 1;
    static const int SOUTH = 2;
    static const int WEST = 3;

    /* Number of rows in the ice field.
     */
    const int rows;

    /* Number of columns in the ice field
     */
    const int cols;

    /* Current row number of the zamboni, zero-indexed
     */
    int zamboniRow;

    /* Current column number of the zamboni, zero-indexed
     */
    int zamboniCol;

    /* Number of times the zamboni moves and changes color.
     */
    const int numMoves;

    /* Distance the zamboni should move in the next direction.
     */
    int stepSize;

    /* A 2D array that contains the colors of every square on the
     * ice field, with '.' representing white, A-Z representing colors,
     * and '@' representing the current location of the zamboni.
     */
    char** grid;

    /* An integer representing the color the zamboni is painting.
     * Always meets the condition 0 <= currentColor < NUMBER_OF_COLORS.
     * To guarantee this, it should always be modded by NUMBER_OF_COLORS
     * after incrementing.
     */
    int currentColor = 0;

    /* An integer representing the direction in which the zamboni is
     * moving. It should always have the value NORTH, EAST, SOUTH, or
     * WEST.
     */
    int currentDirection;

    /* Moves the zamboni in its current direction, coloring every square
     * it passes over, including the square it starts from, and not
     * including the square it finishes on. If it moves across one edge,
     * it wraps around to the opposite edge.
     */
    void moveZamboni();

    /* Turns the zamboni clockwise.
     */
    void turnZamboni();
};

// Closes #include guard.
#endif<|endoftext|>


<commit_before>/*
 * Chrome Token Signing Native Host
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name != 0; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({name, 0, 0, 0, 0, 0});
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, NULL, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath = openscPath;
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string eTokenPath("/usr/local/lib/libeTPkcs11.dylib");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<commit_msg>Add Belgium middleware paths (#107)<commit_after>/*
 * Chrome Token Signing Native Host
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({name, 0, 0, 0, 0, 0});
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, NULL, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("/usr/local/lib/beid-pkcs11.bundle/Contents/MacOS/libbeidpkcs11.dylib");
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath = openscPath;
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("libbeidpkcs11.so.0");
    static const std::string eTokenPath("/usr/local/lib/libeTPkcs11.dylib");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},

        {"3B9813400AA503010101AD1311", {belPath, "PIN", "PIN"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<|endoftext|>


<commit_before>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions and variables in the input module.
// If the function or variable is not in the list of external names given to
// the pass it is marked as internal.
//
// This transformation would not be legal in a regular compilation, but it gets
// extra information from the linker about what is safe.
//
// For example: Internalizing a function with external linkage. Only if we are
// told it is only used from within this module, it is safe to do it.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <fstream>
#include <set>
using namespace llvm;

#define DEBUG_TYPE "internalize"

STATISTIC(NumAliases, "Number of aliases internalized");
STATISTIC(NumFunctions, "Number of functions internalized");
STATISTIC(NumGlobals, "Number of global vars internalized");

// APIFile - A file which contains a list of symbols that should not be marked
// external.
static cl::opt<std::string>
    APIFile("internalize-public-api-file", cl::value_desc("filename"),
            cl::desc("A file containing list of symbol names to preserve"));

// APIList - A list of symbols that should not be marked internal.
static cl::list<std::string>
    APIList("internalize-public-api-list", cl::value_desc("list"),
            cl::desc("A list of symbol names to preserve"), cl::CommaSeparated);

namespace {

// Helper to load an API list to preserve from file and expose it as a functor
// for internalization.
class PreserveAPIList {
public:
  PreserveAPIList() {
    if (!APIFile.empty())
      LoadFile(APIFile);
    ExternalNames.insert(APIList.begin(), APIList.end());
  }

  bool operator()(const GlobalValue &GV) {
    return ExternalNames.count(GV.getName());
  }

private:
  // Contains the set of symbols loaded from file
  StringSet<> ExternalNames;

  void LoadFile(StringRef Filename) {
    // Load the APIFile...
    std::ifstream In(Filename.data());
    if (!In.good()) {
      errs() << "WARNING: Internalize couldn't load file '" << Filename
             << "'! Continuing as if it's empty.\n";
      return; // Just continue as if the file were empty
    }
    while (In) {
      std::string Symbol;
      In >> Symbol;
      if (!Symbol.empty())
        ExternalNames.insert(Symbol);
    }
  }
};

// Internalization exposed as a pass
class InternalizePass : public ModulePass {
  // Client supplied callback to control wheter a symbol must be preserved.
  std::function<bool(const GlobalValue &)> MustPreserveGV;

public:
  static char ID; // Pass identification, replacement for typeid

  InternalizePass() : ModulePass(ID), MustPreserveGV(PreserveAPIList()) {}

  InternalizePass(std::function<bool(const GlobalValue &)> MustPreserveGV)
      : ModulePass(ID), MustPreserveGV(std::move(MustPreserveGV)) {
    initializeInternalizePassPass(*PassRegistry::getPassRegistry());
  }

  bool runOnModule(Module &M) override {
    CallGraphWrapperPass *CGPass =
        getAnalysisIfAvailable<CallGraphWrapperPass>();
    CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr;
    return internalizeModule(M, MustPreserveGV, CG);
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    AU.addPreserved<CallGraphWrapperPass>();
  }
};
} // end anonymous namespace

char InternalizePass::ID = 0;
INITIALIZE_PASS(InternalizePass, "internalize", "Internalize Global Symbols",
                false, false)

// Helper class to perform internalization.
class Internalizer {
  // Client supplied callback to control wheter a symbol must be preserved.
  const std::function<bool(const GlobalValue &)> &MustPreserveGV;

  // Set of symbols private to the compiler that this pass should not touch.
  StringSet<> AlwaysPreserved;

  // Return false if we're allowed to internalize this GV.
  bool ShouldPreserveGV(const GlobalValue &GV) {
    // Function must be defined here
    if (GV.isDeclaration())
      return true;

    // Available externally is really just a "declaration with a body".
    if (GV.hasAvailableExternallyLinkage())
      return true;

    // Assume that dllexported symbols are referenced elsewhere
    if (GV.hasDLLExportStorageClass())
      return true;

    // Already local, has nothing to do.
    if (GV.hasLocalLinkage())
      return false;

    // Check some special cases
    if (AlwaysPreserved.count(GV.getName()))
      return true;

    return MustPreserveGV(GV);
  }

  bool maybeInternalize(GlobalValue &GV,
                        const std::set<const Comdat *> &ExternalComdats);
  void checkComdatVisibility(GlobalValue &GV,
                             std::set<const Comdat *> &ExternalComdats);

public:
  Internalizer(const std::function<bool(const GlobalValue &)> &MustPreserveGV)
      : MustPreserveGV(MustPreserveGV) {}

  /// Run the internalizer on \p TheModule, returns true if any changes was
  /// made.
  ///
  /// If the CallGraph \p CG is supplied, it will be updated when
  /// internalizing a function (by removing any edge from the "external node")
  bool internalizeModule(Module &TheModule, CallGraph *CG = nullptr);
};

// Internalize GV if it is possible to do so, i.e. it is not externally visible
// and is not a member of an externally visible comdat.
bool Internalizer::maybeInternalize(
    GlobalValue &GV, const std::set<const Comdat *> &ExternalComdats) {
  if (Comdat *C = GV.getComdat()) {
    if (ExternalComdats.count(C))
      return false;

    // If a comdat is not externally visible we can drop it.
    if (auto GO = dyn_cast<GlobalObject>(&GV))
      GO->setComdat(nullptr);

    if (GV.hasLocalLinkage())
      return false;
  } else {
    if (GV.hasLocalLinkage())
      return false;

    if (ShouldPreserveGV(GV))
      return false;
  }

  GV.setVisibility(GlobalValue::DefaultVisibility);
  GV.setLinkage(GlobalValue::InternalLinkage);
  return true;
}

// If GV is part of a comdat and is externally visible, keep track of its
// comdat so that we don't internalize any of its members.
void Internalizer::checkComdatVisibility(
    GlobalValue &GV, std::set<const Comdat *> &ExternalComdats) {
  Comdat *C = GV.getComdat();
  if (!C)
    return;

  if (ShouldPreserveGV(GV))
    ExternalComdats.insert(C);
}

bool Internalizer::internalizeModule(Module &M, CallGraph *CG) {
  CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : nullptr;

  SmallPtrSet<GlobalValue *, 8> Used;
  collectUsedGlobalVariables(M, Used, false);

  // Collect comdat visiblity information for the module.
  std::set<const Comdat *> ExternalComdats;
  if (!M.getComdatSymbolTable().empty()) {
    for (Function &F : M)
      checkComdatVisibility(F, ExternalComdats);
    for (GlobalVariable &GV : M.globals())
      checkComdatVisibility(GV, ExternalComdats);
    for (GlobalAlias &GA : M.aliases())
      checkComdatVisibility(GA, ExternalComdats);
  }

  // We must assume that globals in llvm.used have a reference that not even
  // the linker can see, so we don't internalize them.
  // For llvm.compiler.used the situation is a bit fuzzy. The assembler and
  // linker can drop those symbols. If this pass is running as part of LTO,
  // one might think that it could just drop llvm.compiler.used. The problem
  // is that even in LTO llvm doesn't see every reference. For example,
  // we don't see references from function local inline assembly. To be
  // conservative, we internalize symbols in llvm.compiler.used, but we
  // keep llvm.compiler.used so that the symbol is not deleted by llvm.
  for (GlobalValue *V : Used) {
    AlwaysPreserved.insert(V->getName());
  }

  // Mark all functions not in the api as internal.
  for (Function &I : M) {
    if (!maybeInternalize(I, ExternalComdats))
      continue;

    if (ExternalNode)
      // Remove a callgraph edge from the external node to this function.
      ExternalNode->removeOneAbstractEdgeTo((*CG)[&I]);

    ++NumFunctions;
    DEBUG(dbgs() << "Internalizing func " << I.getName() << "\n");
  }

  // Never internalize the llvm.used symbol.  It is used to implement
  // attribute((used)).
  // FIXME: Shouldn't this just filter on llvm.metadata section??
  AlwaysPreserved.insert("llvm.used");
  AlwaysPreserved.insert("llvm.compiler.used");

  // Never internalize anchors used by the machine module info, else the info
  // won't find them.  (see MachineModuleInfo.)
  AlwaysPreserved.insert("llvm.global_ctors");
  AlwaysPreserved.insert("llvm.global_dtors");
  AlwaysPreserved.insert("llvm.global.annotations");

  // Never internalize symbols code-gen inserts.
  // FIXME: We should probably add this (and the __stack_chk_guard) via some
  // type of call-back in CodeGen.
  AlwaysPreserved.insert("__stack_chk_fail");
  AlwaysPreserved.insert("__stack_chk_guard");

  // Mark all global variables with initializers that are not in the api as
  // internal as well.
  for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E;
       ++I) {
    if (!maybeInternalize(*I, ExternalComdats))
      continue;

    ++NumGlobals;
    DEBUG(dbgs() << "Internalized gvar " << I->getName() << "\n");
  }

  // Mark all aliases that are not in the api as internal as well.
  for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end(); I != E;
       ++I) {
    if (!maybeInternalize(*I, ExternalComdats))
      continue;

    ++NumAliases;
    DEBUG(dbgs() << "Internalized alias " << I->getName() << "\n");
  }

  // We do not keep track of whether this pass changed the module because
  // it adds unnecessary complexity:
  // 1) This pass will generally be near the start of the pass pipeline, so
  //    there will be no analyses to invalidate.
  // 2) This pass will most likely end up changing the module and it isn't worth
  //    worrying about optimizing the case where the module is unchanged.
  return true;
}

/// Public API below

bool llvm::internalizeModule(
    Module &TheModule,
    const std::function<bool(const GlobalValue &)> &MustPreserveGV,
    CallGraph *CG) {
  return Internalizer(MustPreserveGV).internalizeModule(TheModule, CG);
}

ModulePass *llvm::createInternalizePass() { return new InternalizePass(); }

ModulePass *llvm::createInternalizePass(
    std::function<bool(const GlobalValue &)> MustPreserveGV) {
  return new InternalizePass(std::move(MustPreserveGV));
}
<commit_msg>Modernize Internalizer with for-range loop (NFC)<commit_after>//===-- Internalize.cpp - Mark functions internal -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over all of the functions and variables in the input module.
// If the function or variable is not in the list of external names given to
// the pass it is marked as internal.
//
// This transformation would not be legal in a regular compilation, but it gets
// extra information from the linker about what is safe.
//
// For example: Internalizing a function with external linkage. Only if we are
// told it is only used from within this module, it is safe to do it.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <fstream>
#include <set>
using namespace llvm;

#define DEBUG_TYPE "internalize"

STATISTIC(NumAliases, "Number of aliases internalized");
STATISTIC(NumFunctions, "Number of functions internalized");
STATISTIC(NumGlobals, "Number of global vars internalized");

// APIFile - A file which contains a list of symbols that should not be marked
// external.
static cl::opt<std::string>
    APIFile("internalize-public-api-file", cl::value_desc("filename"),
            cl::desc("A file containing list of symbol names to preserve"));

// APIList - A list of symbols that should not be marked internal.
static cl::list<std::string>
    APIList("internalize-public-api-list", cl::value_desc("list"),
            cl::desc("A list of symbol names to preserve"), cl::CommaSeparated);

namespace {

// Helper to load an API list to preserve from file and expose it as a functor
// for internalization.
class PreserveAPIList {
public:
  PreserveAPIList() {
    if (!APIFile.empty())
      LoadFile(APIFile);
    ExternalNames.insert(APIList.begin(), APIList.end());
  }

  bool operator()(const GlobalValue &GV) {
    return ExternalNames.count(GV.getName());
  }

private:
  // Contains the set of symbols loaded from file
  StringSet<> ExternalNames;

  void LoadFile(StringRef Filename) {
    // Load the APIFile...
    std::ifstream In(Filename.data());
    if (!In.good()) {
      errs() << "WARNING: Internalize couldn't load file '" << Filename
             << "'! Continuing as if it's empty.\n";
      return; // Just continue as if the file were empty
    }
    while (In) {
      std::string Symbol;
      In >> Symbol;
      if (!Symbol.empty())
        ExternalNames.insert(Symbol);
    }
  }
};

// Internalization exposed as a pass
class InternalizePass : public ModulePass {
  // Client supplied callback to control wheter a symbol must be preserved.
  std::function<bool(const GlobalValue &)> MustPreserveGV;

public:
  static char ID; // Pass identification, replacement for typeid

  InternalizePass() : ModulePass(ID), MustPreserveGV(PreserveAPIList()) {}

  InternalizePass(std::function<bool(const GlobalValue &)> MustPreserveGV)
      : ModulePass(ID), MustPreserveGV(std::move(MustPreserveGV)) {
    initializeInternalizePassPass(*PassRegistry::getPassRegistry());
  }

  bool runOnModule(Module &M) override {
    CallGraphWrapperPass *CGPass =
        getAnalysisIfAvailable<CallGraphWrapperPass>();
    CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr;
    return internalizeModule(M, MustPreserveGV, CG);
  }

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.setPreservesCFG();
    AU.addPreserved<CallGraphWrapperPass>();
  }
};
} // end anonymous namespace

char InternalizePass::ID = 0;
INITIALIZE_PASS(InternalizePass, "internalize", "Internalize Global Symbols",
                false, false)

// Helper class to perform internalization.
class Internalizer {
  // Client supplied callback to control wheter a symbol must be preserved.
  const std::function<bool(const GlobalValue &)> &MustPreserveGV;

  // Set of symbols private to the compiler that this pass should not touch.
  StringSet<> AlwaysPreserved;

  // Return false if we're allowed to internalize this GV.
  bool ShouldPreserveGV(const GlobalValue &GV) {
    // Function must be defined here
    if (GV.isDeclaration())
      return true;

    // Available externally is really just a "declaration with a body".
    if (GV.hasAvailableExternallyLinkage())
      return true;

    // Assume that dllexported symbols are referenced elsewhere
    if (GV.hasDLLExportStorageClass())
      return true;

    // Already local, has nothing to do.
    if (GV.hasLocalLinkage())
      return false;

    // Check some special cases
    if (AlwaysPreserved.count(GV.getName()))
      return true;

    return MustPreserveGV(GV);
  }

  bool maybeInternalize(GlobalValue &GV,
                        const std::set<const Comdat *> &ExternalComdats);
  void checkComdatVisibility(GlobalValue &GV,
                             std::set<const Comdat *> &ExternalComdats);

public:
  Internalizer(const std::function<bool(const GlobalValue &)> &MustPreserveGV)
      : MustPreserveGV(MustPreserveGV) {}

  /// Run the internalizer on \p TheModule, returns true if any changes was
  /// made.
  ///
  /// If the CallGraph \p CG is supplied, it will be updated when
  /// internalizing a function (by removing any edge from the "external node")
  bool internalizeModule(Module &TheModule, CallGraph *CG = nullptr);
};

// Internalize GV if it is possible to do so, i.e. it is not externally visible
// and is not a member of an externally visible comdat.
bool Internalizer::maybeInternalize(
    GlobalValue &GV, const std::set<const Comdat *> &ExternalComdats) {
  if (Comdat *C = GV.getComdat()) {
    if (ExternalComdats.count(C))
      return false;

    // If a comdat is not externally visible we can drop it.
    if (auto GO = dyn_cast<GlobalObject>(&GV))
      GO->setComdat(nullptr);

    if (GV.hasLocalLinkage())
      return false;
  } else {
    if (GV.hasLocalLinkage())
      return false;

    if (ShouldPreserveGV(GV))
      return false;
  }

  GV.setVisibility(GlobalValue::DefaultVisibility);
  GV.setLinkage(GlobalValue::InternalLinkage);
  return true;
}

// If GV is part of a comdat and is externally visible, keep track of its
// comdat so that we don't internalize any of its members.
void Internalizer::checkComdatVisibility(
    GlobalValue &GV, std::set<const Comdat *> &ExternalComdats) {
  Comdat *C = GV.getComdat();
  if (!C)
    return;

  if (ShouldPreserveGV(GV))
    ExternalComdats.insert(C);
}

bool Internalizer::internalizeModule(Module &M, CallGraph *CG) {
  CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : nullptr;

  SmallPtrSet<GlobalValue *, 8> Used;
  collectUsedGlobalVariables(M, Used, false);

  // Collect comdat visiblity information for the module.
  std::set<const Comdat *> ExternalComdats;
  if (!M.getComdatSymbolTable().empty()) {
    for (Function &F : M)
      checkComdatVisibility(F, ExternalComdats);
    for (GlobalVariable &GV : M.globals())
      checkComdatVisibility(GV, ExternalComdats);
    for (GlobalAlias &GA : M.aliases())
      checkComdatVisibility(GA, ExternalComdats);
  }

  // We must assume that globals in llvm.used have a reference that not even
  // the linker can see, so we don't internalize them.
  // For llvm.compiler.used the situation is a bit fuzzy. The assembler and
  // linker can drop those symbols. If this pass is running as part of LTO,
  // one might think that it could just drop llvm.compiler.used. The problem
  // is that even in LTO llvm doesn't see every reference. For example,
  // we don't see references from function local inline assembly. To be
  // conservative, we internalize symbols in llvm.compiler.used, but we
  // keep llvm.compiler.used so that the symbol is not deleted by llvm.
  for (GlobalValue *V : Used) {
    AlwaysPreserved.insert(V->getName());
  }

  // Mark all functions not in the api as internal.
  for (Function &I : M) {
    if (!maybeInternalize(I, ExternalComdats))
      continue;

    if (ExternalNode)
      // Remove a callgraph edge from the external node to this function.
      ExternalNode->removeOneAbstractEdgeTo((*CG)[&I]);

    ++NumFunctions;
    DEBUG(dbgs() << "Internalizing func " << I.getName() << "\n");
  }

  // Never internalize the llvm.used symbol.  It is used to implement
  // attribute((used)).
  // FIXME: Shouldn't this just filter on llvm.metadata section??
  AlwaysPreserved.insert("llvm.used");
  AlwaysPreserved.insert("llvm.compiler.used");

  // Never internalize anchors used by the machine module info, else the info
  // won't find them.  (see MachineModuleInfo.)
  AlwaysPreserved.insert("llvm.global_ctors");
  AlwaysPreserved.insert("llvm.global_dtors");
  AlwaysPreserved.insert("llvm.global.annotations");

  // Never internalize symbols code-gen inserts.
  // FIXME: We should probably add this (and the __stack_chk_guard) via some
  // type of call-back in CodeGen.
  AlwaysPreserved.insert("__stack_chk_fail");
  AlwaysPreserved.insert("__stack_chk_guard");

  // Mark all global variables with initializers that are not in the api as
  // internal as well.
  for (auto &GV : M.globals()) {
    if (!maybeInternalize(GV, ExternalComdats))
      continue;

    ++NumGlobals;
    DEBUG(dbgs() << "Internalized gvar " << GV.getName() << "\n");
  }

  // Mark all aliases that are not in the api as internal as well.
  for (auto &GA : M.aliases()) {
    if (!maybeInternalize(GA, ExternalComdats))
      continue;

    ++NumAliases;
    DEBUG(dbgs() << "Internalized alias " << GA.getName() << "\n");
  }

  // We do not keep track of whether this pass changed the module because
  // it adds unnecessary complexity:
  // 1) This pass will generally be near the start of the pass pipeline, so
  //    there will be no analyses to invalidate.
  // 2) This pass will most likely end up changing the module and it isn't worth
  //    worrying about optimizing the case where the module is unchanged.
  return true;
}

/// Public API below

bool llvm::internalizeModule(
    Module &TheModule,
    const std::function<bool(const GlobalValue &)> &MustPreserveGV,
    CallGraph *CG) {
  return Internalizer(MustPreserveGV).internalizeModule(TheModule, CG);
}

ModulePass *llvm::createInternalizePass() { return new InternalizePass(); }

ModulePass *llvm::createInternalizePass(
    std::function<bool(const GlobalValue &)> MustPreserveGV) {
  return new InternalizePass(std::move(MustPreserveGV));
}
<|endoftext|>