<commit_before>/**
 * @file kmeans_main.cpp
 * @author Ryan Curtin
 *
 * Executable for running K-Means.
 */
#include <mlpack/core.hpp>

#include "kmeans.hpp"
#include "allow_empty_clusters.hpp"

using namespace mlpack;
using namespace mlpack::kmeans;
using namespace std;

// Define parameters for the executable.
PROGRAM_INFO("K-Means Clustering", "This program performs K-Means clustering "
    "on the given dataset, storing the learned cluster assignments either as "
    "a column of labels in the file containing the input dataset or in a "
    "separate file.  Empty clusters are not allowed by default; when a cluster "
    "becomes empty, the point furthest from the centroid of the cluster with "
    "maximum variance is taken to fill that cluster.", "");

PARAM_STRING_REQ("input_file", "Input dataset to perform clustering on.", "");
PARAM_INT_REQ("clusters", "Number of clusters to find.", "");
PARAM_FLAG("in_place", "If specified, a column of the learned cluster "
    "assignments will be added to the input dataset file.  In this case "
    "--output_file is not necessary.", "");
PARAM_STRING("output_file", "File to write output labels to.", "", "");
PARAM_FLAG("allow_empty_clusters", "Allow empty clusters to be created.", "");
PARAM_FLAG("labels_only", "Only output labels into output file.", "");
PARAM_DOUBLE("overclustering", "Finds (overclustering * clusters) clusters, "
    "then merges them together until only the desired number of clusters are "
    "left.", "", 1.0);
PARAM_INT("max_iterations", "Maximum number of iterations before K-Means "
    "terminates.", "", 1000);

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Initialize random seed -- because that makes a difference.
  srand(time(NULL));

  // Now do validation of options.
  string input_file = CLI::GetParam<string>("input_file");
  int clusters = CLI::GetParam<int>("clusters");
  if (clusters < 1)
  {
    Log::Fatal << "Invalid number of clusters requested (" << clusters << ")! "
        << "Must be greater than or equal to 1." << std::endl;
  }

  int maxIterations = CLI::GetParam<int>("max_iterations");
  if (maxIterations < 0)
  {
    Log::Fatal << "Invalid value for maximum iterations (" << maxIterations <<
        ")! Must be greater than or equal to 0." << std::endl;
  }

  double overclustering = CLI::GetParam<double>("overclustering");
  if (overclustering < 1)
  {
    Log::Fatal << "Invalid value for overclustering (" << overclustering <<
        ")! Must be greater than or equal to 1." << std::endl;
  }

  // Make sure we have an output file if we're not doing the work in-place.
  if (!CLI::HasParam("in_place") && !CLI::HasParam("output_file"))
  {
    Log::Fatal << "--output_file not specified (and --in_place not set)."
        << std::endl;
  }

  // Load our dataset.
  arma::mat dataset;
  data::Load(input_file.c_str(), dataset);

  // Now create the KMeans object.  Because we could be using different types,
  // it gets a little weird...
  arma::Col<size_t> assignments;
  if (CLI::HasParam("allow_empty_clusters"))
  {
    KMeans<metric::SquaredEuclideanDistance, RandomPartition,
        AllowEmptyClusters> k(maxIterations, overclustering);

    k.Cluster(dataset, clusters, assignments);
  }
  else
  {
    KMeans<> k(maxIterations, overclustering);

    k.Cluster(dataset, clusters, assignments);
  }

  // Now figure out what to do with our results.
  if (CLI::HasParam("in_place"))
  {
    // Add the column of assignments to the dataset; but we have to convert them
    // to type double first.
    arma::vec converted(assignments.n_elem);
    for (size_t i = 0; i < assignments.n_elem; i++)
      converted(i) = (double) assignments(i);

    dataset.insert_rows(dataset.n_rows, trans(converted));

    // Save the dataset.
    data::Save(input_file.c_str(), dataset);
  }
  else
  {
    if (CLI::HasParam("only_labels"))
    {
      // Save only the labels.
      string output_file = CLI::GetParam<string>("output_file");
      arma::Mat<size_t> output = trans(assignments);
      data::Save(output_file.c_str(), output);
    }
    else
    {
      // Convert the assignments to doubles.
      arma::vec converted(assignments.n_elem);
      for (size_t i = 0; i < assignments.n_elem; i++)
        converted(i) = (double) assignments(i);

      dataset.insert_rows(dataset.n_rows, trans(converted));

      // Now save, in the different file.
      string output_file = CLI::GetParam<string>("output_file");
      data::Save(output_file.c_str(), dataset);
    }
  }
}

<commit_msg>Misspelling of option.<commit_after>/**
 * @file kmeans_main.cpp
 * @author Ryan Curtin
 *
 * Executable for running K-Means.
 */
#include <mlpack/core.hpp>

#include "kmeans.hpp"
#include "allow_empty_clusters.hpp"

using namespace mlpack;
using namespace mlpack::kmeans;
using namespace std;

// Define parameters for the executable.
PROGRAM_INFO("K-Means Clustering", "This program performs K-Means clustering "
    "on the given dataset, storing the learned cluster assignments either as "
    "a column of labels in the file containing the input dataset or in a "
    "separate file.  Empty clusters are not allowed by default; when a cluster "
    "becomes empty, the point furthest from the centroid of the cluster with "
    "maximum variance is taken to fill that cluster.", "");

PARAM_STRING_REQ("input_file", "Input dataset to perform clustering on.", "");
PARAM_INT_REQ("clusters", "Number of clusters to find.", "");
PARAM_FLAG("in_place", "If specified, a column of the learned cluster "
    "assignments will be added to the input dataset file.  In this case "
    "--output_file is not necessary.", "");
PARAM_STRING("output_file", "File to write output labels to.", "", "");
PARAM_FLAG("allow_empty_clusters", "Allow empty clusters to be created.", "");
PARAM_FLAG("labels_only", "Only output labels into output file.", "");
PARAM_DOUBLE("overclustering", "Finds (overclustering * clusters) clusters, "
    "then merges them together until only the desired number of clusters are "
    "left.", "", 1.0);
PARAM_INT("max_iterations", "Maximum number of iterations before K-Means "
    "terminates.", "", 1000);

int main(int argc, char** argv)
{
  CLI::ParseCommandLine(argc, argv);

  // Initialize random seed -- because that makes a difference.
  srand(time(NULL));

  // Now do validation of options.
  string input_file = CLI::GetParam<string>("input_file");
  int clusters = CLI::GetParam<int>("clusters");
  if (clusters < 1)
  {
    Log::Fatal << "Invalid number of clusters requested (" << clusters << ")! "
        << "Must be greater than or equal to 1." << std::endl;
  }

  int maxIterations = CLI::GetParam<int>("max_iterations");
  if (maxIterations < 0)
  {
    Log::Fatal << "Invalid value for maximum iterations (" << maxIterations <<
        ")! Must be greater than or equal to 0." << std::endl;
  }

  double overclustering = CLI::GetParam<double>("overclustering");
  if (overclustering < 1)
  {
    Log::Fatal << "Invalid value for overclustering (" << overclustering <<
        ")! Must be greater than or equal to 1." << std::endl;
  }

  // Make sure we have an output file if we're not doing the work in-place.
  if (!CLI::HasParam("in_place") && !CLI::HasParam("output_file"))
  {
    Log::Fatal << "--output_file not specified (and --in_place not set)."
        << std::endl;
  }

  // Load our dataset.
  arma::mat dataset;
  data::Load(input_file.c_str(), dataset);

  // Now create the KMeans object.  Because we could be using different types,
  // it gets a little weird...
  arma::Col<size_t> assignments;
  if (CLI::HasParam("allow_empty_clusters"))
  {
    KMeans<metric::SquaredEuclideanDistance, RandomPartition,
        AllowEmptyClusters> k(maxIterations, overclustering);

    k.Cluster(dataset, clusters, assignments);
  }
  else
  {
    KMeans<> k(maxIterations, overclustering);

    k.Cluster(dataset, clusters, assignments);
  }

  // Now figure out what to do with our results.
  if (CLI::HasParam("in_place"))
  {
    // Add the column of assignments to the dataset; but we have to convert them
    // to type double first.
    arma::vec converted(assignments.n_elem);
    for (size_t i = 0; i < assignments.n_elem; i++)
      converted(i) = (double) assignments(i);

    dataset.insert_rows(dataset.n_rows, trans(converted));

    // Save the dataset.
    data::Save(input_file.c_str(), dataset);
  }
  else
  {
    if (CLI::HasParam("labels_only"))
    {
      // Save only the labels.
      string output_file = CLI::GetParam<string>("output_file");
      arma::Mat<size_t> output = trans(assignments);
      data::Save(output_file.c_str(), output);
    }
    else
    {
      // Convert the assignments to doubles.
      arma::vec converted(assignments.n_elem);
      for (size_t i = 0; i < assignments.n_elem; i++)
        converted(i) = (double) assignments(i);

      dataset.insert_rows(dataset.n_rows, trans(converted));

      // Now save, in the different file.
      string output_file = CLI::GetParam<string>("output_file");
      data::Save(output_file.c_str(), dataset);
    }
  }
}

<|endoftext|>


<commit_before>/*
    daemon.cpp

    Copyright (c) 2013, Nikita Karnauhov

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
*/

#include <string>
#include <stdexcept>
#include <memory>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <list>
#include <set>
#include <thread>
#include <mutex>
#include <unordered_map>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>

#include <alsa/asoundlib.h>

#include <lansink.pb.h>
#include "log.h"
#include "alsa.h"
#include "player.h"
#include "settings.h"

// Signal flags.
static int g_nExitSignal = 0;

static
void _print_usage(std::ostream &_os) {
    static const Settings c_defaults;

    _os << "d, network audio receiver.\n" <<
            "Usage: " LANSINK_PROGRAM_NAME " [OPTION]...\n\n" <<
            "  -h, --help                       Print this message and exit.\n" <<
            "  -v, --version                    Display the version and exit.\n" <<
            "  -c, --config-path PATH           Set configuration file location.\n" <<
            "  -l, --log-path PATH              Set log file location (default: " << c_defaults.strLogPath << ").\n" <<
            "  -L, --log-level NUMBER           Set log verbosity level (default: " << c_defaults.nLogLevel << ", maximum: 4).\n" <<
            "  -d, --daemon                     Run as a daemon.\n" <<
            "  -n, --no-daemon                  Don't run as a daemon, display log messages (default).\n" <<
            "  -p, --pid-path PATH              PID file location (default: " << c_defaults.strPIDPath << ").\n" <<
            "  -H, --host NAME                  Server host.\n" <<
            "  -P, --port NUMBER                Server port (default: " << c_defaults.nPort << ").\n" <<
            "  -D, --alsa-device NAME           Output ALSA device.\n" <<
            "  -x, --exclusive                  Do not try to open device if it is already in use.\n" <<
            "      --no-exclusive               Try to open device for every new connection (default).\n" <<
            "      --recovery-timeout SECONDS   Seconds to wait after for stream data to reappear (default: " << c_defaults.nRecoveryTimeout << ").\n" <<
            "      --open-timeout MILLISECONDS  Milliseconds to wait between attempts to open device (default: " << c_defaults.nOpenTimeout << ").\n" <<
            "      --buffered-packets NUMBER    Number of packets preserved if failed to open device (default: " << c_defaults.nBufferedPackets << ").\n" <<
            "" << std::flush;
}

static
void _print_version() {
    std::cout << LANSINK_PROGRAM_NAME << ", network audio receiver.\n" <<
            "Version 0.1" << std::endl;
}

static
void _parse_options(int _nArgs, char *const _pArgs[]) {
    static struct option options[] = {
            {"help", 0, 0, 'h'},
            {"version", 0, 0, 'v'},
            {"config-path", required_argument, 0, 'c'},

            // These options have equivalents in settings file.
            {"log-path", required_argument, 0, 'l'},
            {"log-level", required_argument, 0, 'L'},
            {"daemon", 0, 0, 'd'},
            {"no-daemon", 0, 0, 'n'},
            {"pid-path", required_argument, 0, 'p'},
            {"host", required_argument, 0, 'H'},
            {"port", required_argument, 0, 'P'},
            {"alsa-device", required_argument, 0, 'D'},
            {"recovery-timeout", required_argument, 0, 500},
            {"open-timeout", required_argument, 0, 501},
            {"exclusive", 0, 0, 'x'},
            {"no-exclusive", 0, 0, 502},
            {0, 0, 0, 0}
    };

    const char *strOptions = "hvc:l:L:dnp:H:P:D:x";
    int nOption = 0;
    SettingsParser sp;
    std::map<std::string, std::string> kvs;
    std::unordered_map<int, std::string> longNames;

    for (auto &option : options)
        if (option.name)
            longNames[option.val] = option.name;

    // Handle --help, --version and --config-path options.
    while (true) {
        const int c = getopt_long(_nArgs, _pArgs, strOptions, options, &nOption);

        if (c == -1) {
            if (optind < _nArgs)
                throw RuntimeError("Redundant argument: %s", _pArgs[optind]);
            break;
        }

        switch (c) {
            case 'h':
                _print_usage(std::cout);
                exit(EXIT_SUCCESS);

            case 'v':
                _print_version();
                exit(EXIT_SUCCESS);

            case 'c':
                sp.parse_file(optarg);
                break;

            case 'd':
                kvs["daemon"] = "true";
                break;

            case 'n':
                kvs["daemon"] = "false";
                break;

            case 'x':
                kvs["exclusive"] = "true";
                break;

            case 502:
                kvs["exclusive"] = "false";
                break;

            case '?':
                _print_usage(std::cerr);
                exit(EXIT_FAILURE);

            default:
                if (!optarg)
                    throw LogicError("Option '%c' requires argument", c);

                kvs[longNames[c]] = optarg;
                break;
        }
    }

    for (auto &kv : kvs)
        sp.parse_option(kv.first, kv.second);

    g_settings = sp.get();

    if (g_settings.nLogLevel < llSilent || g_settings.nLogLevel > llDebug)
        throw RuntimeError("Invalid log level %d (must be between %d and %d)",
                g_settings.nLogLevel, llSilent, llDebug);
}

static
std::string _in_addr_to_string(struct sockaddr *_pAddr) {
    char buf[INET6_ADDRSTRLEN];
    void *pInAddr = nullptr;
    int nPort = 0;

    if (_pAddr->sa_family == AF_INET) {
        auto p = (struct sockaddr_in *)_pAddr;
        pInAddr = &p->sin_addr;
        nPort = p->sin_port;
    } else {
        auto p = (struct sockaddr_in6 *)_pAddr;
        pInAddr = &p->sin6_addr;
        nPort = p->sin6_port;
    }

    inet_ntop(_pAddr->sa_family, pInAddr, buf, sizeof(buf));

    return std::string(buf) + ":" + std::to_string(ntohs(nPort));
}

static
bool _write_pid(Log &_log) {
    // Specify empty PID path to disable writing PID.
    if (g_settings.strPIDPath.empty())
        return false;

    std::ofstream os(g_settings.strPIDPath);

    if (!os.good())
        throw RuntimeError("Cannot write PID file: %s", g_settings.strPIDPath.c_str());

    os << getpid() << std::endl;
    _log.info("PID file written to %s", g_settings.strPIDPath.c_str());

    return true;
}

static
void _main(Log &_log, bool &_bPIDWritten) {
    std::string strPort = format(16, "%d", g_settings.nPort);
    struct addrinfo hints = {};
    struct addrinfo *pServerInfo = nullptr;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if (getaddrinfo(g_settings.strHost.empty() ? NULL : g_settings.strHost.c_str(),
            strPort.c_str(), &hints, &pServerInfo) < 0)
        throw SystemError("getaddrinfo()");

    const int nSocket = socket(pServerInfo->ai_family,
            pServerInfo->ai_socktype, pServerInfo->ai_protocol);

    if (bind(nSocket, pServerInfo->ai_addr, pServerInfo->ai_addrlen) < 0)
        throw SystemError("bind()");

    _log.info("Server listening on %s",
            _in_addr_to_string(pServerInfo->ai_addr).c_str(), g_settings.nPort);

    freeaddrinfo(pServerInfo);

    _bPIDWritten = _write_pid(_log);

    struct pollfd fd{nSocket, POLLIN, 0};
    constexpr size_t cBufferSize = 1024*100; // Should be enough, right?
    auto pBuf = std::unique_ptr<char[]>(new char[cBufferSize]);
    std::list<lansink::Packet> packets;

    typedef std::chrono::steady_clock Clock;
    typedef std::chrono::duration<int, std::milli> Duration;
    typedef std::chrono::time_point<Clock> TimePoint;
    TimePoint m_lastOpenAttempt;

    do {
        try {
            if (poll(&fd, 1, 1000) < 0)
                throw SystemError("poll()");

            if (fd.revents & POLLIN) {
                struct sockaddr_storage sender = {};
                socklen_t cSendSize = sizeof(sender);

                bzero(&sender, sizeof(sender));

                const int nPacketSize = recvfrom(
                        fd.fd, pBuf.get(), cBufferSize, 0, (struct sockaddr *)&sender, &cSendSize);

                if (nPacketSize < 0)
                    throw SystemError("recvfrom()");

                lansink::Packet &packet = *packets.emplace(packets.end());

                if (!packet.ParseFromArray(pBuf.get(), nPacketSize)) {
                    _log.warning("Broken packet from %s",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    continue;
                }

                if (packets.size() > (size_t)g_settings.nBufferedPackets)
                    packets.pop_front();

                if (m_lastOpenAttempt.time_since_epoch().count() > 0) {
                    // Last attempt at open() failed, check if timeout expired.
                    Duration ms(std::chrono::duration_cast<Duration>(Clock::now() - m_lastOpenAttempt));
                    if (ms.count() < g_settings.nOpenTimeout)
                        continue;
                }

                Player::TimePoint errorTime;
                Player *pPlayer = Player::get(packet, _log, errorTime);

                if (!pPlayer) {
                    _log.info("Dropping connection from %s: device is busy",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    m_lastOpenAttempt = TimePoint(errorTime.time_since_epoch());
                    continue;
                }

                if (!pPlayer->is_prepared()) {
                    _log.info("New connection from %s",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    pPlayer->init(packet);

                    if (pPlayer->is_prepared()) {
                        m_lastOpenAttempt = TimePoint();
                        pPlayer->run();
                    } else {
                        m_lastOpenAttempt = Clock::now();
                        continue;
                    }
                }

                for (auto iPacket = packets.begin(); iPacket != packets.end();)
                    if (iPacket->stream() == pPlayer->get_id()) {
                        pPlayer->play(*iPacket);
                        iPacket = packets.erase(iPacket);
                    } else
                        ++iPacket;
            }
        } catch (SystemError &se) {
            if (se.get_error() != EINTR)
                throw;
        }

        if (g_nExitSignal != 0)
            _log.info("Got signal %d, exiting gracefully.", g_nExitSignal);
    } while (g_nExitSignal == 0);
}

static
void _handle_signal(int _nSignal, siginfo_t *_pSigInfo, void *_pContext) {
    g_nExitSignal = _nSignal;
}

static
void _init_signals() {
    struct sigaction action = {};
    const int exitSignals[]{
            SIGTERM, SIGINT, SIGPIPE, SIGALRM, SIGUSR1, SIGUSR2, SIGPOLL,
            SIGPROF, SIGVTALRM
    };

    action.sa_sigaction = &_handle_signal;
    action.sa_flags = SA_SIGINFO;

    for (int nSignal : exitSignals)
        if (sigaction(nSignal, &action, NULL) < 0)
            throw SystemError("sigaction()");

}

int main(int _nArgs, char *const _pArgs[]) {
    Log log("");
    bool bPIDWritten = false; // FIXME do not overwrite PID if failed to start.

    log.setLevel(llError);

    try {
        _parse_options(_nArgs, _pArgs);
        log.setLevel(LogLevel(g_settings.nLogLevel));

        if (!g_settings.strLogPath.empty()) {
            log.open(g_settings.strLogPath);
            log.info("Logging to %s", g_settings.strLogPath.c_str());
        }

        if (g_settings.bDaemon) {
            log.close("");

            if (daemon(true, false) != 0)
                throw SystemError("daemon()");
        }

        _init_signals();
        _main(log, bPIDWritten);
    } catch (std::exception &e) {
        log.error(e.what());
        return EXIT_FAILURE;
    }

    if (bPIDWritten)
        unlink(g_settings.strPIDPath.c_str());

    return EXIT_SUCCESS;
}
<commit_msg>Log active daemon settings.<commit_after>/*
    daemon.cpp

    Copyright (c) 2013, Nikita Karnauhov

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
*/

#include <string>
#include <stdexcept>
#include <memory>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <list>
#include <set>
#include <thread>
#include <mutex>
#include <unordered_map>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>

#include <alsa/asoundlib.h>

#include <lansink.pb.h>
#include "log.h"
#include "alsa.h"
#include "player.h"
#include "settings.h"

// Signal flags.
static int g_nExitSignal = 0;

static
void _print_usage(std::ostream &_os) {
    static const Settings c_defaults;

    _os << "d, network audio receiver.\n" <<
            "Usage: " LANSINK_PROGRAM_NAME " [OPTION]...\n\n" <<
            "  -h, --help                       Print this message and exit.\n" <<
            "  -v, --version                    Display the version and exit.\n" <<
            "  -c, --config-path PATH           Set configuration file location.\n" <<
            "  -l, --log-path PATH              Set log file location (default: " << c_defaults.strLogPath << ").\n" <<
            "  -L, --log-level NUMBER           Set log verbosity level (default: " << c_defaults.nLogLevel << ", maximum: 4).\n" <<
            "  -d, --daemon                     Run as a daemon.\n" <<
            "  -n, --no-daemon                  Don't run as a daemon, display log messages (default).\n" <<
            "  -p, --pid-path PATH              PID file location (default: " << c_defaults.strPIDPath << ").\n" <<
            "  -H, --host NAME                  Server host.\n" <<
            "  -P, --port NUMBER                Server port (default: " << c_defaults.nPort << ").\n" <<
            "  -D, --alsa-device NAME           Output ALSA device.\n" <<
            "  -x, --exclusive                  Do not try to open device if it is already in use.\n" <<
            "      --no-exclusive               Try to open device for every new connection (default).\n" <<
            "      --recovery-timeout SECONDS   Seconds to wait after for stream data to reappear (default: " << c_defaults.nRecoveryTimeout << ").\n" <<
            "      --open-timeout MILLISECONDS  Milliseconds to wait between attempts to open device (default: " << c_defaults.nOpenTimeout << ").\n" <<
            "      --buffered-packets NUMBER    Number of packets preserved if failed to open device (default: " << c_defaults.nBufferedPackets << ").\n" <<
            "" << std::flush;
}

static
void _print_version() {
    std::cout << LANSINK_PROGRAM_NAME << ", network audio receiver.\n" <<
            "Version 0.1" << std::endl;
}

static
void _parse_options(int _nArgs, char *const _pArgs[]) {
    static struct option options[] = {
            {"help", 0, 0, 'h'},
            {"version", 0, 0, 'v'},
            {"config-path", required_argument, 0, 'c'},

            // These options have equivalents in settings file.
            {"log-path", required_argument, 0, 'l'},
            {"log-level", required_argument, 0, 'L'},
            {"daemon", 0, 0, 'd'},
            {"no-daemon", 0, 0, 'n'},
            {"pid-path", required_argument, 0, 'p'},
            {"host", required_argument, 0, 'H'},
            {"port", required_argument, 0, 'P'},
            {"alsa-device", required_argument, 0, 'D'},
            {"recovery-timeout", required_argument, 0, 500},
            {"open-timeout", required_argument, 0, 501},
            {"exclusive", 0, 0, 'x'},
            {"no-exclusive", 0, 0, 502},
            {0, 0, 0, 0}
    };

    const char *strOptions = "hvc:l:L:dnp:H:P:D:x";
    int nOption = 0;
    SettingsParser sp;
    std::map<std::string, std::string> kvs;
    std::unordered_map<int, std::string> longNames;

    for (auto &option : options)
        if (option.name)
            longNames[option.val] = option.name;

    // Handle --help, --version and --config-path options.
    while (true) {
        const int c = getopt_long(_nArgs, _pArgs, strOptions, options, &nOption);

        if (c == -1) {
            if (optind < _nArgs)
                throw RuntimeError("Redundant argument: %s", _pArgs[optind]);
            break;
        }

        switch (c) {
            case 'h':
                _print_usage(std::cout);
                exit(EXIT_SUCCESS);

            case 'v':
                _print_version();
                exit(EXIT_SUCCESS);

            case 'c':
                sp.parse_file(optarg);
                break;

            case 'd':
                kvs["daemon"] = "true";
                break;

            case 'n':
                kvs["daemon"] = "false";
                break;

            case 'x':
                kvs["exclusive"] = "true";
                break;

            case 502:
                kvs["exclusive"] = "false";
                break;

            case '?':
                _print_usage(std::cerr);
                exit(EXIT_FAILURE);

            default:
                if (!optarg)
                    throw LogicError("Option '%c' requires argument", c);

                kvs[longNames[c]] = optarg;
                break;
        }
    }

    for (auto &kv : kvs)
        sp.parse_option(kv.first, kv.second);

    g_settings = sp.get();

    if (g_settings.nLogLevel < llSilent || g_settings.nLogLevel > llDebug)
        throw RuntimeError("Invalid log level %d (must be between %d and %d)",
                g_settings.nLogLevel, llSilent, llDebug);
}

static
std::string _in_addr_to_string(struct sockaddr *_pAddr) {
    char buf[INET6_ADDRSTRLEN];
    void *pInAddr = nullptr;
    int nPort = 0;

    if (_pAddr->sa_family == AF_INET) {
        auto p = (struct sockaddr_in *)_pAddr;
        pInAddr = &p->sin_addr;
        nPort = p->sin_port;
    } else {
        auto p = (struct sockaddr_in6 *)_pAddr;
        pInAddr = &p->sin6_addr;
        nPort = p->sin6_port;
    }

    inet_ntop(_pAddr->sa_family, pInAddr, buf, sizeof(buf));

    return std::string(buf) + ":" + std::to_string(ntohs(nPort));
}

static
bool _write_pid(Log &_log) {
    // Specify empty PID path to disable writing PID.
    if (g_settings.strPIDPath.empty())
        return false;

    std::ofstream os(g_settings.strPIDPath);

    if (!os.good())
        throw RuntimeError("Cannot write PID file: %s", g_settings.strPIDPath.c_str());

    os << getpid() << std::endl;
    _log.info("PID file written to %s", g_settings.strPIDPath.c_str());

    return true;
}

static
void _main(Log &_log, bool &_bPIDWritten) {
    std::string strPort = format(16, "%d", g_settings.nPort);
    struct addrinfo hints = {};
    struct addrinfo *pServerInfo = nullptr;

    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if (getaddrinfo(g_settings.strHost.empty() ? NULL : g_settings.strHost.c_str(),
            strPort.c_str(), &hints, &pServerInfo) < 0)
        throw SystemError("getaddrinfo()");

    const int nSocket = socket(pServerInfo->ai_family,
            pServerInfo->ai_socktype, pServerInfo->ai_protocol);

    if (bind(nSocket, pServerInfo->ai_addr, pServerInfo->ai_addrlen) < 0)
        throw SystemError("bind()");

    _log.info("Server listening on %s",
            _in_addr_to_string(pServerInfo->ai_addr).c_str(), g_settings.nPort);

    freeaddrinfo(pServerInfo);

    _bPIDWritten = _write_pid(_log);

    struct pollfd fd{nSocket, POLLIN, 0};
    constexpr size_t cBufferSize = 1024*100; // Should be enough, right?
    auto pBuf = std::unique_ptr<char[]>(new char[cBufferSize]);
    std::list<lansink::Packet> packets;

    typedef std::chrono::steady_clock Clock;
    typedef std::chrono::duration<int, std::milli> Duration;
    typedef std::chrono::time_point<Clock> TimePoint;
    TimePoint m_lastOpenAttempt;

    do {
        try {
            if (poll(&fd, 1, 1000) < 0)
                throw SystemError("poll()");

            if (fd.revents & POLLIN) {
                struct sockaddr_storage sender = {};
                socklen_t cSendSize = sizeof(sender);

                bzero(&sender, sizeof(sender));

                const int nPacketSize = recvfrom(
                        fd.fd, pBuf.get(), cBufferSize, 0, (struct sockaddr *)&sender, &cSendSize);

                if (nPacketSize < 0)
                    throw SystemError("recvfrom()");

                lansink::Packet &packet = *packets.emplace(packets.end());

                if (!packet.ParseFromArray(pBuf.get(), nPacketSize)) {
                    _log.warning("Broken packet from %s",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    packets.pop_back();
                    continue;
                }

                if (packets.size() > (size_t)g_settings.nBufferedPackets)
                    packets.pop_front();

                if (m_lastOpenAttempt.time_since_epoch().count() > 0) {
                    // Last attempt at open() failed, check if timeout expired.
                    Duration ms(std::chrono::duration_cast<Duration>(Clock::now() - m_lastOpenAttempt));
                    if (ms.count() < g_settings.nOpenTimeout)
                        continue;
                }

                Player::TimePoint errorTime;
                Player *pPlayer = Player::get(packet, _log, errorTime);

                if (!pPlayer) {
                    _log.info("Dropping connection from %s: device is busy",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    m_lastOpenAttempt = TimePoint(errorTime.time_since_epoch());
                    continue;
                }

                if (!pPlayer->is_prepared()) {
                    _log.info("New connection from %s",
                            _in_addr_to_string((struct sockaddr *)&sender).c_str());
                    pPlayer->init(packet);

                    if (pPlayer->is_prepared()) {
                        m_lastOpenAttempt = TimePoint();
                        pPlayer->run();
                    } else {
                        m_lastOpenAttempt = Clock::now();
                        continue;
                    }
                }

                for (auto iPacket = packets.begin(); iPacket != packets.end();)
                    if (iPacket->stream() == pPlayer->get_id()) {
                        pPlayer->play(*iPacket);
                        iPacket = packets.erase(iPacket);
                    } else
                        ++iPacket;
            }
        } catch (SystemError &se) {
            if (se.get_error() != EINTR)
                throw;
        }

        if (g_nExitSignal != 0)
            _log.info("Got signal %d, exiting gracefully.", g_nExitSignal);
    } while (g_nExitSignal == 0);
}

static
void _handle_signal(int _nSignal, siginfo_t *_pSigInfo, void *_pContext) {
    g_nExitSignal = _nSignal;
}

static
void _init_signals() {
    struct sigaction action = {};
    const int exitSignals[]{
            SIGTERM, SIGINT, SIGPIPE, SIGALRM, SIGUSR1, SIGUSR2, SIGPOLL,
            SIGPROF, SIGVTALRM
    };

    action.sa_sigaction = &_handle_signal;
    action.sa_flags = SA_SIGINFO;

    for (int nSignal : exitSignals)
        if (sigaction(nSignal, &action, NULL) < 0)
            throw SystemError("sigaction()");

}

static
void _log_settings(Log & _log) {
    _log.info("Running with the following settings:");
    _log.info("daemon = %d", g_settings.bDaemon);
    _log.info("exclusive = %d", g_settings.bExclusive);
    _log.info("log-level = %d", g_settings.nLogLevel);
    _log.info("port = %d", g_settings.nPort);
    _log.info("recovery-timeout = %d", g_settings.nRecoveryTimeout);
    _log.info("open-timeout = %d", g_settings.nOpenTimeout);
    _log.info("buffered-packets = %d", g_settings.nBufferedPackets);
    _log.info("log-path = %s", g_settings.strLogPath.c_str());
    _log.info("pid-path = %s", g_settings.strPIDPath.c_str());
    _log.info("host = %s", g_settings.strHost.c_str());
    _log.info("alsa-device = %s", g_settings.strALSADevice.c_str());
}

int main(int _nArgs, char *const _pArgs[]) {
    Log log("");
    bool bPIDWritten = false; // FIXME do not overwrite PID if failed to start.

    log.setLevel(llError);

    try {
        _parse_options(_nArgs, _pArgs);
        log.setLevel(LogLevel(g_settings.nLogLevel));

        if (!g_settings.strLogPath.empty()) {
            log.open(g_settings.strLogPath);
            log.info("Logging to %s", g_settings.strLogPath.c_str());
        }

        if (g_settings.bDaemon) {
            log.close("");

            if (daemon(true, false) != 0)
                throw SystemError("daemon()");
        }

        _init_signals();
        _log_settings(log);
        _main(log, bPIDWritten);
    } catch (std::exception &e) {
        log.error(e.what());
        return EXIT_FAILURE;
    }

    if (bPIDWritten)
        unlink(g_settings.strPIDPath.c_str());

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>coverity#982152 Unchecked return value<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: managelang.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2007-01-02 15:51:44 $
 *
 *  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_basctl.hxx"

#include "managelang.hxx"
#include "iderid.hxx"
#include "localizationmgr.hxx"
#include "iderdll.hxx"
#include "basidesh.hxx"
#include "basobj.hxx"

#include "managelang.hrc"
#include "dlgresid.hrc"
#include "helpid.hrc"

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_RESOURCE_XSTRINGRESOURCEMANAGER_HPP_
#include <com/sun/star/resource/XStringResourceManager.hpp>
#endif
#include <comphelper/processfactory.hxx>

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef _UNOTOOLS_LOCALEDATAWRAPPER_HXX
#include <unotools/localedatawrapper.hxx>
#endif
#ifndef _UNO_LINGU_HXX
#include <svx/unolingu.hxx>
#endif
#ifndef _SVX_LANGTAB_HXX
#include <svx/langtab.hxx>
#endif
#include <sfx2/bindings.hxx>

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::resource;
using namespace ::com::sun::star::uno;

bool localesAreEqual( const Locale& rLocaleLeft, const Locale& rLocaleRight )
{
    bool bRet = ( rLocaleLeft.Language.equals( rLocaleRight.Language ) &&
                  rLocaleLeft.Country.equals( rLocaleRight.Country ) &&
                  rLocaleLeft.Variant.equals( rLocaleRight.Variant ) );
    return bRet;
}

ManageLanguageDialog::ManageLanguageDialog( Window* pParent, LocalizationMgr* _pLMgr ) :

    ModalDialog( pParent, IDEResId( RID_DLG_MANAGE_LANGUAGE ) ),

    m_aLanguageFT       ( this, ResId( FT_LANGUAGE ) ),
    m_aLanguageLB       ( this, ResId( LB_LANGUAGE ) ),
    m_aAddPB            ( this, ResId( PB_ADD_LANG ) ),
    m_aDeletePB         ( this, ResId( PB_DEL_LANG ) ),
    m_aMakeDefPB        ( this, ResId( PB_MAKE_DEFAULT ) ),
    m_aInfoFT           ( this, ResId( FT_INFO ) ),
    m_aBtnLine          ( this, ResId( FL_BUTTONS ) ),
    m_aHelpBtn          ( this, ResId( PB_HELP ) ),
    m_aCloseBtn         ( this, ResId( PB_CLOSE ) ),
    m_pLocalizationMgr  ( _pLMgr ),
    m_sDefLangStr       (       ResId( STR_DEF_LANG ) ),
    m_sDeleteStr        (       ResId( STR_DELETE ) ),
    m_sCreateLangStr    (       ResId( STR_CREATE_LANG ) )

{
    FreeResource();

    Init();
    FillLanguageBox();
    SelectHdl( NULL );
}

ManageLanguageDialog::~ManageLanguageDialog()
{
    ClearLanguageBox();
}

void ManageLanguageDialog::Init()
{
    // get current IDE
    BasicIDEShell* pIDEShell = IDE_DLL()->GetShell();
    String sLibName = pIDEShell->GetCurLibName();
    // set dialog title with library name
    String sText = GetText();
    sText.SearchAndReplace( String::CreateFromAscii("$1"), sLibName );
    SetText( sText );
    // set handler
    m_aAddPB.SetClickHdl( LINK( this, ManageLanguageDialog, AddHdl ) );
    m_aDeletePB.SetClickHdl( LINK( this, ManageLanguageDialog, DeleteHdl ) );
    m_aMakeDefPB.SetClickHdl( LINK( this, ManageLanguageDialog, MakeDefHdl ) );
    m_aLanguageLB.SetSelectHdl( LINK( this, ManageLanguageDialog, SelectHdl ) );

    m_aLanguageLB.EnableMultiSelection( TRUE );
}

void ManageLanguageDialog::FillLanguageBox()
{
    DBG_ASSERT( m_pLocalizationMgr, "ManageLanguageDialog::FillLanguageBox(): no localization manager" );

    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        SvxLanguageTable aLangTable;
        Locale aDefaultLocale = m_pLocalizationMgr->getStringResourceManager()->getDefaultLocale();
        Sequence< Locale > aLocaleSeq = m_pLocalizationMgr->getStringResourceManager()->getLocales();
        const Locale* pLocale = aLocaleSeq.getConstArray();
        INT32 i, nCount = aLocaleSeq.getLength();
        for ( i = 0;  i < nCount;  ++i )
        {
            bool bIsDefault = localesAreEqual( aDefaultLocale, pLocale[i] );
            LanguageType eLangType = SvxLocaleToLanguage( pLocale[i] );
            String sLanguage = aLangTable.GetString( eLangType );
            if ( bIsDefault )
            {
                sLanguage += ' ';
                sLanguage += m_sDefLangStr;
            }
            USHORT nPos = m_aLanguageLB.InsertEntry( sLanguage );
            m_aLanguageLB.SetEntryData( nPos, new LanguageEntry( sLanguage, pLocale[i], bIsDefault ) );
        }
    }
    else
        m_aLanguageLB.InsertEntry( m_sCreateLangStr );
}

void ManageLanguageDialog::ClearLanguageBox()
{
    USHORT i, nCount = m_aLanguageLB.GetEntryCount();
    for ( i = 0; i < nCount; ++i )
    {
        LanguageEntry* pEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData(i) );
        if ( pEntry )
            delete pEntry;
    }
    m_aLanguageLB.Clear();
}

IMPL_LINK( ManageLanguageDialog, AddHdl, Button *, EMPTYARG )
{
    SetDefaultLanguageDialog aDlg( this, m_pLocalizationMgr );
    if ( RET_OK == aDlg.Execute() )
    {
        // add new locales
        Sequence< Locale > aLocaleSeq = aDlg.GetLocales();
        m_pLocalizationMgr->handleAddLocales( aLocaleSeq );
        // update listbox
        ClearLanguageBox();
        FillLanguageBox();

        SfxBindings* pBindings = BasicIDE::GetBindingsPtr();
        if ( pBindings )
            pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
    }
    return 1;
}

IMPL_LINK( ManageLanguageDialog, DeleteHdl, Button *, EMPTYARG )
{
    QueryBox aQBox( this, IDEResId( RID_QRYBOX_LANGUAGE ) );
    aQBox.SetButtonText( RET_OK, m_sDeleteStr );
    if ( aQBox.Execute() == RET_OK )
    {
        USHORT i, nCount = m_aLanguageLB.GetSelectEntryCount();
        USHORT nPos = m_aLanguageLB.GetSelectEntryPos();
        // remove locales
        Sequence< Locale > aLocaleSeq( nCount );
        for ( i = 0; i < nCount; ++i )
        {
            USHORT nSelPos = m_aLanguageLB.GetSelectEntryPos(i);
            LanguageEntry* pEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData( nSelPos ) );
            if ( pEntry )
                aLocaleSeq[i] = pEntry->m_aLocale;
        }
        m_pLocalizationMgr->handleRemoveLocales( aLocaleSeq );
        // update listbox
        ClearLanguageBox();
        FillLanguageBox();
        // reset selection
        nCount = m_aLanguageLB.GetEntryCount();
        if ( nCount <= nPos )
            nPos = nCount - 1;
        m_aLanguageLB.SelectEntryPos( nPos );
        SelectHdl( NULL );
    }
    return 1;
}

IMPL_LINK( ManageLanguageDialog, MakeDefHdl, Button *, EMPTYARG )
{
    USHORT nPos = m_aLanguageLB.GetSelectEntryPos();
    LanguageEntry* pSelectEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData( nPos ) );
    if ( pSelectEntry && !pSelectEntry->m_bIsDefault )
    {
        // set new default entry
        m_pLocalizationMgr->handleSetDefaultLocale( pSelectEntry->m_aLocale );
        // update Listbox
        ClearLanguageBox();
        FillLanguageBox();
        // reset selection
        m_aLanguageLB.SelectEntryPos( nPos );
        SelectHdl( NULL );
    }

    return 1;
}

IMPL_LINK( ManageLanguageDialog, SelectHdl, ListBox *, EMPTYARG )
{
    USHORT nCount = m_aLanguageLB.GetEntryCount();
    bool bEmpty = ( !nCount ||
                    m_aLanguageLB.GetEntryPos( m_sCreateLangStr ) != LISTBOX_ENTRY_NOTFOUND );
    bool bSelect = ( m_aLanguageLB.GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND );
    bool bEnable = ( !bEmpty && bSelect != false );

    m_aDeletePB.Enable( bEnable != false );
    m_aMakeDefPB.Enable( bEnable != false && nCount > 1 && m_aLanguageLB.GetSelectEntryCount() == 1 );

    return 1;
}

// class SetDefaultLanguageDialog -----------------------------------------------

SetDefaultLanguageDialog::SetDefaultLanguageDialog( Window* pParent, LocalizationMgr* _pLMgr ) :

    ModalDialog( pParent, IDEResId( RID_DLG_SETDEF_LANGUAGE ) ),

    m_aLanguageFT   ( this, ResId( FT_DEF_LANGUAGE ) ),
    m_aLanguageLB   ( this, ResId( LB_DEF_LANGUAGE ) ),
    m_aCheckLangLB  ( this, ResId( LB_ADD_LANGUAGE ) ),
    m_aInfoFT       ( this, ResId( FT_DEF_INFO ) ),
    m_aBtnLine      ( this, ResId( FL_DEF_BUTTONS ) ),
    m_aOKBtn        ( this, ResId( PB_DEF_OK ) ),
    m_aCancelBtn    ( this, ResId( PB_DEF_CANCEL ) ),
    m_aHelpBtn      ( this, ResId( PB_DEF_HELP ) ),

    m_pLocalizationMgr( _pLMgr )

{
    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        // change to "Add Interface Language" mode
        SetHelpId( HID_BASICIDE_ADDNEW_LANGUAGE );
        m_aLanguageLB.Hide();
        m_aCheckLangLB.Show();
        SetText( String( ResId( STR_ADDLANG_TITLE ) ) );
        m_aLanguageFT.SetText( String( ResId( STR_ADDLANG_LABEL ) ) );
        m_aInfoFT.SetText( String( ResId( STR_ADDLANG_INFO ) ) );
    }
    else
    {
        m_aCheckLangLB.Hide();
        m_aLanguageLB.Show();
    }

    FreeResource();
    FillLanguageBox();
}

SetDefaultLanguageDialog::~SetDefaultLanguageDialog()
{
}

void SetDefaultLanguageDialog::FillLanguageBox()
{
    // fill list with all languages
    m_aLanguageLB.SetLanguageList( LANG_LIST_ALL, FALSE );
    // remove the already localized languages
    Sequence< Locale > aLocaleSeq = m_pLocalizationMgr->getStringResourceManager()->getLocales();
    const Locale* pLocale = aLocaleSeq.getConstArray();
    INT32 i, nCount = aLocaleSeq.getLength();
    for ( i = 0;  i < nCount;  ++i )
        m_aLanguageLB.RemoveLanguage( SvxLocaleToLanguage( pLocale[i] ) );

    // fill checklistbox if not in default mode
    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        USHORT i, nCount = m_aLanguageLB.GetEntryCount();
        for ( i = 0;  i < nCount;  ++i )
            m_aCheckLangLB.InsertEntry( m_aLanguageLB.GetEntry(i) );
    }
    else
        // preselect current UI language
        m_aLanguageLB.SelectLanguage( Application::GetSettings().GetUILanguage() );
}

Sequence< Locale > SetDefaultLanguageDialog::GetLocales() const
{
    bool bNotLocalized = !m_pLocalizationMgr->isLibraryLocalized();
    INT32 nSize = bNotLocalized ? 1 : m_aCheckLangLB.GetCheckedEntryCount();
    Sequence< Locale > aLocaleSeq( nSize );
    if ( bNotLocalized )
    {
        Locale aLocale;
        SvxLanguageToLocale( aLocale, m_aLanguageLB.GetSelectLanguage() );
        aLocaleSeq[0] = aLocale;
    }
    else
    {
        USHORT i, nCount = static_cast< USHORT >( m_aCheckLangLB.GetEntryCount() );
        INT32 j = 0;
        for ( i = 0; i < nCount; ++i )
        {
            if ( m_aCheckLangLB.IsChecked(i) )
            {
                LanguageType eType = LanguageType( (ULONG)m_aLanguageLB.GetEntryData(i) );
                Locale aLocale;
                SvxLanguageToLocale( aLocale, eType );
                aLocaleSeq[j++] = aLocale;
            }
        }
        DBG_ASSERT( nSize == j, "SetDefaultLanguageDialog::GetLocales(): invalid indexes" );
    }
    return aLocaleSeq;
}

<commit_msg>INTEGRATION: CWS ab33 (1.2.4); FILE MERGED 2007/01/10 16:34:50 ab 1.2.4.1: #i69280# Removed warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: managelang.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2007-01-16 16:36:20 $
 *
 *  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_basctl.hxx"

#include "managelang.hxx"
#include "iderid.hxx"
#include "localizationmgr.hxx"
#include "iderdll.hxx"
#include "basidesh.hxx"
#include "basobj.hxx"

#include "managelang.hrc"
#include "dlgresid.hrc"
#include "helpid.hrc"

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_RESOURCE_XSTRINGRESOURCEMANAGER_HPP_
#include <com/sun/star/resource/XStringResourceManager.hpp>
#endif
#include <comphelper/processfactory.hxx>

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif
#ifndef _UNOTOOLS_LOCALEDATAWRAPPER_HXX
#include <unotools/localedatawrapper.hxx>
#endif
#ifndef _UNO_LINGU_HXX
#include <svx/unolingu.hxx>
#endif
#ifndef _SVX_LANGTAB_HXX
#include <svx/langtab.hxx>
#endif
#include <sfx2/bindings.hxx>

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::resource;
using namespace ::com::sun::star::uno;

bool localesAreEqual( const Locale& rLocaleLeft, const Locale& rLocaleRight )
{
    bool bRet = ( rLocaleLeft.Language.equals( rLocaleRight.Language ) &&
                  rLocaleLeft.Country.equals( rLocaleRight.Country ) &&
                  rLocaleLeft.Variant.equals( rLocaleRight.Variant ) );
    return bRet;
}

ManageLanguageDialog::ManageLanguageDialog( Window* pParent, LocalizationMgr* _pLMgr ) :

    ModalDialog( pParent, IDEResId( RID_DLG_MANAGE_LANGUAGE ) ),

    m_aLanguageFT       ( this, ResId( FT_LANGUAGE ) ),
    m_aLanguageLB       ( this, ResId( LB_LANGUAGE ) ),
    m_aAddPB            ( this, ResId( PB_ADD_LANG ) ),
    m_aDeletePB         ( this, ResId( PB_DEL_LANG ) ),
    m_aMakeDefPB        ( this, ResId( PB_MAKE_DEFAULT ) ),
    m_aInfoFT           ( this, ResId( FT_INFO ) ),
    m_aBtnLine          ( this, ResId( FL_BUTTONS ) ),
    m_aHelpBtn          ( this, ResId( PB_HELP ) ),
    m_aCloseBtn         ( this, ResId( PB_CLOSE ) ),
    m_pLocalizationMgr  ( _pLMgr ),
    m_sDefLangStr       (       ResId( STR_DEF_LANG ) ),
    m_sDeleteStr        (       ResId( STR_DELETE ) ),
    m_sCreateLangStr    (       ResId( STR_CREATE_LANG ) )

{
    FreeResource();

    Init();
    FillLanguageBox();
    SelectHdl( NULL );
}

ManageLanguageDialog::~ManageLanguageDialog()
{
    ClearLanguageBox();
}

void ManageLanguageDialog::Init()
{
    // get current IDE
    BasicIDEShell* pIDEShell = IDE_DLL()->GetShell();
    String sLibName = pIDEShell->GetCurLibName();
    // set dialog title with library name
    String sText = GetText();
    sText.SearchAndReplace( String::CreateFromAscii("$1"), sLibName );
    SetText( sText );
    // set handler
    m_aAddPB.SetClickHdl( LINK( this, ManageLanguageDialog, AddHdl ) );
    m_aDeletePB.SetClickHdl( LINK( this, ManageLanguageDialog, DeleteHdl ) );
    m_aMakeDefPB.SetClickHdl( LINK( this, ManageLanguageDialog, MakeDefHdl ) );
    m_aLanguageLB.SetSelectHdl( LINK( this, ManageLanguageDialog, SelectHdl ) );

    m_aLanguageLB.EnableMultiSelection( TRUE );
}

void ManageLanguageDialog::FillLanguageBox()
{
    DBG_ASSERT( m_pLocalizationMgr, "ManageLanguageDialog::FillLanguageBox(): no localization manager" );

    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        SvxLanguageTable aLangTable;
        Locale aDefaultLocale = m_pLocalizationMgr->getStringResourceManager()->getDefaultLocale();
        Sequence< Locale > aLocaleSeq = m_pLocalizationMgr->getStringResourceManager()->getLocales();
        const Locale* pLocale = aLocaleSeq.getConstArray();
        INT32 i, nCount = aLocaleSeq.getLength();
        for ( i = 0;  i < nCount;  ++i )
        {
            bool bIsDefault = localesAreEqual( aDefaultLocale, pLocale[i] );
            LanguageType eLangType = SvxLocaleToLanguage( pLocale[i] );
            String sLanguage = aLangTable.GetString( eLangType );
            if ( bIsDefault )
            {
                sLanguage += ' ';
                sLanguage += m_sDefLangStr;
            }
            USHORT nPos = m_aLanguageLB.InsertEntry( sLanguage );
            m_aLanguageLB.SetEntryData( nPos, new LanguageEntry( sLanguage, pLocale[i], bIsDefault ) );
        }
    }
    else
        m_aLanguageLB.InsertEntry( m_sCreateLangStr );
}

void ManageLanguageDialog::ClearLanguageBox()
{
    USHORT i, nCount = m_aLanguageLB.GetEntryCount();
    for ( i = 0; i < nCount; ++i )
    {
        LanguageEntry* pEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData(i) );
        if ( pEntry )
            delete pEntry;
    }
    m_aLanguageLB.Clear();
}

IMPL_LINK( ManageLanguageDialog, AddHdl, Button *, EMPTYARG )
{
    SetDefaultLanguageDialog aDlg( this, m_pLocalizationMgr );
    if ( RET_OK == aDlg.Execute() )
    {
        // add new locales
        Sequence< Locale > aLocaleSeq = aDlg.GetLocales();
        m_pLocalizationMgr->handleAddLocales( aLocaleSeq );
        // update listbox
        ClearLanguageBox();
        FillLanguageBox();

        SfxBindings* pBindings = BasicIDE::GetBindingsPtr();
        if ( pBindings )
            pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG );
    }
    return 1;
}

IMPL_LINK( ManageLanguageDialog, DeleteHdl, Button *, EMPTYARG )
{
    QueryBox aQBox( this, IDEResId( RID_QRYBOX_LANGUAGE ) );
    aQBox.SetButtonText( RET_OK, m_sDeleteStr );
    if ( aQBox.Execute() == RET_OK )
    {
        USHORT i, nCount = m_aLanguageLB.GetSelectEntryCount();
        USHORT nPos = m_aLanguageLB.GetSelectEntryPos();
        // remove locales
        Sequence< Locale > aLocaleSeq( nCount );
        for ( i = 0; i < nCount; ++i )
        {
            USHORT nSelPos = m_aLanguageLB.GetSelectEntryPos(i);
            LanguageEntry* pEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData( nSelPos ) );
            if ( pEntry )
                aLocaleSeq[i] = pEntry->m_aLocale;
        }
        m_pLocalizationMgr->handleRemoveLocales( aLocaleSeq );
        // update listbox
        ClearLanguageBox();
        FillLanguageBox();
        // reset selection
        nCount = m_aLanguageLB.GetEntryCount();
        if ( nCount <= nPos )
            nPos = nCount - 1;
        m_aLanguageLB.SelectEntryPos( nPos );
        SelectHdl( NULL );
    }
    return 1;
}

IMPL_LINK( ManageLanguageDialog, MakeDefHdl, Button *, EMPTYARG )
{
    USHORT nPos = m_aLanguageLB.GetSelectEntryPos();
    LanguageEntry* pSelectEntry = (LanguageEntry*)( m_aLanguageLB.GetEntryData( nPos ) );
    if ( pSelectEntry && !pSelectEntry->m_bIsDefault )
    {
        // set new default entry
        m_pLocalizationMgr->handleSetDefaultLocale( pSelectEntry->m_aLocale );
        // update Listbox
        ClearLanguageBox();
        FillLanguageBox();
        // reset selection
        m_aLanguageLB.SelectEntryPos( nPos );
        SelectHdl( NULL );
    }

    return 1;
}

IMPL_LINK( ManageLanguageDialog, SelectHdl, ListBox *, EMPTYARG )
{
    USHORT nCount = m_aLanguageLB.GetEntryCount();
    bool bEmpty = ( !nCount ||
                    m_aLanguageLB.GetEntryPos( m_sCreateLangStr ) != LISTBOX_ENTRY_NOTFOUND );
    bool bSelect = ( m_aLanguageLB.GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND );
    bool bEnable = ( !bEmpty && bSelect != false );

    m_aDeletePB.Enable( bEnable != false );
    m_aMakeDefPB.Enable( bEnable != false && nCount > 1 && m_aLanguageLB.GetSelectEntryCount() == 1 );

    return 1;
}

// class SetDefaultLanguageDialog -----------------------------------------------

SetDefaultLanguageDialog::SetDefaultLanguageDialog( Window* pParent, LocalizationMgr* _pLMgr ) :

    ModalDialog( pParent, IDEResId( RID_DLG_SETDEF_LANGUAGE ) ),

    m_aLanguageFT   ( this, ResId( FT_DEF_LANGUAGE ) ),
    m_aLanguageLB   ( this, ResId( LB_DEF_LANGUAGE ) ),
    m_aCheckLangLB  ( this, ResId( LB_ADD_LANGUAGE ) ),
    m_aInfoFT       ( this, ResId( FT_DEF_INFO ) ),
    m_aBtnLine      ( this, ResId( FL_DEF_BUTTONS ) ),
    m_aOKBtn        ( this, ResId( PB_DEF_OK ) ),
    m_aCancelBtn    ( this, ResId( PB_DEF_CANCEL ) ),
    m_aHelpBtn      ( this, ResId( PB_DEF_HELP ) ),

    m_pLocalizationMgr( _pLMgr )

{
    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        // change to "Add Interface Language" mode
        SetHelpId( HID_BASICIDE_ADDNEW_LANGUAGE );
        m_aLanguageLB.Hide();
        m_aCheckLangLB.Show();
        SetText( String( ResId( STR_ADDLANG_TITLE ) ) );
        m_aLanguageFT.SetText( String( ResId( STR_ADDLANG_LABEL ) ) );
        m_aInfoFT.SetText( String( ResId( STR_ADDLANG_INFO ) ) );
    }
    else
    {
        m_aCheckLangLB.Hide();
        m_aLanguageLB.Show();
    }

    FreeResource();
    FillLanguageBox();
}

SetDefaultLanguageDialog::~SetDefaultLanguageDialog()
{
}

void SetDefaultLanguageDialog::FillLanguageBox()
{
    // fill list with all languages
    m_aLanguageLB.SetLanguageList( LANG_LIST_ALL, FALSE );
    // remove the already localized languages
    Sequence< Locale > aLocaleSeq = m_pLocalizationMgr->getStringResourceManager()->getLocales();
    const Locale* pLocale = aLocaleSeq.getConstArray();
    INT32 i, nCount = aLocaleSeq.getLength();
    for ( i = 0;  i < nCount;  ++i )
        m_aLanguageLB.RemoveLanguage( SvxLocaleToLanguage( pLocale[i] ) );

    // fill checklistbox if not in default mode
    if ( m_pLocalizationMgr->isLibraryLocalized() )
    {
        USHORT j, nCount_ = m_aLanguageLB.GetEntryCount();
        for ( j = 0;  j < nCount_;  ++j )
            m_aCheckLangLB.InsertEntry( m_aLanguageLB.GetEntry(j) );
    }
    else
        // preselect current UI language
        m_aLanguageLB.SelectLanguage( Application::GetSettings().GetUILanguage() );
}

Sequence< Locale > SetDefaultLanguageDialog::GetLocales() const
{
    bool bNotLocalized = !m_pLocalizationMgr->isLibraryLocalized();
    INT32 nSize = bNotLocalized ? 1 : m_aCheckLangLB.GetCheckedEntryCount();
    Sequence< Locale > aLocaleSeq( nSize );
    if ( bNotLocalized )
    {
        Locale aLocale;
        SvxLanguageToLocale( aLocale, m_aLanguageLB.GetSelectLanguage() );
        aLocaleSeq[0] = aLocale;
    }
    else
    {
        USHORT i, nCount = static_cast< USHORT >( m_aCheckLangLB.GetEntryCount() );
        INT32 j = 0;
        for ( i = 0; i < nCount; ++i )
        {
            if ( m_aCheckLangLB.IsChecked(i) )
            {
                LanguageType eType = LanguageType( (ULONG)m_aLanguageLB.GetEntryData(i) );
                Locale aLocale;
                SvxLanguageToLocale( aLocale, eType );
                aLocaleSeq[j++] = aLocale;
            }
        }
        DBG_ASSERT( nSize == j, "SetDefaultLanguageDialog::GetLocales(): invalid indexes" );
    }
    return aLocaleSeq;
}

<|endoftext|>


<commit_before>#include "driver.hpp"
#include "scanner.hpp"
#include "parser.hpp"
#include "ast.hpp"
#include "codegen.hpp"

#include <sstream>
#include <vector>
#include <cstdlib>
#include <getopt.h>
#include <fstream>
#include <functional>
#include <boost/filesystem.hpp>

using namespace std;
using boost::filesystem::path;

lisplike_driver::lisplike_driver()
    : trace_scanning(false)
    , trace_parsing(false) { }

lisplike_driver::~lisplike_driver()
    { }

bool lisplike_driver::parse_stream(istream& in, const string& sname, std::ostream& out)
{
    streamname = sname;
    lisplike_scanner scanner(&in);
    scanner.set_debug(trace_scanning);
    lexer = &scanner;
    yy::lisplike_parser parser(*this);
    parser.set_debug_level(trace_parsing);
    return parser.parse() == 0;
}

bool lisplike_driver::parse_string(const string& line, const string& sname, std::ostream& out)
{
    istringstream iss(line);
    return parse_stream(iss, sname);
}

bool lisplike_driver::parse_file(const string& filename, std::ostream& out)
{
    ifstream in(filename);
    if(!in.good()) return false;
    return parse_stream(in, filename);
}

void lisplike_driver::error (const yy::location& l, const string& m)
{
    cerr << l << ": " << m << endl;
}

void lisplike_driver::error (const string& m)
{
    cerr << m << endl;
}

static vector<string> filenames;
static path outdir = ".";
static bool outfile = false;
static bool genheader = false;
static bool genmain = false;

static void print_usage(int argc, char **argv)
{
    cout << "usage: " << argv[0] << " [opts] [input1 [input2 input3 ...]]" << endl;
    cout << "opts:" << endl <<
"-p --trace-parsing         traces the Bison parse of the input" << endl <<
"-s --trace-scanning        traces the Lexx scan of the input" << endl <<
"-o --outfile               generate an output file for every output" << endl <<
"-g --gen-header            generate a header file for every output" << endl <<
"-m --gen-main              generate a main file, containing every top level " << endl <<
"                               function call, in order of the files passed to " << endl <<
"                               the command line." << endl <<
"-d --dir [outdir]          directory to save output file to" << endl;
}

static void parse_args(int argc, char **argv, lisplike_driver &driver)
{
    while(1)
    {
        int optindex;
        static struct option long_options[] = {
            { "trace-parsing",      no_argument,        0,  'p' },
            { "trace-scanning",     no_argument,        0,  's' },
            { "outfile",            no_argument,        0,  'o' },
            { "gen-header",         no_argument,        0,  'g' },
            { "gen-main",           no_argument,        0,  'm' },
            { "dir",                required_argument,  0,  'd' },
            { nullptr,              0,                  0,   0  },
        };

        int c = getopt_long(argc, argv, "sphogmd:", long_options, &optindex);
        if(c == -1)
            break;
        switch(c)
        {
            case 's':
                driver.trace_scanning = true;
                break;
            case 'p':
                driver.trace_parsing = true;
                break;
            case 'o':
                outfile = true;
                break;
            case 'g':
                genheader = true;
                break;
            case 'm':
                genmain = true;
                break;
            case 'd':
                outdir = path(optarg);
                break;
            case '?':
            case 'h':
                print_usage(argc, argv);
                exit(0);
                break;
            default:
                break;
        }
    }

    while(optind < argc)
        filenames.push_back(argv[optind++]);
    for(; optind < argc; optind++)
        cerr << "ignoring input file: " << argv[optind] << endl;
}

static void do_codegen(function<string(const ll_children&)> codegen_fn,
    const ll_children& ast, cstref filename)
{
    path outpath = outdir / (path(filename).filename());
    ofstream out_stream(outpath.string());
    if(!out_stream.good())
    {
        cerr << "could not open " << outpath << endl;
        exit(1);
    }
    out_stream << codegen_fn(ast);
}

int main(int argc, char **argv)
{
    lisplike_driver driver;
    parse_args(argc, argv, driver);

    if(!filenames.empty())
    {
        ll_children ast;
        for(auto filename : filenames)
        {
            if(!driver.parse_file(filename))
            {
                cerr << "ERROR" << endl;
                exit(1);
            }
            else
            {
                ast.insert(ast.end(), driver.ast.begin(), driver.ast.end());
                if(outfile)
                    do_codegen(gen_cpp, driver.ast, filename + ".cpp");
                if(genheader)
                    do_codegen(gen_header, driver.ast, filename + ".hpp");
            }
        }
        if(genmain)
            do_codegen(gen_main, ast, "main.cpp");
        cerr << "OK" << endl;
    }
    else
    {
        string line;
        while(getline(cin, line))
        {
            bool result = driver.parse_string(line, "stdin");
            if(result)
                cout << "OK" << endl;
        }
    }
    return 0;
}
<commit_msg>Make code generation the default behavior, all options now *disable* code generation. Also made the header code generation flag more coherent, favoring the -h over the -g. Help text is now generated from the -?, --help, or incorrect options.<commit_after>#include "driver.hpp"
#include "scanner.hpp"
#include "parser.hpp"
#include "ast.hpp"
#include "codegen.hpp"

#include <sstream>
#include <vector>
#include <cstdlib>
#include <getopt.h>
#include <fstream>
#include <functional>
#include <boost/filesystem.hpp>

using namespace std;
using boost::filesystem::path;

lisplike_driver::lisplike_driver()
    : trace_scanning(false)
    , trace_parsing(false) { }

lisplike_driver::~lisplike_driver()
    { }

bool lisplike_driver::parse_stream(istream& in, const string& sname, std::ostream& out)
{
    streamname = sname;
    lisplike_scanner scanner(&in);
    scanner.set_debug(trace_scanning);
    lexer = &scanner;
    yy::lisplike_parser parser(*this);
    parser.set_debug_level(trace_parsing);
    return parser.parse() == 0;
}

bool lisplike_driver::parse_string(const string& line, const string& sname, std::ostream& out)
{
    istringstream iss(line);
    return parse_stream(iss, sname);
}

bool lisplike_driver::parse_file(const string& filename, std::ostream& out)
{
    ifstream in(filename);
    if(!in.good()) return false;
    return parse_stream(in, filename);
}

void lisplike_driver::error (const yy::location& l, const string& m)
{
    cerr << l << ": " << m << endl;
}

void lisplike_driver::error (const string& m)
{
    cerr << m << endl;
}

static vector<string> filenames;
static path outdir = ".";
static bool outfile = true;
static bool genheader = true;
static bool genmain = true;

static void print_usage(int argc, char **argv)
{
    cout << "usage: " << argv[0] << " [opts] [input1 [input2 input3 ...]]" << endl;
    cout << "opts:" << endl <<
"-p --trace-parsing         traces the Bison parse of the input" << endl <<
"-s --trace-scanning        traces the Lexx scan of the input" << endl <<
"-o --no-outfile            don't generate an output file" << endl <<
"-h --no-header             don't generate a header file" << endl <<
"-m --no-main               don't generate a main file" << endl <<
"-d --dir [outdir]          directory to save output file to" << endl <<
"-? --help                  shows this help message" << endl;
}

static void parse_args(int argc, char **argv, lisplike_driver &driver)
{
    while(1)
    {
        int optindex;
        static struct option long_options[] = {
            { "trace-parsing",      no_argument,        0,  'p' },
            { "trace-scanning",     no_argument,        0,  's' },
            { "outfile",            no_argument,        0,  'o' },
            { "gen-header",         no_argument,        0,  'h' },
            { "gen-main",           no_argument,        0,  'm' },
            { "dir",                required_argument,  0,  'd' },
            { "help",               required_argument,  0,  '?' },
            { nullptr,              0,                  0,   0  },
        };

        int c = getopt_long(argc, argv, "sphogmd:", long_options, &optindex);
        if(c == -1)
            break;
        switch(c)
        {
            case 's':
                driver.trace_scanning = true;
                break;
            case 'p':
                driver.trace_parsing = true;
                break;
            case 'o':
                outfile = false;
                break;
            case 'h':
                genheader = false;
                break;
            case 'm':
                genmain = false;
                break;
            case 'd':
                outdir = path(optarg);
                break;
            case '?':
                print_usage(argc, argv);
                exit(0);
                break;
            default:
                break;
        }
    }

    while(optind < argc)
        filenames.push_back(argv[optind++]);
    for(; optind < argc; optind++)
        cerr << "ignoring input file: " << argv[optind] << endl;
}

static int do_codegen(function<string(const ll_children&)> codegen_fn,
    const ll_children& ast, cstref filename)
{
    path outpath = outdir / (path(filename).filename());
    ofstream out_stream(outpath.string());
    if(!out_stream.good())
    {
        cerr << "could not open " << outpath << endl;
        return 1;
    }
    out_stream << codegen_fn(ast);
    return 0;
}

int main(int argc, char **argv)
{
    int mainresult = 0;
    lisplike_driver driver;
    parse_args(argc, argv, driver);

    if(!filenames.empty())
    {
        ll_children ast;
        for(auto filename : filenames)
        {
            if(!driver.parse_file(filename))
            {
                cerr << "error in " << filename << endl;
                exit(1);
            }
            else
            {
                ast.insert(ast.end(), driver.ast.begin(), driver.ast.end());
                if(outfile)
                    mainresult |= do_codegen(gen_cpp, driver.ast, filename + ".cpp");
                if(genheader)
                    mainresult |= do_codegen(gen_header, driver.ast, filename + ".hpp");
            }
        }
        if(genmain)
            mainresult |= do_codegen(gen_main, ast, "main.cpp");

        if(mainresult == 0)
            cerr << "OK" << endl;
    }
    else
    {
        string line;
        while(getline(cin, line))
        {
            bool result = driver.parse_string(line, "stdin");
            if(result)
                cout << "OK" << endl;
        }
    }
    return mainresult;
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file esc_calibration.cpp
 *
 * Definition of esc calibration
 *
 * @author Roman Bapst <bapstr@ethz.ch>
 */

#include "esc_calibration.h"
#include "calibration_messages.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <systemlib/err.h>
#include <fcntl.h>
#include <px4_posix.h>
#include <px4_time.h>
#include "drivers/drv_pwm_output.h"
#include <uORB/topics/battery_status.h>
#include <uORB/topics/vehicle_command.h>
#include <uORB/uORB.h>
#include <drivers/drv_hrt.h>
#include <mavlink/mavlink_log.h>

/* oddly, ERROR is not defined for c++ */
#ifdef ERROR
# undef ERROR
#endif
static const int ERROR = -1;

int do_esc_calibration(int mavlink_fd, struct actuator_armed_s* armed)
{
	int	return_code = OK;
	int	fd = -1;
	struct	battery_status_s battery;
	int	batt_sub = -1;
	bool	batt_updated = false;
	bool	batt_connected = false;
	hrt_abstime start_time;

	mavlink_and_console_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, "esc");

	batt_sub = orb_subscribe(ORB_ID(battery_status));
	if (batt_sub < 0) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Subscribe to battery");
		goto Error;
	}

	// Make sure battery is disconnected
	orb_copy(ORB_ID(battery_status), batt_sub, &battery);
	if (battery.voltage_filtered_v > 3.0f) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Disconnect battery and try again");
		goto Error;
	}

	armed->in_esc_calibration_mode = true;

	fd = px4_open(PWM_OUTPUT0_DEVICE_PATH, 0);

	if (fd < 0) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Can't open PWM device");
		goto Error;
	}

	/* tell IO/FMU that its ok to disable its safety with the switch */
	if (px4_ioctl(fd, PWM_SERVO_SET_ARM_OK, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to disable safety switch");
		goto Error;
	}

	/* tell IO/FMU that the system is armed (it will output values if safety is off) */
	if (px4_ioctl(fd, PWM_SERVO_ARM, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to arm system");
		goto Error;
	}

	/* tell IO to switch off safety without using the safety switch */
	if (px4_ioctl(fd, PWM_SERVO_SET_FORCE_SAFETY_OFF, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to force safety off");
		goto Error;
	}

	mavlink_and_console_log_info(mavlink_fd, "[cal] Connect battery now");

	start_time = hrt_absolute_time();

	while (true) {
		if (hrt_absolute_time() - start_time > 5000000) {
			if (!batt_connected) {
				mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Timeout waiting for battery");
				goto Error;
			}

			// 5 seconds at high pwm
			break;
		}

		if (!batt_connected) {
			orb_check(batt_sub, &batt_updated);
			if (batt_updated) {
				orb_copy(ORB_ID(battery_status), batt_sub, &battery);
				if (battery.voltage_filtered_v > 3.0f) {
					// Battery connected, wait for 5 seconds at high pwm
					batt_connected = true;
					start_time = hrt_absolute_time();
					mavlink_and_console_log_info(mavlink_fd, "[cal] Battery connected");
				}
			}
		}
		usleep(50000);
	}

Out:
	if (batt_sub != -1) {
		orb_unsubscribe(batt_sub);
	}
	if (fd != -1) {
		if (px4_ioctl(fd, PWM_SERVO_SET_FORCE_SAFETY_ON, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Safety switch still off");
		}
		if (px4_ioctl(fd, PWM_SERVO_DISARM, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Servos still armed");
		}
		if (px4_ioctl(fd, PWM_SERVO_CLEAR_ARM_OK, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Safety switch still deactivated");
		}
		px4_close(fd);
	}
	armed->in_esc_calibration_mode = false;

	if (return_code == OK) {
		mavlink_and_console_log_info(mavlink_fd, CAL_QGC_DONE_MSG, "esc");
	}

	return return_code;

Error:
	return_code = ERROR;
	goto Out;
}
<commit_msg>Separate timeouts for battery and high pwm<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file esc_calibration.cpp
 *
 * Definition of esc calibration
 *
 * @author Roman Bapst <bapstr@ethz.ch>
 */

#include "esc_calibration.h"
#include "calibration_messages.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <systemlib/err.h>
#include <fcntl.h>
#include <px4_posix.h>
#include <px4_time.h>
#include "drivers/drv_pwm_output.h"
#include <uORB/topics/battery_status.h>
#include <uORB/topics/vehicle_command.h>
#include <uORB/uORB.h>
#include <drivers/drv_hrt.h>
#include <mavlink/mavlink_log.h>

/* oddly, ERROR is not defined for c++ */
#ifdef ERROR
# undef ERROR
#endif
static const int ERROR = -1;

int do_esc_calibration(int mavlink_fd, struct actuator_armed_s* armed)
{
	int	return_code = OK;

	int	fd = -1;

	struct	battery_status_s battery;
	int	batt_sub = -1;
	bool	batt_updated = false;
	bool	batt_connected = false;

	hrt_abstime battery_connect_wait_timeout = 20000000;
	hrt_abstime pwm_high_timeout = 5000000;
	hrt_abstime timeout_start;

	mavlink_and_console_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, "esc");

	batt_sub = orb_subscribe(ORB_ID(battery_status));
	if (batt_sub < 0) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Subscribe to battery");
		goto Error;
	}

	// Make sure battery is disconnected
	orb_copy(ORB_ID(battery_status), batt_sub, &battery);
	if (battery.voltage_filtered_v > 3.0f) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Disconnect battery and try again");
		goto Error;
	}

	armed->in_esc_calibration_mode = true;

	fd = px4_open(PWM_OUTPUT0_DEVICE_PATH, 0);

	if (fd < 0) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Can't open PWM device");
		goto Error;
	}

	/* tell IO/FMU that its ok to disable its safety with the switch */
	if (px4_ioctl(fd, PWM_SERVO_SET_ARM_OK, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to disable safety switch");
		goto Error;
	}

	/* tell IO/FMU that the system is armed (it will output values if safety is off) */
	if (px4_ioctl(fd, PWM_SERVO_ARM, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to arm system");
		goto Error;
	}

	/* tell IO to switch off safety without using the safety switch */
	if (px4_ioctl(fd, PWM_SERVO_SET_FORCE_SAFETY_OFF, 0) != OK) {
		mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Unable to force safety off");
		goto Error;
	}

	mavlink_and_console_log_info(mavlink_fd, "[cal] Connect battery now");

	timeout_start = hrt_absolute_time();

	while (true) {
		// We are either waiting for the user to connect the battery. Or we are waiting to let the PWM
		// sit high.
		hrt_abstime timeout_wait = batt_connected ? pwm_high_timeout : battery_connect_wait_timeout;

		if (hrt_absolute_time() - timeout_start > timeout_wait) {
			if (!batt_connected) {
				mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, "Timeout waiting for battery");
				goto Error;
			}

			// PWM was high long enough
			break;
		}

		if (!batt_connected) {
			orb_check(batt_sub, &batt_updated);
			if (batt_updated) {
				orb_copy(ORB_ID(battery_status), batt_sub, &battery);
				if (battery.voltage_filtered_v > 3.0f) {
					// Battery is connected, signal to user and start waiting again
					batt_connected = true;
					timeout_start = hrt_absolute_time();
					mavlink_and_console_log_info(mavlink_fd, "[cal] Battery connected");
				}
			}
		}
		usleep(50000);
	}

Out:
	if (batt_sub != -1) {
		orb_unsubscribe(batt_sub);
	}
	if (fd != -1) {
		if (px4_ioctl(fd, PWM_SERVO_SET_FORCE_SAFETY_ON, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Safety switch still off");
		}
		if (px4_ioctl(fd, PWM_SERVO_DISARM, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Servos still armed");
		}
		if (px4_ioctl(fd, PWM_SERVO_CLEAR_ARM_OK, 0) != OK) {
			mavlink_and_console_log_info(mavlink_fd, CAL_QGC_WARNING_MSG, "Safety switch still deactivated");
		}
		px4_close(fd);
	}
	armed->in_esc_calibration_mode = false;

	if (return_code == OK) {
		mavlink_and_console_log_info(mavlink_fd, CAL_QGC_DONE_MSG, "esc");
	}

	return return_code;

Error:
	return_code = ERROR;
	goto Out;
}
<|endoftext|>


<commit_before><commit_msg>fdo#75757: remove inheritance to std::vector<commit_after><|endoftext|>


<commit_before>#include "sdl2ffbperiodiceffect.h"
#include "globalsettings.h"
#include <QtWidgets/QMessageBox>

SDL2FFBPeriodicEffect::SDL2FFBPeriodicEffect() :
  SDL2FFBEffect(FFBEffectTypes::PERIODIC)
{}

SDL_HapticEffect* SDL2FFBPeriodicEffect::createFFstruct()
{
  SDL_HapticEffect* effect = SDL2FFBEffect::createFFstruct();

  if (effect == nullptr)
    return nullptr;

  switch (m_params->waveform) {
    case PeriodicWaveforms::SINE:
      effect->type = SDL_HAPTIC_SINE;
      break;
    case PeriodicWaveforms::TRIANGLE:
      effect->type = SDL_HAPTIC_TRIANGLE;
      break;
    case PeriodicWaveforms::SAW_UP:
      effect->type = SDL_HAPTIC_SAWTOOTHUP;
      break;
    case PeriodicWaveforms::SAW_DOWN:
      effect->type = SDL_HAPTIC_SAWTOOTHDOWN;
    default:
      delete effect;
      return nullptr;
  }

  effect->periodic.direction.type = SDL_HAPTIC_POLAR;
  effect->periodic.direction.dir[0] = m_params->direction;

  if (m_params->replayLength == 0)
    effect->periodic.length = SDL_HAPTIC_INFINITY;
  else
    effect->periodic.length = m_params->replayLength;

  effect->periodic.delay = m_params->replayDelay;

  effect->periodic.period = m_params->period;
  effect->periodic.magnitude = m_params->magnitude;
  effect->periodic.offset = m_params->offset;
  effect->periodic.phase = m_params->phase;

  return effect;
}

bool SDL2FFBPeriodicEffect::setParameters(const std::shared_ptr<FFBEffectParameters> params)
{
  try {
    const std::shared_ptr<FFBPeriodicEffectParameters> iParams = std::dynamic_pointer_cast<FFBPeriodicEffectParameters>(params);
    return setParameters(iParams);
  } catch (std::bad_cast& ) {
    return false;
  }
}

bool SDL2FFBPeriodicEffect::setParameters(const std::shared_ptr<FFBPeriodicEffectParameters> params)
{
  if (!GlobalSettings::GS()->doSanityChecks)
    return true;

  if (!checkGenericParameters(params))
    return false;

  if (!checkEnvelopeParameters(params->attackLength, params->attackLevel, params->fadeLength, params->fadeLevel))
    return false;

  if (!checkBoundsInclusive(params->period, 0, 36000)) {
    QMessageBox::warning(nullptr, CAPTION, "Period must be within <0; 36000>");
    return false;
  }

  if (!checkBoundsInclusive(params->magnitude, -0x7FFF, 0x7FFF)) {
    QMessageBox::warning(nullptr, CAPTION, "Magnitude must be within <-32767; 32767>");
    return false;
  }

  if (!checkBoundsInclusive(params->offset, -0x7FFF, 0x7FFF)) {
    QMessageBox::warning(nullptr, CAPTION, "Offset must be within <-32767; 32767>");
    return false;
  }

  if (!checkBoundsInclusive(params->phase, 0, 36000)) {
    QMessageBox::warning(nullptr, CAPTION, "Phase must be withing <0; 36000>");
    return false;
  }

  if (params->waveform == PeriodicWaveforms::NONE ||
      params->waveform == PeriodicWaveforms::SQUARE) {
    QMessageBox::warning(nullptr, CAPTION, "Unsupported waveform");
    return false;
  }

  m_params = params;
  return true;
}

<commit_msg>Support envelope in SDL2's periodic effect<commit_after>#include "sdl2ffbperiodiceffect.h"
#include "globalsettings.h"
#include <QtWidgets/QMessageBox>

SDL2FFBPeriodicEffect::SDL2FFBPeriodicEffect() :
  SDL2FFBEffect(FFBEffectTypes::PERIODIC)
{}

SDL_HapticEffect* SDL2FFBPeriodicEffect::createFFstruct()
{
  SDL_HapticEffect* effect = SDL2FFBEffect::createFFstruct();

  if (effect == nullptr)
    return nullptr;

  switch (m_params->waveform) {
    case PeriodicWaveforms::SINE:
      effect->type = SDL_HAPTIC_SINE;
      break;
    case PeriodicWaveforms::TRIANGLE:
      effect->type = SDL_HAPTIC_TRIANGLE;
      break;
    case PeriodicWaveforms::SAW_UP:
      effect->type = SDL_HAPTIC_SAWTOOTHUP;
      break;
    case PeriodicWaveforms::SAW_DOWN:
      effect->type = SDL_HAPTIC_SAWTOOTHDOWN;
    default:
      delete effect;
      return nullptr;
  }

  effect->periodic.direction.type = SDL_HAPTIC_POLAR;
  effect->periodic.direction.dir[0] = m_params->direction;

  if (m_params->replayLength == 0)
    effect->periodic.length = SDL_HAPTIC_INFINITY;
  else
    effect->periodic.length = m_params->replayLength;

  effect->periodic.delay = m_params->replayDelay;

  effect->periodic.attack_length = m_params->attackLength;
  effect->periodic.attack_level = m_params->attackLevel;
  effect->periodic.fade_length = m_params->fadeLength;
  effect->periodic.fade_level = m_params->fadeLevel;

  effect->periodic.period = m_params->period;
  effect->periodic.magnitude = m_params->magnitude;
  effect->periodic.offset = m_params->offset;
  effect->periodic.phase = m_params->phase;

  return effect;
}

bool SDL2FFBPeriodicEffect::setParameters(const std::shared_ptr<FFBEffectParameters> params)
{
  try {
    const std::shared_ptr<FFBPeriodicEffectParameters> iParams = std::dynamic_pointer_cast<FFBPeriodicEffectParameters>(params);
    return setParameters(iParams);
  } catch (std::bad_cast& ) {
    return false;
  }
}

bool SDL2FFBPeriodicEffect::setParameters(const std::shared_ptr<FFBPeriodicEffectParameters> params)
{
  if (!GlobalSettings::GS()->doSanityChecks)
    return true;

  if (!checkGenericParameters(params))
    return false;

  if (!checkEnvelopeParameters(params->attackLength, params->attackLevel, params->fadeLength, params->fadeLevel))
    return false;

  if (!checkBoundsInclusive(params->period, 0, 36000)) {
    QMessageBox::warning(nullptr, CAPTION, "Period must be within <0; 36000>");
    return false;
  }

  if (!checkBoundsInclusive(params->magnitude, -0x7FFF, 0x7FFF)) {
    QMessageBox::warning(nullptr, CAPTION, "Magnitude must be within <-32767; 32767>");
    return false;
  }

  if (!checkBoundsInclusive(params->offset, -0x7FFF, 0x7FFF)) {
    QMessageBox::warning(nullptr, CAPTION, "Offset must be within <-32767; 32767>");
    return false;
  }

  if (!checkBoundsInclusive(params->phase, 0, 36000)) {
    QMessageBox::warning(nullptr, CAPTION, "Phase must be withing <0; 36000>");
    return false;
  }

  if (params->waveform == PeriodicWaveforms::NONE ||
      params->waveform == PeriodicWaveforms::SQUARE) {
    QMessageBox::warning(nullptr, CAPTION, "Unsupported waveform");
    return false;
  }

  m_params = params;
  return true;
}

<|endoftext|>


<commit_before>/**
 *  Copyright 2014-2015 MongoDB, Inc.
 *
 *  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 "hphp/runtime/ext/extension.h"
#include "hphp/runtime/vm/native-data.h"
#include "hphp/runtime/base/array-iterator.h"
#include "hphp/runtime/ext/stream/ext_stream.h"
#include "hphp/runtime/base/variable-serializer.h"

#include "mongodb.h"
#include "pool.h"

extern "C" {
#include "../../../libmongoc/src/mongoc/mongoc-client.h"
}

namespace {
	thread_local std::unordered_map<std::string, std::shared_ptr<HPHP::Pool>> s_connections;
}

namespace HPHP {

std::string Pool::CreateHash(const mongoc_uri_t *uri, const Array &options, const Array &driverOptions)
{
	std::string hash;
	StringBuffer buf;

	VariableSerializer vs(VariableSerializer::Type::Serialize);

	buf.append(mongoc_uri_get_string(uri));

	if (options.size() > 0) {
		buf.append("#");
		buf.append(vs.serialize(Variant(options), true, true));
	}

	if (driverOptions.size() > 0) {
		buf.append("#");
	}
	for (ArrayIter iter(driverOptions); iter; ++iter) {
		Variant key(iter.first());
		String s_key = key.toString();
		Variant value(iter.second());

		if (strcmp(s_key.c_str(), "context") == 0 && value.isResource()) {
			Array context;
			buf.append("context:");
#if HIPPO_HHVM_VERSION >= 30900
			req::ptr<StreamContext> sc;
#else
			SmartPtr<StreamContext> sc;
#endif
			sc = cast<StreamContext>(value);

			if (!sc) {
				continue;
			}

			context = sc->getOptions();
			buf.append(vs.serialize(context, true, true));
		} else {
			buf.append(s_key);
			buf.append(":");

			buf.append(vs.serialize(value, true, true));
		}
	}

	String tmp = buf.detach();

	return tmp.c_str();
}

mongoc_client_t *Pool::GetClient(std::string hash, mongoc_uri_t *uri)
{
	auto key = hash;
	std::shared_ptr<Pool> tmp;

	tmp = s_connections[key];
	if (!tmp) {
		Logger::Verbose("[HIPPO] Client Caching; New Client; Hash: %s", hash.c_str());
		std::shared_ptr<Pool> new_client_ptr(new Pool(uri));
		s_connections[key] = new_client_ptr;
		return new_client_ptr->m_client;
	} else {
		Logger::Verbose("[HIPPO] Client Caching; Existing Client; Hash: %s", hash.c_str());
		return tmp->m_client;
	}
}

void Pool::ReturnClient(const std::string hash, mongoc_client_t *client)
{
	auto key = hash;
	std::shared_ptr<Pool> tmp;

	tmp = s_connections[key];
	if (!tmp) {
		Logger::Warning("[HIPPO] Client Caching; Gone From Map; Hash: %s", hash.c_str());
	} else {
		/* We don't really need to do anything. The anti-case is just to make
		 * sure that things weren't broken. */
	}
}

}
<commit_msg>HHVM-214: Fix compile issue with HHVM 3.15<commit_after>/**
 *  Copyright 2014-2015 MongoDB, Inc.
 *
 *  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 "hphp/runtime/ext/extension.h"
#include "hphp/runtime/vm/native-data.h"
#include "hphp/runtime/base/array-iterator.h"
#include "hphp/runtime/ext/stream/ext_stream.h"
#include "hphp/runtime/base/variable-serializer.h"
#include "hphp/util/logger.h"

#include "mongodb.h"
#include "pool.h"

extern "C" {
#include "../../../libmongoc/src/mongoc/mongoc-client.h"
}

namespace {
	thread_local std::unordered_map<std::string, std::shared_ptr<HPHP::Pool>> s_connections;
}

namespace HPHP {

std::string Pool::CreateHash(const mongoc_uri_t *uri, const Array &options, const Array &driverOptions)
{
	std::string hash;
	StringBuffer buf;

	VariableSerializer vs(VariableSerializer::Type::Serialize);

	buf.append(mongoc_uri_get_string(uri));

	if (options.size() > 0) {
		buf.append("#");
		buf.append(vs.serialize(Variant(options), true, true));
	}

	if (driverOptions.size() > 0) {
		buf.append("#");
	}
	for (ArrayIter iter(driverOptions); iter; ++iter) {
		Variant key(iter.first());
		String s_key = key.toString();
		Variant value(iter.second());

		if (strcmp(s_key.c_str(), "context") == 0 && value.isResource()) {
			Array context;
			buf.append("context:");
#if HIPPO_HHVM_VERSION >= 30900
			req::ptr<StreamContext> sc;
#else
			SmartPtr<StreamContext> sc;
#endif
			sc = cast<StreamContext>(value);

			if (!sc) {
				continue;
			}

			context = sc->getOptions();
			buf.append(vs.serialize(context, true, true));
		} else {
			buf.append(s_key);
			buf.append(":");

			buf.append(vs.serialize(value, true, true));
		}
	}

	String tmp = buf.detach();

	return tmp.c_str();
}

mongoc_client_t *Pool::GetClient(std::string hash, mongoc_uri_t *uri)
{
	auto key = hash;
	std::shared_ptr<Pool> tmp;

	tmp = s_connections[key];
	if (!tmp) {
		Logger::Verbose("[HIPPO] Client Caching; New Client; Hash: %s", hash.c_str());
		std::shared_ptr<Pool> new_client_ptr(new Pool(uri));
		s_connections[key] = new_client_ptr;
		return new_client_ptr->m_client;
	} else {
		Logger::Verbose("[HIPPO] Client Caching; Existing Client; Hash: %s", hash.c_str());
		return tmp->m_client;
	}
}

void Pool::ReturnClient(const std::string hash, mongoc_client_t *client)
{
	auto key = hash;
	std::shared_ptr<Pool> tmp;

	tmp = s_connections[key];
	if (!tmp) {
		Logger::Warning("[HIPPO] Client Caching; Gone From Map; Hash: %s", hash.c_str());
	} else {
		/* We don't really need to do anything. The anti-case is just to make
		 * sure that things weren't broken. */
	}
}

}
<|endoftext|>