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

//------------------------------------------------------------------------------
// Qt includes
//------------------------------------------------------------------------------

#include <QTime>
#include <QtQml>
#include <QScreen>
#include <iostream>
#include <QApplication>
#include <QJoysticks.h>
#include <QDesktopServices>
#include <QQmlApplicationEngine>

//------------------------------------------------------------------------------
// Library includes
//------------------------------------------------------------------------------

#include <stdio.h>
#include <DriverStation.h>
#include <QSimpleUpdater.h>

//------------------------------------------------------------------------------
// Application includes
//------------------------------------------------------------------------------

#include "beeper.h"
#include "versions.h"
#include "shortcuts.h"
#include "utilities.h"
#include "dashboards.h"

//------------------------------------------------------------------------------
// Fix compilation issues in Windows
//------------------------------------------------------------------------------

#ifdef Q_OS_WIN
#ifdef main
#undef main
#endif
#endif

//------------------------------------------------------------------------------
// Mac-specific initialization code
//------------------------------------------------------------------------------

#ifdef Q_OS_MAC
#include <QObject>
#include <QSettings>
#include <QMessageBox>
#include <QDesktopServices>
#endif

//------------------------------------------------------------------------------
// CLI messages
//------------------------------------------------------------------------------

const QString LOGS = "We instructed your file manager to navigate to:       \n"
                     "    %1                                                \n"
                     "If nothing happens, please navigate to that directory   ";

const QString WEBS = "We instructed your web browser to navigate to:        \n"
                     "    %1                                                \n"
                     "If nothing happens, please navigate to that URL         ";

const QString HELP = "Usage: qdriverstation [ options ... ]                 \n"
                     "                                                      \n"
                     "Options include:                                      \n"
                     "    -b, --bug       Report a bug                      \n"
                     "    -h, --help      Show this message                 \n"
                     "    -l, --logs      Open the logs directory           \n"
                     "    -r, --reset     Reset/clear the settings          \n"
                     "    -c, --contact   Contact the lead developer        \n"
                     "    -v, --version   Display the application version   \n"
                     "    -w, --website   Open a web site of this project   \n";

//------------------------------------------------------------------------------
// Website, contact info & other URLs
//------------------------------------------------------------------------------

// *INDENT-OFF*
const QString LOGS_DIR = DS_LOGGER_PATH();
const QString CONT_URL = "alex_spataru@outlook.com";
const QString HTTP_URL = "http://qdriverstation.sf.net";
const QString BUGS_URL = "http://github.com/FRC-Utilities/QDriverStation/issues";
// *INDENT-ON*

//------------------------------------------------------------------------------
// Download joystick drivers if needed
//------------------------------------------------------------------------------

static void DownloadXboxDrivers() {
#ifdef Q_OS_MAC
    QSettings settings (APP_COMPANY, APP_DSPNAME);

    if (settings.value ("FirstLaunch", true).toBool()) {
        QMessageBox box;
        box.setIcon (QMessageBox::Question);
        box.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
        box.setDefaultButton (QMessageBox::Yes);

        box.setWindowTitle (QObject::tr ("Download Joystick Drivers"));

        box.setText (QObject::tr (
                         "Do you want to install a driver "
                         "for Xbox joysticks?"));

        box.setInformativeText (QObject::tr (
                                    "Clicking \"Yes\" will open a web "
                                    "browser to download the drivers"));

        settings.setValue ("FirstLaunch", false);

        if (box.exec() == QMessageBox::Yes)
            QDesktopServices::openUrl (QUrl (
                                           "https://github.com/360Controller/"
                                           "360Controller/releases/latest"));
    }
#endif
}

//------------------------------------------------------------------------------
// Utility functions
//------------------------------------------------------------------------------

static void showHelp() {
    qDebug() << HELP.toStdString().c_str();
}

static void resetSettings() {
    QSettings (APP_COMPANY, APP_DSPNAME).clear();
    qDebug() << "QDriverStation settings cleared!";
}

static void contact() {
    QString url = "mailto:" + CONT_URL;
    QDesktopServices::openUrl (QUrl (url));
    qDebug() << WEBS.arg (CONT_URL).toStdString().c_str();
}

static void reportBug() {
    QDesktopServices::openUrl (QUrl (BUGS_URL));
    qDebug() << WEBS.arg (BUGS_URL).toStdString().c_str();
}

static void openLogsDir() {
    qDebug() << LOGS.arg (LOGS_DIR).toStdString().c_str();
    QDesktopServices::openUrl (QUrl::fromLocalFile (LOGS_DIR));
}

static void openWebsite() {
    QDesktopServices::openUrl (QUrl (HTTP_URL));
    qDebug() << WEBS.arg (HTTP_URL).toStdString().c_str();
}

static void showVersion() {
    QString appver = APP_DSPNAME + " version " + APP_VERSION;
    QString author = "Written by Alex Spataru <" + CONT_URL + ">";

    qDebug() << appver.toStdString().c_str();
    qDebug() << author.toStdString().c_str();
}

//------------------------------------------------------------------------------
// Application init
//------------------------------------------------------------------------------

int main (int argc, char* argv[]) {
    /* Fix scalling issues */
#if QT_VERSION >= QT_VERSION_CHECK (5, 6, 0)
#if defined Q_OS_MAC
    QApplication::setAttribute (Qt::AA_EnableHighDpiScaling);
#else
    QApplication::setAttribute (Qt::AA_DisableHighDpiScaling);
#endif
#endif

    /* Initialize application */
    QString arguments;
    QApplication app (argc, argv);

    /* Read command line arguments */
    if (app.arguments().count() >= 2)
        arguments = app.arguments().at (1);

    /* We have some arguments, read them */
    if (!arguments.isEmpty() && arguments.startsWith ("-")) {
        if (arguments == "-b" || arguments == "--bug")
            reportBug();

        else if (arguments == "-l" || arguments == "--logs")
            openLogsDir();

        else if (arguments == "-r" || arguments == "--reset")
            resetSettings();

        else if (arguments == "-c" || arguments == "--contact")
            contact();

        else if (arguments == "-v" || arguments == "--version")
            showVersion();

        else if (arguments == "-w" || arguments == "--website")
            openWebsite();

        else
            showHelp();

        return EXIT_SUCCESS;
    }

    /* Start the init. time counter */
    QTime* pElapsedTime = new QTime;
    pElapsedTime->start();

    /* Register application info and install logger */
    app.setApplicationName    (APP_DSPNAME);
    app.setOrganizationName   (APP_COMPANY);
    app.setApplicationVersion (APP_VERSION);
    app.setOrganizationDomain (APP_WEBSITE);
    qInstallMessageHandler    (DS_MESSAGE_HANDLER);

    /* Initialize OS variables */
    bool isMac = false;
    bool isUnx = false;
    bool isWin = false;

    /* Let QML know the operating system */
#if defined Q_OS_MAC
    isMac = true;
#elif defined Q_OS_WIN
    isWin = true;
#else
    isUnx = true;
#endif

    /* Calculate the scale factor of the screen */
    qreal ratio = (app.primaryScreen()->physicalDotsPerInch() / 100) * 0.9;

    /* Scale factor is too small or OS is Mac */
    if (ratio < 1.2 || isMac)
        ratio = 1;

    /* Report the scale factor */
    qDebug() << "Scale factor set to:" << ratio;

    /* Initialize application modules */
    Beeper beeper;
    Utilities utilities;
    Shortcuts shortcuts;
    Dashboards dashboards;
    QJoysticks* qjoysticks = QJoysticks::getInstance();
    QSimpleUpdater* updater = QSimpleUpdater::getInstance();
    DriverStation* driverstation = DriverStation::getInstance();

    /* Shortcuts gets events before virtual joystick */
    app.installEventFilter (&shortcuts);

    /* Load the QML interface */
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty ("cRatio",        ratio);
    engine.rootContext()->setContextProperty ("cIsMac",        isMac);
    engine.rootContext()->setContextProperty ("cIsUnix",       isUnx);
    engine.rootContext()->setContextProperty ("cIsWindows",    isWin);
    engine.rootContext()->setContextProperty ("cBeeper",       &beeper);
    engine.rootContext()->setContextProperty ("cUpdater",      updater);
    engine.rootContext()->setContextProperty ("QJoysticks",    qjoysticks);
    engine.rootContext()->setContextProperty ("cUtilities",    &utilities);
    engine.rootContext()->setContextProperty ("cDashboard",    &dashboards);
    engine.rootContext()->setContextProperty ("appDspName",    APP_DSPNAME);
    engine.rootContext()->setContextProperty ("appVersion",    APP_VERSION);
    engine.rootContext()->setContextProperty ("cUpdaterUrl",   URL_UPDATER);
    engine.rootContext()->setContextProperty ("DriverStation", driverstation);
    engine.load (QUrl (QStringLiteral ("qrc:/qml/main.qml")));

    /* QML loading failed, exit the application */
    if (engine.rootObjects().isEmpty())
        return EXIT_FAILURE;

    /* Ask first-timers to download the xbox drivers */
    DownloadXboxDrivers();

    /* Tell user how much time was needed to initialize the app */
    qDebug() << "Initialized in " << pElapsedTime->elapsed() << "milliseconds";
    delete pElapsedTime;

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

//------------------------------------------------------------------------------
// Qt includes
//------------------------------------------------------------------------------

#include <QTime>
#include <QtQml>
#include <QScreen>
#include <iostream>
#include <QApplication>
#include <QJoysticks.h>
#include <QDesktopServices>
#include <QQmlApplicationEngine>

//------------------------------------------------------------------------------
// Library includes
//------------------------------------------------------------------------------

#include <stdio.h>
#include <DriverStation.h>
#include <QSimpleUpdater.h>

//------------------------------------------------------------------------------
// Application includes
//------------------------------------------------------------------------------

#include "beeper.h"
#include "versions.h"
#include "shortcuts.h"
#include "utilities.h"
#include "dashboards.h"

//------------------------------------------------------------------------------
// Fix compilation issues in Windows
//------------------------------------------------------------------------------

#ifdef Q_OS_WIN
#ifdef main
#undef main
#endif
#endif

//------------------------------------------------------------------------------
// Mac-specific initialization code
//------------------------------------------------------------------------------

#ifdef Q_OS_MAC
#include <QObject>
#include <QSettings>
#include <QMessageBox>
#include <QDesktopServices>
#endif

//------------------------------------------------------------------------------
// CLI messages
//------------------------------------------------------------------------------

const QString LOGS = "We instructed your file manager to navigate to:       \n"
                     "    %1                                                \n"
                     "If nothing happens, please navigate to that directory   ";

const QString WEBS = "We instructed your web browser to navigate to:        \n"
                     "    %1                                                \n"
                     "If nothing happens, please navigate to that URL         ";

const QString HELP = "Usage: qdriverstation [ options ... ]                 \n"
                     "                                                      \n"
                     "Options include:                                      \n"
                     "    -b, --bug       Report a bug                      \n"
                     "    -h, --help      Show this message                 \n"
                     "    -l, --logs      Open the logs directory           \n"
                     "    -r, --reset     Reset/clear the settings          \n"
                     "    -c, --contact   Contact the lead developer        \n"
                     "    -v, --version   Display the application version   \n"
                     "    -w, --website   Open a web site of this project   \n";

//------------------------------------------------------------------------------
// Website, contact info & other URLs
//------------------------------------------------------------------------------

// *INDENT-OFF*
const QString CONT_URL = "alex_spataru@outlook.com";
const QString HTTP_URL = "http://qdriverstation.sf.net";
const QString BUGS_URL = "http://github.com/FRC-Utilities/QDriverStation/issues";
// *INDENT-ON*

//------------------------------------------------------------------------------
// Download joystick drivers if needed
//------------------------------------------------------------------------------

static void DownloadXboxDrivers() {
#ifdef Q_OS_MAC
    QSettings settings (APP_COMPANY, APP_DSPNAME);

    if (settings.value ("FirstLaunch", true).toBool()) {
        QMessageBox box;
        box.setIcon (QMessageBox::Question);
        box.setStandardButtons (QMessageBox::Yes | QMessageBox::No);
        box.setDefaultButton (QMessageBox::Yes);

        box.setWindowTitle (QObject::tr ("Download Joystick Drivers"));

        box.setText (QObject::tr (
                         "Do you want to install a driver "
                         "for Xbox joysticks?"));

        box.setInformativeText (QObject::tr (
                                    "Clicking \"Yes\" will open a web "
                                    "browser to download the drivers"));

        settings.setValue ("FirstLaunch", false);

        if (box.exec() == QMessageBox::Yes)
            QDesktopServices::openUrl (QUrl (
                                           "https://github.com/360Controller/"
                                           "360Controller/releases/latest"));
    }
#endif
}

//------------------------------------------------------------------------------
// Utility functions
//------------------------------------------------------------------------------

static void showHelp() {
    qDebug() << HELP.toStdString().c_str();
}

static void resetSettings() {
    QSettings (APP_COMPANY, APP_DSPNAME).clear();
    qDebug() << "QDriverStation settings cleared!";
}

static void contact() {
    QString url = "mailto:" + CONT_URL;
    QDesktopServices::openUrl (QUrl (url));
    qDebug() << WEBS.arg (CONT_URL).toStdString().c_str();
}

static void reportBug() {
    QDesktopServices::openUrl (QUrl (BUGS_URL));
    qDebug() << WEBS.arg (BUGS_URL).toStdString().c_str();
}

static void openLogsDir() {
    qDebug() << LOGS.arg (DS_LOGGER_PATH()).toStdString().c_str();
    QDesktopServices::openUrl (QUrl::fromLocalFile (DS_LOGGER_PATH()));
}

static void openWebsite() {
    QDesktopServices::openUrl (QUrl (HTTP_URL));
    qDebug() << WEBS.arg (HTTP_URL).toStdString().c_str();
}

static void showVersion() {
    QString appver = APP_DSPNAME + " version " + APP_VERSION;
    QString author = "Written by Alex Spataru <" + CONT_URL + ">";

    qDebug() << appver.toStdString().c_str();
    qDebug() << author.toStdString().c_str();
}

//------------------------------------------------------------------------------
// Application init
//------------------------------------------------------------------------------

int main (int argc, char* argv[]) {
    /* Fix scalling issues */
#if QT_VERSION >= QT_VERSION_CHECK (5, 6, 0)
#if defined Q_OS_MAC
    QApplication::setAttribute (Qt::AA_EnableHighDpiScaling);
#else
    QApplication::setAttribute (Qt::AA_DisableHighDpiScaling);
#endif
#endif

    /* Initialize application */
    QString arguments;
    QApplication app (argc, argv);
    app.setApplicationName    (APP_DSPNAME);
    app.setOrganizationName   (APP_COMPANY);
    app.setApplicationVersion (APP_VERSION);
    app.setOrganizationDomain (APP_WEBSITE);

    /* Read command line arguments */
    if (app.arguments().count() >= 2)
        arguments = app.arguments().at (1);

    /* We have some arguments, read them */
    if (!arguments.isEmpty() && arguments.startsWith ("-")) {
        if (arguments == "-b" || arguments == "--bug")
            reportBug();

        else if (arguments == "-l" || arguments == "--logs")
            openLogsDir();

        else if (arguments == "-r" || arguments == "--reset")
            resetSettings();

        else if (arguments == "-c" || arguments == "--contact")
            contact();

        else if (arguments == "-v" || arguments == "--version")
            showVersion();

        else if (arguments == "-w" || arguments == "--website")
            openWebsite();

        else
            showHelp();

        return EXIT_SUCCESS;
    }

    /* Start the init. time counter */
    QTime* pElapsedTime = new QTime;
    pElapsedTime->start();

    /* Install the more advanced logger */
    qInstallMessageHandler (DS_MESSAGE_HANDLER);

    /* Initialize OS variables */
    bool isMac = false;
    bool isUnx = false;
    bool isWin = false;

    /* Let QML know the operating system */
#if defined Q_OS_MAC
    isMac = true;
#elif defined Q_OS_WIN
    isWin = true;
#else
    isUnx = true;
#endif

    /* Calculate the scale factor of the screen */
    qreal ratio = (app.primaryScreen()->physicalDotsPerInch() / 100) * 0.9;

    /* Scale factor is too small or OS is Mac */
    if (ratio < 1.2 || isMac)
        ratio = 1;

    /* Report the scale factor */
    qDebug() << "Scale factor set to:" << ratio;

    /* Initialize application modules */
    Beeper beeper;
    Utilities utilities;
    Shortcuts shortcuts;
    Dashboards dashboards;
    QJoysticks* qjoysticks = QJoysticks::getInstance();
    QSimpleUpdater* updater = QSimpleUpdater::getInstance();
    DriverStation* driverstation = DriverStation::getInstance();

    /* Shortcuts gets events before virtual joystick */
    app.installEventFilter (&shortcuts);

    /* Load the QML interface */
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty ("cRatio",        ratio);
    engine.rootContext()->setContextProperty ("cIsMac",        isMac);
    engine.rootContext()->setContextProperty ("cIsUnix",       isUnx);
    engine.rootContext()->setContextProperty ("cIsWindows",    isWin);
    engine.rootContext()->setContextProperty ("cBeeper",       &beeper);
    engine.rootContext()->setContextProperty ("cUpdater",      updater);
    engine.rootContext()->setContextProperty ("QJoysticks",    qjoysticks);
    engine.rootContext()->setContextProperty ("cUtilities",    &utilities);
    engine.rootContext()->setContextProperty ("cDashboard",    &dashboards);
    engine.rootContext()->setContextProperty ("appDspName",    APP_DSPNAME);
    engine.rootContext()->setContextProperty ("appVersion",    APP_VERSION);
    engine.rootContext()->setContextProperty ("cUpdaterUrl",   URL_UPDATER);
    engine.rootContext()->setContextProperty ("DriverStation", driverstation);
    engine.load (QUrl (QStringLiteral ("qrc:/qml/main.qml")));

    /* QML loading failed, exit the application */
    if (engine.rootObjects().isEmpty())
        return EXIT_FAILURE;

    /* Ask first-timers to download the xbox drivers */
    DownloadXboxDrivers();

    /* Tell user how much time was needed to initialize the app */
    qDebug() << "Initialized in " << pElapsedTime->elapsed() << "milliseconds";
    delete pElapsedTime;

    /* Run normally */
    return app.exec();
}
<|endoftext|>


<commit_before>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

              Copyright (c) 2003-2017, Cauldron Development LLC
                 Copyright (c) 2003-2017, Stanford University
                             All rights reserved.

        The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
        as published by the Free Software Foundation, either version 2.1 of
        the License, or (at your option) any later version.

        The C! 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 the C! library.  If not, see
        <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
        You may request written permission by emailing the authors.

                For information regarding this software email:
                               Joseph Coffland
                        joseph@cauldrondevelopment.com

\******************************************************************************/

#include "URI.h"

#include <cbang/String.h>
#include <cbang/Exception.h>
#include <cbang/log/Logger.h>

#include <sstream>

#include <ctype.h>
#include <string.h>

using namespace cb;
using namespace std;

#define DIGIT_CHARS        "1234567890"
#define HEX_CHARS          DIGIT_CHARS "abcdefABCDEF"
#define LOWER_CHARS        "abcdefghijklmnopqrstuvwxyz"
#define UPPER_CHARS        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define ALPHA_CHARS        LOWER_CHARS UPPER_CHARS
#define ALPHANUMERIC_CHARS ALPHA_CHARS DIGIT_CHARS
#define RESERVED_CHARS     ";/?:@&=+$,"
#define UNRESERVED_CHARS   ALPHANUMERIC_CHARS "-_.!~*'()"
#define USER_PASS_CHARS    UNRESERVED_CHARS ";&=+$,"
#define NAME_CHARS         UNRESERVED_CHARS ";/?:@+$,"
#define VALUE_CHARS        NAME_CHARS "="
#define PATH_SEGMENT_CHARS UNRESERVED_CHARS ":@&=+$,"
#define HOST_CHARS         ALPHANUMERIC_CHARS "-."
#define SCHEME_CHARS       ALPHANUMERIC_CHARS "+-."

namespace {
  int hexToInt(char x) {
    return isdigit(x) ? x - '0' : ((islower(x) ? x - 'a' : x - 'A') + 10);
  }

  char nibblesToChar(char a, char b) {
    return (char)((hexToInt(a) << 4) + hexToInt(b));
  }

  char match(const char *&s, char c) {
    if (*s != c) THROWS("Expected '" << c << "'");
    s++;
    return c;
  }

  bool consume(const char *&s, char c) {
    if (*s == c) s++;
    else return false;
    return true;
  }

  bool contains(const char *s, char c) {
    return c && strchr(s, c);
  }
}

const char *URI::DEFAULT_UNESCAPED = UNRESERVED_CHARS "/";

URI::URI() : port(0) {}

URI::URI(const string &uri) : port(0) {
  read(uri);
}

URI::URI(const char *uri) : port(0) {
  read(uri);
}

unsigned URI::getPort() const {
  if (port || scheme.empty()) return port;

  if (scheme == "ftp") return 21;
  if (scheme == "ssh") return 22;
  if (scheme == "telnet") return 23;
  if (scheme == "domain") return 53;
  if (scheme == "tftp") return 69;
  if (scheme == "gopher") return 70;
  if (scheme == "finger") return 79;
  if (scheme == "http") return 80;
  if (scheme == "pop2") return 109;
  if (scheme == "pop3") return 110;
  if (scheme == "auth") return 113;
  if (scheme == "sftp") return 115;
  if (scheme == "nntp") return 119;
  if (scheme == "ntp") return 123;
  if (scheme == "snmp") return 161;
  if (scheme == "irc") return 194;
  if (scheme == "imap3") return 220;
  if (scheme == "ldap") return 389;
  if (scheme == "https") return 443;

  THROWS("Unknown scheme '" << scheme << "' and port not set");
}

string URI::getExtension() const {
  size_t ptr = path.find_last_of('.');
  return (ptr == string::npos) ? "" : path.substr(ptr + 1);
}

const string URI::getQuery() const {
  ostringstream str;
  writeQuery(str);
  return decode(str.str());
}

void URI::setQuery(const string &query) {
  setQuery(query.c_str());
}

void URI::setQuery(const char *query) {
  StringMap::clear(); // Reset query string vars
  const char *s = query;

  try {
    parseQuery(s);
  } catch (const Exception &e) {
    THROWS("Failed to parse URI query '" << query << "' at char "
           << (s - query) << ": " << e.getMessage());
  }
}

void URI::clear() {
  StringMap::clear();
  scheme.clear();
  host.clear();
  port = 0;
  path.clear();
  user.clear();
  pass.clear();
}

void URI::normalize() {
  // TODO: Resolove '..' and '.'

  vector<string> parts;
  String::tokenize(path, parts, "/");
  path = string("/") + String::join(parts, "/");
}

void URI::read(const string &uri) {
  read(uri.c_str());
}

void URI::read(const char *uri) {
  // See RFC2396
  // Does not support:
  //   opaque URI data (Section 3)
  //   registry-based naming (Section 3.2.1)
  //   path parameters (Section 3.3)

  clear(); // Reset all

  const char *s = uri;
  try {
    if (!*s) THROW("Cannot be empty");

    if (*s == '/') parseAbsPath(s);
    else {
      parseScheme(s);
      parseNetPath(s);
    }
    if (consume(s, '?')) parseQuery(s);

  } catch (const Exception &e) {
    THROWS("Failed to parse URI '" << uri << "' at char " << (s - uri) << ": "
           << e.getMessage());
  }
}

ostream &URI::write(ostream &stream) const {
  if (!scheme.empty()) stream << scheme << ':';
  if (!host.empty()) {
    stream << "//";

    if (!user.empty()) stream << encode(user, USER_PASS_CHARS);
    if (!pass.empty()) stream << ':' << encode(pass, USER_PASS_CHARS);
    if (!user.empty() || !pass.empty()) stream << '@';

    stream << encode(host, HOST_CHARS);
    if (port) stream << ':' << port;
  }

  stream << encode(path, PATH_SEGMENT_CHARS "/");

  if (!empty()) stream << '?';

  return writeQuery(stream);
}

ostream &URI::writeQuery(ostream &stream) const {
  for (const_iterator it = begin(); it != end(); it++) {
    if (it != begin()) stream << '&';

    stream << encode(it->first, NAME_CHARS);
    if (!it->second.empty()) stream << '=' << encode(it->second, VALUE_CHARS);
  }

  return stream;
}

string URI::toString() const {
  ostringstream str;
  str << *this;
  return str.str();
}

string URI::encode(const string &s, const char *unescaped) {
  string result;

  for (unsigned i = 0; i < s.length(); i++)
    if (contains(unescaped, s[i])) result.append(1, s[i]);
    else result.append(String::printf("%%%02x", (unsigned)s[i]));

  return result;
}

string URI::decode(const string &s) {
  string result;

  for (unsigned i = 0; i < s.length(); i++)
    if (s[i] == '%' && i < s.length() - 2 &&
        isxdigit(s[i + 1]) && isxdigit(s[i + 2])) {
      result.append(1, nibblesToChar(s[i + 1], s[i + 2]));
      i += 2;

    } else result.append(1, s[i]);

  return result;
}

char URI::parseEscape(const char *&s) {
  match(s, '%');

  char a, b;
  if (!isxdigit(a = *s++) || !isxdigit(b = *s++))
    THROW("Expected hexadecimal digit in escape sequence");

  return nibblesToChar(a, b);
}

void URI::parseAbsPath(const char *&s) {
  match(s, '/');

  do {
    path.append(1, '/');
    parsePathSegment(s);
  } while (consume(s, '/'));
}

void URI::parsePathSegment(const char *&s) {
  while (true)
    if (contains(PATH_SEGMENT_CHARS, *s)) path.append(1, *s++);
    else if (*s == '%') path.append(1, parseEscape(s));
    else break;
}

void URI::parseScheme(const char *&s) {
  if (!isalpha(*s)) THROW("Expected alpha at start of scheme");

  while (true)
    if (contains(SCHEME_CHARS, *s)) scheme.append(1, *s++);
    else break;

  match(s, ':');
}

void URI::parseNetPath(const char *&s) {
  match(s, '/');
  consume(s, '/');
  parseAuthority(s);
  if (*s == '/') parseAbsPath(s);
}

void URI::parseAuthority(const char *&s) {
  // Try parsing user info
  const char *save = s;
  parseUserInfo(s);
  if (!consume(s, '@')) {
    // Backtrack, wasn't user info
    s = save;
    user.clear();
    pass.clear();
  }

  parseHost(s);
  if (consume(s, ':')) parsePort(s);
}

string URI::parseUserPass(const char *&s) {
  string result;

  while (true)
    if (contains(USER_PASS_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  return result;
}

void URI::parseUserInfo(const char *&s) {
  user = parseUserPass(s);
  if (consume(s, ':')) pass = parseUserPass(s);
}

void URI::parseHost(const char *&s) {
  while (true)
    if (contains(HOST_CHARS, *s)) host.append(1, *s++);
    else break;

  if (host.empty()) THROW("Expected host character");
}

void URI::parsePort(const char *&s) {
  string result;

  while (isdigit(*s)) result.append(1, *s++);

  if (result.empty()) return;
  port = String::parseU32(result);
}

void URI::parseQuery(const char *&s) {
  if (!*s) return; // Empty query
  parsePair(s);
  while (consume(s, '&')) parsePair(s);
}

void URI::parsePair(const char *&s) {
  string name = parseName(s);
  string value = consume(s, '=') ? parseValue(s) : "";
  set(name, value);
}

string URI::parseName(const char *&s) {
  string result;

  while (true)
    if (contains(NAME_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  if (result.empty()) THROW("Expected query name character");

  return result;
}

string URI::parseValue(const char *&s) {
  string result;

  while (true)
    if (contains(VALUE_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  return result;
}
<commit_msg>escape debug string<commit_after>/******************************************************************************\

          This file is part of the C! library.  A.K.A the cbang library.

              Copyright (c) 2003-2017, Cauldron Development LLC
                 Copyright (c) 2003-2017, Stanford University
                             All rights reserved.

        The C! library is free software: you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public License
        as published by the Free Software Foundation, either version 2.1 of
        the License, or (at your option) any later version.

        The C! 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 the C! library.  If not, see
        <http://www.gnu.org/licenses/>.

        In addition, BSD licensing may be granted on a case by case basis
        by written permission from at least one of the copyright holders.
        You may request written permission by emailing the authors.

                For information regarding this software email:
                               Joseph Coffland
                        joseph@cauldrondevelopment.com

\******************************************************************************/

#include "URI.h"

#include <cbang/String.h>
#include <cbang/Exception.h>
#include <cbang/log/Logger.h>

#include <sstream>

#include <ctype.h>
#include <string.h>

using namespace cb;
using namespace std;

#define DIGIT_CHARS        "1234567890"
#define HEX_CHARS          DIGIT_CHARS "abcdefABCDEF"
#define LOWER_CHARS        "abcdefghijklmnopqrstuvwxyz"
#define UPPER_CHARS        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define ALPHA_CHARS        LOWER_CHARS UPPER_CHARS
#define ALPHANUMERIC_CHARS ALPHA_CHARS DIGIT_CHARS
#define RESERVED_CHARS     ";/?:@&=+$,"
#define UNRESERVED_CHARS   ALPHANUMERIC_CHARS "-_.!~*'()"
#define USER_PASS_CHARS    UNRESERVED_CHARS ";&=+$,"
#define NAME_CHARS         UNRESERVED_CHARS ";/?:@+$,"
#define VALUE_CHARS        NAME_CHARS "="
#define PATH_SEGMENT_CHARS UNRESERVED_CHARS ":@&=+$,"
#define HOST_CHARS         ALPHANUMERIC_CHARS "-."
#define SCHEME_CHARS       ALPHANUMERIC_CHARS "+-."

namespace {
  int hexToInt(char x) {
    return isdigit(x) ? x - '0' : ((islower(x) ? x - 'a' : x - 'A') + 10);
  }

  char nibblesToChar(char a, char b) {
    return (char)((hexToInt(a) << 4) + hexToInt(b));
  }

  char match(const char *&s, char c) {
    if (*s != c) THROWS("Expected '" << c << "'");
    s++;
    return c;
  }

  bool consume(const char *&s, char c) {
    if (*s == c) s++;
    else return false;
    return true;
  }

  bool contains(const char *s, char c) {
    return c && strchr(s, c);
  }
}

const char *URI::DEFAULT_UNESCAPED = UNRESERVED_CHARS "/";

URI::URI() : port(0) {}

URI::URI(const string &uri) : port(0) {
  read(uri);
}

URI::URI(const char *uri) : port(0) {
  read(uri);
}

unsigned URI::getPort() const {
  if (port || scheme.empty()) return port;

  if (scheme == "ftp") return 21;
  if (scheme == "ssh") return 22;
  if (scheme == "telnet") return 23;
  if (scheme == "domain") return 53;
  if (scheme == "tftp") return 69;
  if (scheme == "gopher") return 70;
  if (scheme == "finger") return 79;
  if (scheme == "http") return 80;
  if (scheme == "pop2") return 109;
  if (scheme == "pop3") return 110;
  if (scheme == "auth") return 113;
  if (scheme == "sftp") return 115;
  if (scheme == "nntp") return 119;
  if (scheme == "ntp") return 123;
  if (scheme == "snmp") return 161;
  if (scheme == "irc") return 194;
  if (scheme == "imap3") return 220;
  if (scheme == "ldap") return 389;
  if (scheme == "https") return 443;

  THROWS("Unknown scheme '" << scheme << "' and port not set");
}

string URI::getExtension() const {
  size_t ptr = path.find_last_of('.');
  return (ptr == string::npos) ? "" : path.substr(ptr + 1);
}

const string URI::getQuery() const {
  ostringstream str;
  writeQuery(str);
  return decode(str.str());
}

void URI::setQuery(const string &query) {
  setQuery(query.c_str());
}

void URI::setQuery(const char *query) {
  StringMap::clear(); // Reset query string vars
  const char *s = query;

  try {
    parseQuery(s);
  } catch (const Exception &e) {
    THROWS("Failed to parse URI query '" << String::escapeC(query)
           << "' at char " << (s - query) << ": " << e.getMessage());
  }
}

void URI::clear() {
  StringMap::clear();
  scheme.clear();
  host.clear();
  port = 0;
  path.clear();
  user.clear();
  pass.clear();
}

void URI::normalize() {
  // TODO: Resolove '..' and '.'

  vector<string> parts;
  String::tokenize(path, parts, "/");
  path = string("/") + String::join(parts, "/");
}

void URI::read(const string &uri) {
  read(uri.c_str());
}

void URI::read(const char *uri) {
  // See RFC2396
  // Does not support:
  //   opaque URI data (Section 3)
  //   registry-based naming (Section 3.2.1)
  //   path parameters (Section 3.3)

  clear(); // Reset all

  const char *s = uri;
  try {
    if (!*s) THROW("Cannot be empty");

    if (*s == '/') parseAbsPath(s);
    else {
      parseScheme(s);
      parseNetPath(s);
    }
    if (consume(s, '?')) parseQuery(s);

  } catch (const Exception &e) {
    THROWS("Failed to parse URI '" << String::escapeC(uri) << "' at char "
           << (s - uri) << ": " << e.getMessage());
  }
}

ostream &URI::write(ostream &stream) const {
  if (!scheme.empty()) stream << scheme << ':';
  if (!host.empty()) {
    stream << "//";

    if (!user.empty()) stream << encode(user, USER_PASS_CHARS);
    if (!pass.empty()) stream << ':' << encode(pass, USER_PASS_CHARS);
    if (!user.empty() || !pass.empty()) stream << '@';

    stream << encode(host, HOST_CHARS);
    if (port) stream << ':' << port;
  }

  stream << encode(path, PATH_SEGMENT_CHARS "/");

  if (!empty()) stream << '?';

  return writeQuery(stream);
}

ostream &URI::writeQuery(ostream &stream) const {
  for (const_iterator it = begin(); it != end(); it++) {
    if (it != begin()) stream << '&';

    stream << encode(it->first, NAME_CHARS);
    if (!it->second.empty()) stream << '=' << encode(it->second, VALUE_CHARS);
  }

  return stream;
}

string URI::toString() const {
  ostringstream str;
  str << *this;
  return str.str();
}

string URI::encode(const string &s, const char *unescaped) {
  string result;

  for (unsigned i = 0; i < s.length(); i++)
    if (contains(unescaped, s[i])) result.append(1, s[i]);
    else result.append(String::printf("%%%02x", (unsigned)s[i]));

  return result;
}

string URI::decode(const string &s) {
  string result;

  for (unsigned i = 0; i < s.length(); i++)
    if (s[i] == '%' && i < s.length() - 2 &&
        isxdigit(s[i + 1]) && isxdigit(s[i + 2])) {
      result.append(1, nibblesToChar(s[i + 1], s[i + 2]));
      i += 2;

    } else result.append(1, s[i]);

  return result;
}

char URI::parseEscape(const char *&s) {
  match(s, '%');

  char a, b;
  if (!isxdigit(a = *s++) || !isxdigit(b = *s++))
    THROW("Expected hexadecimal digit in escape sequence");

  return nibblesToChar(a, b);
}

void URI::parseAbsPath(const char *&s) {
  match(s, '/');

  do {
    path.append(1, '/');
    parsePathSegment(s);
  } while (consume(s, '/'));
}

void URI::parsePathSegment(const char *&s) {
  while (true)
    if (contains(PATH_SEGMENT_CHARS, *s)) path.append(1, *s++);
    else if (*s == '%') path.append(1, parseEscape(s));
    else break;
}

void URI::parseScheme(const char *&s) {
  if (!isalpha(*s)) THROW("Expected alpha at start of scheme");

  while (true)
    if (contains(SCHEME_CHARS, *s)) scheme.append(1, *s++);
    else break;

  match(s, ':');
}

void URI::parseNetPath(const char *&s) {
  match(s, '/');
  consume(s, '/');
  parseAuthority(s);
  if (*s == '/') parseAbsPath(s);
}

void URI::parseAuthority(const char *&s) {
  // Try parsing user info
  const char *save = s;
  parseUserInfo(s);
  if (!consume(s, '@')) {
    // Backtrack, wasn't user info
    s = save;
    user.clear();
    pass.clear();
  }

  parseHost(s);
  if (consume(s, ':')) parsePort(s);
}

string URI::parseUserPass(const char *&s) {
  string result;

  while (true)
    if (contains(USER_PASS_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  return result;
}

void URI::parseUserInfo(const char *&s) {
  user = parseUserPass(s);
  if (consume(s, ':')) pass = parseUserPass(s);
}

void URI::parseHost(const char *&s) {
  while (true)
    if (contains(HOST_CHARS, *s)) host.append(1, *s++);
    else break;

  if (host.empty()) THROW("Expected host character");
}

void URI::parsePort(const char *&s) {
  string result;

  while (isdigit(*s)) result.append(1, *s++);

  if (result.empty()) return;
  port = String::parseU32(result);
}

void URI::parseQuery(const char *&s) {
  if (!*s) return; // Empty query
  parsePair(s);
  while (consume(s, '&')) parsePair(s);
}

void URI::parsePair(const char *&s) {
  string name = parseName(s);
  string value = consume(s, '=') ? parseValue(s) : "";
  set(name, value);
}

string URI::parseName(const char *&s) {
  string result;

  while (true)
    if (contains(NAME_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  if (result.empty()) THROW("Expected query name character");

  return result;
}

string URI::parseValue(const char *&s) {
  string result;

  while (true)
    if (contains(VALUE_CHARS, *s)) result.append(1, *s++);
    else if (*s == '%') result.append(1, parseEscape(s));
    else break;

  return result;
}
<|endoftext|>


<commit_before>#include "graphics.h"
#include <SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

static int const SURFACE_WIDTH  = 640;
static int const SURFACE_HEIGHT = 480;
static int const SURFACE_BPP    = 32;

static SDL_Surface *surface = NULL;

void initgraph(int *gdriver, int *gmode, const char *something) {
  fprintf(stderr, "DEBUG: Called initgraph()\n");

  if (surface) {
    fprintf(stderr, "initgraph() can only be called once\n");
    exit(2);
  }

  if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
    fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
    exit(1);
  }

  if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)) {
    fprintf(stderr, "SDL_EnableKeyRepeat failed: %s\n", SDL_GetError());
    SDL_Quit();
    exit(1);
  }

  if ((surface = SDL_SetVideoMode(
    SURFACE_WIDTH,
    SURFACE_HEIGHT,
    SURFACE_BPP,
    SDL_HWSURFACE | SDL_DOUBLEBUF
  )) == NULL) {
    fprintf(stderr, "SDL_SetVideoMode failed: %s\n", SDL_GetError());
    SDL_Quit();
    exit(1);
  }
}

void closegraph(void) {
  // TODO: Implement
}

int getpixel(int x, int y) {
  // TODO: Implement
  return 0;
}

void putpixel(int x, int y, int color) {
  // TODO: Implement
}

int getcolor(void) {
  // TODO: Implement
  return 0;
}

void setcolor(int color) {
  // TODO: Implement
}

void getimage(int left, int top, int right, int bottom, void *pic) {
  // TODO: Implement
}

void putimage(int left, int top, void *pic, int mode) {
  // TODO: Implement
}

size_t imagesize(int left, int top, int right, int bottom) {
  // TODO: Implement
  return 0;
}

void line(int a_x, int a_y, int b_x, int b_y) {
  // TODO: Implement
}

void rectangle(int left, int top, int right, int bottom) {
  // TODO: Implement
}

void setfillstyle(int mode, int color) {
  // TODO: Implement
}

void floodfill(int x, int y, int color) {
  // TODO: Implement
}

void outtextxy(int x, int y, const char *text) {
  // TODO: Implement
}

int GetKeyState(int key) {
  // TODO: Implement
  return 0;
}

void SetNormalKeysMode(void) {
  // no implementation necessary
}

void SetButtonKeysMode(void) {
  // no implementation necessary
}

void delay(int milliseconds) {
  // TODO: Implement
}

void cleardevice(void) {
  // TODO: Implement
}

void itoa(int num, char *str, int base) {
  // Only writing impl for base 10 conversion
  if (base != 10) {
    fprintf(stderr, "iota() only supports base 10 conversion\n");
    exit(1);
  }

  // Stupid unsafe itoa has no buffer size parameter, so we have
  // to use sprintf instead of snprintf
  sprintf(str, "%d", num);
}
<commit_msg>Add error() and sdl_error() functions<commit_after>#include "graphics.h"
#include <SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#define error(fmt, ...) _error(__LINE__, fmt, __VA_ARGS__)
#define sdl_error(name, ...) _sdl_error(__LINE__, name)

static void _error(long  line, const char *fmt, ...);
static void _sdl_error(long  line, const char *name);

static int const SURFACE_WIDTH  = 640;
static int const SURFACE_HEIGHT = 480;
static int const SURFACE_BPP    = 32;

static SDL_Surface *surface = NULL;

void initgraph(int *gdriver, int *gmode, const char *something) {
  if (surface) {
    error("initgraph() can only be called once", NULL);
  }

  if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
    sdl_error("SDL_Init");
  }

  if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)) {
    sdl_error("SDL_EnableKeyRepeat");
  }

  if ((surface = SDL_SetVideoMode(
    SURFACE_WIDTH,
    SURFACE_HEIGHT,
    SURFACE_BPP,
    SDL_HWSURFACE | SDL_DOUBLEBUF
  )) == NULL) {
    sdl_error("SDL_SetVideoMode");
  }
}

void closegraph(void) {
  // TODO: Implement
}

int getpixel(int x, int y) {
  // TODO: Implement
  return 0;
}

void putpixel(int x, int y, int color) {
  // TODO: Implement
}

int getcolor(void) {
  // TODO: Implement
  return 0;
}

void setcolor(int color) {
  // TODO: Implement
}

void getimage(int left, int top, int right, int bottom, void *pic) {
  // TODO: Implement
}

void putimage(int left, int top, void *pic, int mode) {
  // TODO: Implement
}

size_t imagesize(int left, int top, int right, int bottom) {
  // TODO: Implement
  return 0;
}

void line(int a_x, int a_y, int b_x, int b_y) {
  // TODO: Implement
}

void rectangle(int left, int top, int right, int bottom) {
  // TODO: Implement
}

void setfillstyle(int mode, int color) {
  // TODO: Implement
}

void floodfill(int x, int y, int color) {
  // TODO: Implement
}

void outtextxy(int x, int y, const char *text) {
  // TODO: Implement
}

int GetKeyState(int key) {
  // TODO: Implement
  return 0;
}

void SetNormalKeysMode(void) {
  // no implementation necessary
}

void SetButtonKeysMode(void) {
  // no implementation necessary
}

void delay(int milliseconds) {
  // TODO: Implement
}

void cleardevice(void) {
  // TODO: Implement
}

void itoa(int num, char *str, int base) {
  // Only writing impl for base 10 conversion
  if (base != 10) {
    fprintf(stderr, "iota() only supports base 10 conversion\n");
    exit(1);
  }

  // Stupid unsafe itoa has no buffer size parameter, so we have
  // to use sprintf instead of snprintf
  sprintf(str, "%d", num);
}

static void _error(long  line, const char *fmt, ...) {
  va_list args;

  va_start(args, fmt);
  fprintf(stderr, "graphics.cpp error on line %ld: ", line);
  vfprintf(stderr, fmt, args);
  fprintf(stderr, "\n");
  va_end(args);

  if (surface) {
    SDL_Quit();
    surface = NULL;
  }

  exit(1);
}

static void _sdl_error(long  line, const char *name) {
  _error(line, "SDL function %s failed. Reason: %s", name, SDL_GetError());
}
<|endoftext|>


<commit_before>// Filename: bioStreamBuf.cxx
// Created by:  drose (25Sep02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "bioStreamBuf.h"
#include "config_downloader.h"
#include "ssl_utils.h"
#include <errno.h>

#ifdef HAVE_OPENSSL

#ifdef WIN32_VC
  #include <WinSock2.h>
  #include <windows.h>  // for WSAGetLastError()
  #undef X509_NAME
#endif  // WIN32_VC

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
BioStreamBuf::
BioStreamBuf() {
  _is_closed = false;

#ifdef HAVE_IOSTREAM
  _buffer = (char *)PANDA_MALLOC_ARRAY(8192);
  char *ebuf = _buffer + 8192;
  char *mbuf = _buffer + 4096;
  setg(_buffer, mbuf, mbuf);
  setp(mbuf, ebuf);

#else
  allocate();
  // Chop the buffer in half.  The bottom half goes to the get buffer;
  // the top half goes to the put buffer.
  char *b = base();
  char *t = ebuf();
  char *m = b + (t - b) / 2;
  setg(b, m, m);
  setp(b, m);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
BioStreamBuf::
~BioStreamBuf() {
  close();
#ifdef HAVE_IOSTREAM
  PANDA_FREE_ARRAY(_buffer);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void BioStreamBuf::
open(BioPtr *source) {
  _source = source;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void BioStreamBuf::
close() {
  sync();
  _source.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
overflow(int ch) {
  size_t n = pptr() - pbase();
  if (downloader_cat.is_spam()) {
    downloader_cat.spam()
      << "BioStreamBuf::overflow, " << n << " bytes\n";
  }
  if (n != 0) {
    size_t num_wrote = write_chars(pbase(), n);
    pbump(-(int)n);
    if (num_wrote != n) {
      return EOF;
    }
  }

  if (ch != EOF) {
    // Store the next character back in the buffer.
    *pptr() = ch;
    pbump(1);
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
sync() {
  /*
  size_t n = egptr() - gptr();
  gbump(n);
  */

  size_t n = pptr() - pbase();

  if (downloader_cat.is_spam()) {
    downloader_cat.spam()
      << "BioStreamBuf::sync, " << n << " bytes\n";
  }

  size_t num_wrote = write_chars(pbase(), n);
  pbump(-(int)n);
  if (num_wrote != n) {
    return EOF;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
underflow() {
  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    size_t buffer_size = egptr() - eback();
    gbump(-(int)buffer_size);

    size_t num_bytes = buffer_size;

    // BIO_read might return -1 or -2 on eof or error, so we have to
    // allow for negative numbers.
    int read_count = BIO_read(*_source, gptr(), buffer_size);
    thread_consider_yield();

    if (read_count != (int)num_bytes) {
      // Oops, we didn't read what we thought we would.
      if (read_count <= 0) {
        // Immediately save the os error in case we screw up and do
        // something that will change its value before we can output
        // it.
#ifdef WIN32_VC
        int os_error = WSAGetLastError();
#else
        int os_error = errno;
#endif  // WIN32_VC

        _is_closed = !BIO_should_retry(*_source);
        if (_is_closed) {
          downloader_cat.info()
            << "Lost connection to "
            << _source->get_server_name() << ":"
            << _source->get_port() << " (" << read_count << ").\n";
          notify_ssl_errors();

          SSL *ssl = NULL;
          BIO_get_ssl(*_source, &ssl);
          if (ssl != (SSL *)NULL) {
            downloader_cat.warning()
              << "OpenSSL error code: " << SSL_get_error(ssl, read_count)
              << "\n";
          }

#ifdef WIN32_VC
          downloader_cat.warning()
            << "Windows error code: " << os_error << "\n";
#else
          downloader_cat.warning()
            << "Unix error code: " << os_error << "\n";
#endif  // WIN32_VC
        }
        gbump(num_bytes);
        return EOF;
      }

      // Slide what we did read to the top of the buffer.
      nassertr(read_count < (int)num_bytes, EOF);
      size_t delta = (int)num_bytes - read_count;
      memmove(gptr() + delta, gptr(), read_count);
      gbump(delta);
    }
  }

  return (unsigned char)*gptr();
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::write_chars
//       Access: Private
//  Description: Sends some characters to the dest stream.  Does not
//               return until all characters are sent or the socket is
//               closed, even if the underlying BIO is non-blocking.
////////////////////////////////////////////////////////////////////
size_t BioStreamBuf::
write_chars(const char *start, size_t length) {
  if (length != 0) {
    size_t wrote_so_far = 0;

    int write_count = BIO_write(*_source, start, length);
    if (downloader_cat.is_spam()) {
      downloader_cat.spam()
        << "wrote " << write_count << " bytes.\n";
    }
    thread_consider_yield();
    while (write_count != (int)(length - wrote_so_far)) {
      if (write_count <= 0) {
        _is_closed = !BIO_should_retry(*_source);
        if (_is_closed) {
          return wrote_so_far;
        }

        // Block on the underlying socket before we try to write some
        // more.
        int fd = -1;
        BIO_get_fd(*_source, &fd);
        if (fd < 0) {
          downloader_cat.warning()
            << "socket BIO has no file descriptor.\n";
        } else {
          if (downloader_cat.is_spam()) {
            downloader_cat.spam()
              << "waiting to write to BIO.\n";
          }
          fd_set wset;
          FD_ZERO(&wset);
          FD_SET(fd, &wset);
          select(fd + 1, NULL, &wset, NULL, NULL);
        }

      } else {
        // wrote some characters.
        wrote_so_far += write_count;
      }

      // Try to write some more.
      write_count = BIO_write(*_source, start + wrote_so_far, length - wrote_so_far);
      if (downloader_cat.is_spam()) {
        downloader_cat.spam()
          << "continued, wrote " << write_count << " bytes.\n";
      }
      thread_consider_yield();
    }
  }

  return length;
}

#endif  // HAVE_OPENSSL
<commit_msg>more precise detection of a closed connection<commit_after>// Filename: bioStreamBuf.cxx
// Created by:  drose (25Sep02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "bioStreamBuf.h"
#include "config_downloader.h"
#include "ssl_utils.h"
#include <errno.h>

#ifdef HAVE_OPENSSL

#ifdef WIN32_VC
  #include <WinSock2.h>
  #include <windows.h>  // for WSAGetLastError()
  #undef X509_NAME
#endif  // WIN32_VC

#ifndef HAVE_STREAMSIZE
// Some compilers (notably SGI) don't define this for us
typedef int streamsize;
#endif /* HAVE_STREAMSIZE */

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::Constructor
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
BioStreamBuf::
BioStreamBuf() {
  _is_closed = false;

#ifdef HAVE_IOSTREAM
  _buffer = (char *)PANDA_MALLOC_ARRAY(8192);
  char *ebuf = _buffer + 8192;
  char *mbuf = _buffer + 4096;
  setg(_buffer, mbuf, mbuf);
  setp(mbuf, ebuf);

#else
  allocate();
  // Chop the buffer in half.  The bottom half goes to the get buffer;
  // the top half goes to the put buffer.
  char *b = base();
  char *t = ebuf();
  char *m = b + (t - b) / 2;
  setg(b, m, m);
  setp(b, m);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
BioStreamBuf::
~BioStreamBuf() {
  close();
#ifdef HAVE_IOSTREAM
  PANDA_FREE_ARRAY(_buffer);
#endif
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::open
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void BioStreamBuf::
open(BioPtr *source) {
  _source = source;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::close
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void BioStreamBuf::
close() {
  sync();
  _source.clear();
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::overflow
//       Access: Protected, Virtual
//  Description: Called by the system ostream implementation when its
//               internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
overflow(int ch) {
  size_t n = pptr() - pbase();
  if (downloader_cat.is_spam()) {
    downloader_cat.spam()
      << "BioStreamBuf::overflow, " << n << " bytes\n";
  }
  if (n != 0) {
    size_t num_wrote = write_chars(pbase(), n);
    pbump(-(int)n);
    if (num_wrote != n) {
      return EOF;
    }
  }

  if (ch != EOF) {
    // Store the next character back in the buffer.
    *pptr() = ch;
    pbump(1);
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::sync
//       Access: Protected, Virtual
//  Description: Called by the system iostream implementation to
//               implement a flush operation.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
sync() {
  /*
  size_t n = egptr() - gptr();
  gbump(n);
  */

  size_t n = pptr() - pbase();

  if (downloader_cat.is_spam()) {
    downloader_cat.spam()
      << "BioStreamBuf::sync, " << n << " bytes\n";
  }

  size_t num_wrote = write_chars(pbase(), n);
  pbump(-(int)n);
  if (num_wrote != n) {
    return EOF;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::underflow
//       Access: Protected, Virtual
//  Description: Called by the system istream implementation when its
//               internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int BioStreamBuf::
underflow() {
  // Sometimes underflow() is called even if the buffer is not empty.
  if (gptr() >= egptr()) {
    size_t buffer_size = egptr() - eback();
    gbump(-(int)buffer_size);

    size_t num_bytes = buffer_size;

    // BIO_read might return -1 or -2 on eof or error, so we have to
    // allow for negative numbers.
    int read_count = BIO_read(*_source, gptr(), buffer_size);
    thread_consider_yield();

    if (read_count != (int)num_bytes) {
      // Oops, we didn't read what we thought we would.
      if (read_count <= 0) {
        // Immediately save the os error in case we screw up and do
        // something that will change its value before we can output
        // it.
#ifdef WIN32_VC
        int os_error = WSAGetLastError();
#else
        int os_error = errno;
#endif  // WIN32_VC

        // if not EOF, there may be more data on the way even if BIO
        // indicates that no retry is necessary
        //_is_closed = !BIO_should_retry(*_source);
        //_is_closed = !BIO_should_read(*_source);
        _is_closed = BIO_eof(*_source);
        if (_is_closed) {
          downloader_cat.info()
            << "Lost connection to "
            << _source->get_server_name() << ":"
            << _source->get_port() << " (" << read_count << ").\n";
          notify_ssl_errors();

          SSL *ssl = NULL;
          BIO_get_ssl(*_source, &ssl);
          if (ssl != (SSL *)NULL) {
            downloader_cat.warning()
              << "OpenSSL error code: " << SSL_get_error(ssl, read_count)
              << "\n";
          }

#ifdef WIN32_VC
          downloader_cat.warning()
            << "Windows error code: " << os_error << "\n";
#else
          downloader_cat.warning()
            << "Unix error code: " << os_error << "\n";
#endif  // WIN32_VC
        }
        gbump(num_bytes);
        return EOF;
      }

      // Slide what we did read to the top of the buffer.
      nassertr(read_count < (int)num_bytes, EOF);
      size_t delta = (int)num_bytes - read_count;
      memmove(gptr() + delta, gptr(), read_count);
      gbump(delta);
    }
  }

  return (unsigned char)*gptr();
}

////////////////////////////////////////////////////////////////////
//     Function: BioStreamBuf::write_chars
//       Access: Private
//  Description: Sends some characters to the dest stream.  Does not
//               return until all characters are sent or the socket is
//               closed, even if the underlying BIO is non-blocking.
////////////////////////////////////////////////////////////////////
size_t BioStreamBuf::
write_chars(const char *start, size_t length) {
  if (length != 0) {
    size_t wrote_so_far = 0;

    int write_count = BIO_write(*_source, start, length);
    if (downloader_cat.is_spam()) {
      downloader_cat.spam()
        << "wrote " << write_count << " bytes.\n";
    }
    thread_consider_yield();
    while (write_count != (int)(length - wrote_so_far)) {
      if (write_count <= 0) {
        // http://www.openssl.org/docs/crypto/BIO_s_bio.html
        // "Calls to BIO_write() will place data in the buffer or
        // request a retry if the buffer is full."
        //
        // when the server is terminated, this seems to be the best
        // way of detecting that case on the client: a BIO write error
        // without a retry request
        //_is_closed = !BIO_should_retry(*_source);
        //_is_closed = BIO_eof(*_source);
        _is_closed = !BIO_should_write(*_source);
        if (_is_closed) {
          return wrote_so_far;
        }

        // Block on the underlying socket before we try to write some
        // more.
        int fd = -1;
        BIO_get_fd(*_source, &fd);
        if (fd < 0) {
          downloader_cat.warning()
            << "socket BIO has no file descriptor.\n";
        } else {
          if (downloader_cat.is_spam()) {
            downloader_cat.spam()
              << "waiting to write to BIO.\n";
          }
          fd_set wset;
          FD_ZERO(&wset);
          FD_SET(fd, &wset);
          select(fd + 1, NULL, &wset, NULL, NULL);
        }

      } else {
        // wrote some characters.
        wrote_so_far += write_count;
      }

      // Try to write some more.
      write_count = BIO_write(*_source, start + wrote_so_far, length - wrote_so_far);
      if (downloader_cat.is_spam()) {
        downloader_cat.spam()
          << "continued, wrote " << write_count << " bytes.\n";
      }
      thread_consider_yield();
    }
  }

  return length;
}

#endif  // HAVE_OPENSSL
<|endoftext|>


<commit_before>// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

<commit_msg>This will get it's own repo soon.<commit_after><|endoftext|>


<commit_before>// Filename: uniqueIdAllocator.cxx
// Created by:  schuyler 2003-03-13
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
//

#include "pandabase.h"
#include "pnotify.h"
#include "notifyCategoryProxy.h"

#include "uniqueIdAllocator.h"

NotifyCategoryDecl(uniqueIdAllocator, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDef(uniqueIdAllocator, "");

const PN_uint32 UniqueIdAllocator::IndexEnd = (PN_uint32)-1;
const PN_uint32 UniqueIdAllocator::IndexAllocated = (PN_uint32)-2;

#ifndef NDEBUG //[
  // Non-release build:
  #define uniqueIdAllocator_debug(msg) \
  if (uniqueIdAllocator_cat.is_debug()) { \
    uniqueIdAllocator_cat->debug() << msg << endl; \
  } else {}

  #define uniqueIdAllocator_info(msg) \
    uniqueIdAllocator_cat->info() << msg << endl

  #define uniqueIdAllocator_warning(msg) \
    uniqueIdAllocator_cat->warning() << msg << endl
#else //][
  // Release build:
  #define uniqueIdAllocator_debug(msg) ((void)0)
  #define uniqueIdAllocator_info(msg) ((void)0)
  #define uniqueIdAllocator_warning(msg) ((void)0)
#endif //]

#define audio_error(msg) \
  audio_cat->error() << msg << endl

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::Constructor
//       Access: Published
//  Description: Create a free id pool in the range [min:max].
////////////////////////////////////////////////////////////////////
UniqueIdAllocator::
UniqueIdAllocator(PN_uint32 min, PN_uint32 max)
  : _min(min), _max(max) {
  uniqueIdAllocator_debug("UniqueIdAllocator("<<min<<", "<<max<<")");

  nassertv(_max > _min);
  _size = _max-_min+1; // +1 because min and max are inclusive.
  nassertv(_size != 0); // size must be > 0.

  _table=new PN_uint32[_size];
  nassertv(_table); // This should be redundant if new throws an exception.

  for (PN_uint32 i = 0; i < _size; ++i) {
    _table[i] = i + 1;
  }
  _table[_size - 1] = IndexEnd;
  _next_free = 0;
  _last_free = _size - 1;
  _free=_size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::Destructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
UniqueIdAllocator::
~UniqueIdAllocator() {
  uniqueIdAllocator_debug("~UniqueIdAllocator()");
  delete [] _table;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::allocate
//       Access: Published
//  Description: Returns an id between _min and _max (that were passed
//               to the constructor).
//               IndexEnd is returned if no ids are available.
////////////////////////////////////////////////////////////////////
PN_uint32 UniqueIdAllocator::
allocate() {
  if (_next_free == IndexEnd) {
    // ...all ids allocated.
    uniqueIdAllocator_warning("allocate Error: no more free ids.");
    return IndexEnd;
  }
  PN_uint32 index = _next_free;
  _next_free = _table[_next_free];

  #ifndef NDEBUG //[
  nassertr(_table[index] != IndexAllocated, IndexEnd);
  _table[index] = IndexAllocated;
  #endif //]

  --_free;

  PN_uint32 id = index + _min;
  uniqueIdAllocator_debug("allocate() returning " << id);
  return id;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::initial_reserve_id
//       Access: Published
//  Description: This may be called to mark a particular id as having
//               already been allocated (for instance, by a prior
//               pass).  The specified id is removed from the
//               available pool.
//
//               Because of the limitations of this algorithm, this
//               may only be called before the first call to
//               allocate(); and all the calls to initial_reserve_id()
//               must be made in descending order by id.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
initial_reserve_id(PN_uint32 id) {
  nassertv(_next_free == 0);  // Must call before any call to allocate().
  nassertv(id >= _min && id <= _max); // Attempt to reserve out-of-range id.
  PN_uint32 index = id - _min; // Convert to _table index.

  nassertv(_table[index] != IndexAllocated);

  // Because we insist that this call be made before any calls to
  // allocate(), and in descending order, it follows that the _table
  // is still set up such that _table[i] = i+1, at least for all slots
  // <= index.  Thus, the free link to slot [index] is guaranteed to
  // be the slot right before it.

  if (index == 0) {
    _next_free = _table[index];

  } else {
    nassertv(_table[index - 1] == index);
    _table[index - 1] = _table[index];

    if (index == _last_free) {
      _last_free = index - 1;
    }
  }

  #ifndef NDEBUG //[
  _table[index] = IndexAllocated;
  #endif //]

  --_free;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::free
//       Access: Published
//  Description: Free an allocated index (index must be between _min
//               and _max that were passed to the constructor).
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
free(PN_uint32 id) {
  uniqueIdAllocator_debug("free("<<id<<")");

  nassertv(id >= _min && id <= _max); // Attempt to free out-of-range id.
  PN_uint32 index = id - _min; // Convert to _table index.
  nassertv(_table[index] == IndexAllocated); // Attempt to free non-allocated id.
  if (_next_free != IndexEnd) {
    nassertv(_table[_last_free] == IndexEnd);
    _table[_last_free] = index;
  }
  _table[index] = IndexEnd; // Mark this element as the end of the list.
  _last_free = index;

  if (_next_free == IndexEnd) {
    // ...the free list was empty.
    _next_free = index;
  }

  ++_free;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::fraction_used
//       Access: Published
//  Description: return the decimal fraction of the pool that is used.
//               The range is 0 to 1.0 (e.g. 75% would be 0.75).
////////////////////////////////////////////////////////////////////
float UniqueIdAllocator::
fraction_used() const {
  return float(_size-_free)/_size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::output
//       Access: Published
//  Description: ...intended for debugging only.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
output(ostream &out) const {
  out << "UniqueIdAllocator(" << _min << ", " << _max << "), "
      << _free << " id's remaining of " << _size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::write
//       Access: Published
//  Description: ...intended for debugging only.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
write(ostream &out) const {
  out << "_min: " << _min << "; _max: " << _max
      << ";\n_next_free: " << PN_int32(_next_free)
      << "; _last_free: " << PN_int32(_last_free)
      << "; _size: " << _size
      << "; _free: " << _free
      << "; used: " << _size - _free
      << "; fraction_used: " << fraction_used()
      << ";\n";

  out << "Table:";
  for (PN_uint32 i = 0; i < _size; ++i) {
    out << " " << PN_int32(_table[i]);
  }
  out << "\n";

  out << "Free chain:";
  PN_uint32 index = _next_free;
  while (index != IndexEnd) {
    out << " " << index + _min;
    index = _table[index];
  }
  out << "\n";
}

<commit_msg>allow 1-element UniqueIdAllocator<commit_after>// Filename: uniqueIdAllocator.cxx
// Created by:  schuyler 2003-03-13
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
//

#include "pandabase.h"
#include "pnotify.h"
#include "notifyCategoryProxy.h"

#include "uniqueIdAllocator.h"

NotifyCategoryDecl(uniqueIdAllocator, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDef(uniqueIdAllocator, "");

const PN_uint32 UniqueIdAllocator::IndexEnd = (PN_uint32)-1;
const PN_uint32 UniqueIdAllocator::IndexAllocated = (PN_uint32)-2;

#ifndef NDEBUG //[
  // Non-release build:
  #define uniqueIdAllocator_debug(msg) \
  if (uniqueIdAllocator_cat.is_debug()) { \
    uniqueIdAllocator_cat->debug() << msg << endl; \
  } else {}

  #define uniqueIdAllocator_info(msg) \
    uniqueIdAllocator_cat->info() << msg << endl

  #define uniqueIdAllocator_warning(msg) \
    uniqueIdAllocator_cat->warning() << msg << endl
#else //][
  // Release build:
  #define uniqueIdAllocator_debug(msg) ((void)0)
  #define uniqueIdAllocator_info(msg) ((void)0)
  #define uniqueIdAllocator_warning(msg) ((void)0)
#endif //]

#define audio_error(msg) \
  audio_cat->error() << msg << endl

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::Constructor
//       Access: Published
//  Description: Create a free id pool in the range [min:max].
////////////////////////////////////////////////////////////////////
UniqueIdAllocator::
UniqueIdAllocator(PN_uint32 min, PN_uint32 max)
  : _min(min), _max(max) {
  uniqueIdAllocator_debug("UniqueIdAllocator("<<min<<", "<<max<<")");

  nassertv(_max >= _min);
  _size = _max-_min+1; // +1 because min and max are inclusive.
  nassertv(_size != 0); // size must be > 0.

  _table=new PN_uint32[_size];
  nassertv(_table); // This should be redundant if new throws an exception.

  for (PN_uint32 i = 0; i < _size; ++i) {
    _table[i] = i + 1;
  }
  _table[_size - 1] = IndexEnd;
  _next_free = 0;
  _last_free = _size - 1;
  _free=_size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::Destructor
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
UniqueIdAllocator::
~UniqueIdAllocator() {
  uniqueIdAllocator_debug("~UniqueIdAllocator()");
  delete [] _table;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::allocate
//       Access: Published
//  Description: Returns an id between _min and _max (that were passed
//               to the constructor).
//               IndexEnd is returned if no ids are available.
////////////////////////////////////////////////////////////////////
PN_uint32 UniqueIdAllocator::
allocate() {
  if (_next_free == IndexEnd) {
    // ...all ids allocated.
    uniqueIdAllocator_warning("allocate Error: no more free ids.");
    return IndexEnd;
  }
  PN_uint32 index = _next_free;
  _next_free = _table[_next_free];

  #ifndef NDEBUG //[
  nassertr(_table[index] != IndexAllocated, IndexEnd);
  _table[index] = IndexAllocated;
  #endif //]

  --_free;

  PN_uint32 id = index + _min;
  uniqueIdAllocator_debug("allocate() returning " << id);
  return id;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::initial_reserve_id
//       Access: Published
//  Description: This may be called to mark a particular id as having
//               already been allocated (for instance, by a prior
//               pass).  The specified id is removed from the
//               available pool.
//
//               Because of the limitations of this algorithm, this
//               may only be called before the first call to
//               allocate(); and all the calls to initial_reserve_id()
//               must be made in descending order by id.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
initial_reserve_id(PN_uint32 id) {
  nassertv(_next_free == 0);  // Must call before any call to allocate().
  nassertv(id >= _min && id <= _max); // Attempt to reserve out-of-range id.
  PN_uint32 index = id - _min; // Convert to _table index.

  nassertv(_table[index] != IndexAllocated);

  // Because we insist that this call be made before any calls to
  // allocate(), and in descending order, it follows that the _table
  // is still set up such that _table[i] = i+1, at least for all slots
  // <= index.  Thus, the free link to slot [index] is guaranteed to
  // be the slot right before it.

  if (index == 0) {
    _next_free = _table[index];

  } else {
    nassertv(_table[index - 1] == index);
    _table[index - 1] = _table[index];

    if (index == _last_free) {
      _last_free = index - 1;
    }
  }

  #ifndef NDEBUG //[
  _table[index] = IndexAllocated;
  #endif //]

  --_free;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::free
//       Access: Published
//  Description: Free an allocated index (index must be between _min
//               and _max that were passed to the constructor).
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
free(PN_uint32 id) {
  uniqueIdAllocator_debug("free("<<id<<")");

  nassertv(id >= _min && id <= _max); // Attempt to free out-of-range id.
  PN_uint32 index = id - _min; // Convert to _table index.
  nassertv(_table[index] == IndexAllocated); // Attempt to free non-allocated id.
  if (_next_free != IndexEnd) {
    nassertv(_table[_last_free] == IndexEnd);
    _table[_last_free] = index;
  }
  _table[index] = IndexEnd; // Mark this element as the end of the list.
  _last_free = index;

  if (_next_free == IndexEnd) {
    // ...the free list was empty.
    _next_free = index;
  }

  ++_free;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::fraction_used
//       Access: Published
//  Description: return the decimal fraction of the pool that is used.
//               The range is 0 to 1.0 (e.g. 75% would be 0.75).
////////////////////////////////////////////////////////////////////
float UniqueIdAllocator::
fraction_used() const {
  return float(_size-_free)/_size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::output
//       Access: Published
//  Description: ...intended for debugging only.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
output(ostream &out) const {
  out << "UniqueIdAllocator(" << _min << ", " << _max << "), "
      << _free << " id's remaining of " << _size;
}

////////////////////////////////////////////////////////////////////
//     Function: UniqueIdAllocator::write
//       Access: Published
//  Description: ...intended for debugging only.
////////////////////////////////////////////////////////////////////
void UniqueIdAllocator::
write(ostream &out) const {
  out << "_min: " << _min << "; _max: " << _max
      << ";\n_next_free: " << PN_int32(_next_free)
      << "; _last_free: " << PN_int32(_last_free)
      << "; _size: " << _size
      << "; _free: " << _free
      << "; used: " << _size - _free
      << "; fraction_used: " << fraction_used()
      << ";\n";

  out << "Table:";
  for (PN_uint32 i = 0; i < _size; ++i) {
    out << " " << PN_int32(_table[i]);
  }
  out << "\n";

  out << "Free chain:";
  PN_uint32 index = _next_free;
  while (index != IndexEnd) {
    out << " " << index + _min;
    index = _table[index];
  }
  out << "\n";
}

<|endoftext|>


<commit_before>#include <assert.h>
#include <pkcs11.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

// Slots
#define SLOT_INVALID 9999
#define SLOT_INIT_TOKEN 0
#define SLOT_NO_INIT_TOKEN 1

// PIN
#define SLOT_0_SO1_PIN "123456"
#define SLOT_0_SO2_PIN "123456"
#define SLOT_0_USER1_PIN "123456"
#define SLOT_0_USER2_PIN "123456"

int main ( int argc, const char* argv[] )
{
	printf("Hello World\n");

	//for( int i = 0; i < argc; i++ )
	//{
	//	printf( "arg %d: %s\n", i, argv[i] );
	//}
	CK_RV rv;
	//CK_UTF8CHAR pin[] = SLOT_0_USER1_PIN;
	//CK_ULONG pinLength = sizeof(pin) - 1;
	//CK_UTF8CHAR sopin[] = SLOT_0_SO1_PIN;
	//CK_ULONG sopinLength = sizeof(sopin) - 1;
	//CK_SESSION_HANDLE hSession;

	//CK_UTF8CHAR label[32];
	//memset(label, ' ', 32);
	//memcpy(label, "token1", strlen("token1"));

	//void* sym = dlopen("/usr/lib64/libsofthsm2.so", RTLD_LAZY);

	void* sym = dlopen("/usr/lib64/opensc-pkcs11.so", RTLD_LAZY);
	assert(sym != 0);
	CK_C_GetFunctionList getFuncList = (CK_C_GetFunctionList) dlsym(sym, "C_GetFunctionList");

	CK_FUNCTION_LIST_PTR listPointer = 0;
	rv = getFuncList(&listPointer);
	assert(rv == 0);
	printf("getFuncList return: (%lu)\n", rv);

	CK_C_Initialize init = listPointer->C_Initialize;
	// (Re)initialize the token
	rv = (*init)(0);
	printf("Initializing (%lu)\n", rv);

	dlclose(sym);
}
<commit_msg>Compile defs<commit_after>#ifndef MAIN_CPP
#define MAIN_CPP

#include <assert.h>
#include <pkcs11.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>

// Slots
#define SLOT_INVALID 9999
#define SLOT_INIT_TOKEN 0
#define SLOT_NO_INIT_TOKEN 1

// PIN
#define SLOT_0_SO1_PIN "123456"
#define SLOT_0_SO2_PIN "123456"
#define SLOT_0_USER1_PIN "123456"
#define SLOT_0_USER2_PIN "123456"

int main ( int argc, const char* argv[] )
{
	printf("Hello World\n");

	//for( int i = 0; i < argc; i++ )
	//{
	//	printf( "arg %d: %s\n", i, argv[i] );
	//}
	CK_RV rv;
	//CK_UTF8CHAR pin[] = SLOT_0_USER1_PIN;
	//CK_ULONG pinLength = sizeof(pin) - 1;
	//CK_UTF8CHAR sopin[] = SLOT_0_SO1_PIN;
	//CK_ULONG sopinLength = sizeof(sopin) - 1;
	//CK_SESSION_HANDLE hSession;

	//CK_UTF8CHAR label[32];
	//memset(label, ' ', 32);
	//memcpy(label, "token1", strlen("token1"));

	void* sym = dlopen("/usr/lib64/libsofthsm2.so", RTLD_LAZY);
	//void* sym = dlopen("/usr/lib64/opensc-pkcs11.so", RTLD_LAZY);

	assert(sym != 0);
	CK_C_GetFunctionList getFuncList = (CK_C_GetFunctionList) dlsym(sym, "C_GetFunctionList");

	CK_FUNCTION_LIST_PTR listPointer = 0;
	rv = getFuncList(&listPointer);
	assert(rv == 0);
	printf("getFuncList return: (%lu)\n", rv);

	CK_C_Initialize init = listPointer->C_Initialize;
	// (Re)initialize the token
	rv = (*init)(0);
	printf("Initializing (%lu)\n", rv);

	dlclose(sym);
}

#endif /*MAIN_CPP*/
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Joyent Inc.
 * All rights reserved.
 *
 * Written by: Matthew Macy <matt.macy@joyent.com>
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/types.h>
#include <sys/endian.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <net/ethernet.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "uvxbridge.h"
#include "uvxlan.h"

static void
usage(char *name)
{
	printf("usage %s -i <ingress> -e <egress> -c <config> -m <config mac address> -p <provisioning agent mac address> [-d]\n", name);
	exit(1);
}

uint64_t
mac_parse(char *input)
{
	char *idx, *mac = strdup(input);
	const char *del = ":";
	uint8_t mac_num[8];
	int i;

	for (i = 0; ((idx = strsep(&mac, del)) != NULL) && i < ETHER_ADDR_LEN; i++)
		mac_num[i] = strtol(idx, NULL, 16);
	free(mac);
	if (i < ETHER_ADDR_LEN)
		return 0;
	return  *(uint64_t *)&mac_num;
}

int
main(int argc, char *const argv[])
{
	int ch;
	char *ingress, *egress, *config, *log;
	uint64_t pmac, cmac;
	vxstate_t state;
	bool debug = false;
	dp_args_t port_args;

	ingress = egress = config = NULL;
	pmac = cmac = 0;
	while ((ch = getopt(argc, argv, "i:e:c:m:p:l:d")) != -1) {
		switch (ch) {
			case 'i':
				ingress = optarg;
				break;
			case 'e':
				egress = optarg;
				break;
			case 'c':
				config = optarg;
				break;
			case 'p':
				pmac = mac_parse(optarg);
				break;
			case 'm':
				cmac = mac_parse(optarg);
				break;
			case 'l':
				log = optarg;
				break;
			case 'd':
				debug = true;
				break;
			case '?':
			default:
				usage(argv[0]);
		}
	}
	if (pmac == 0) {
		printf("missing provisioning agent mac address\n");
		usage(argv[0]);
	}
	if (cmac == 0) {
		printf("missing bridge configuration mac address\n");
		usage(argv[0]);
	}
	if (config == NULL) {
		printf("missing config netmap interface\n");
		usage(argv[0]);
	}
	if (ingress == NULL && !debug) {
		printf("missing ingress netmap interface\n");
		usage(argv[0]);
	}
	if (egress == NULL && !debug) {
		printf("missing egress netmap interface\n");
		usage(argv[0]);
	}
	bzero(&port_args, sizeof(dp_args_t));
	state.vs_prov_mac = pmac;
	state.vs_ctrl_mac = cmac;
	/* start datapath thread */
	/* .... */
	port_args.da_pa_name = config;
	port_args.da_pb_name = NULL;
	port_args.da_pa = &state.vs_nm_config;
	port_args.da_rx_dispatch = cmd_dispatch;
	run_datapath(&port_args, &state);
	return 0;
}
<commit_msg>add value to debug set poll_timeout<commit_after>/*
 * Copyright (C) 2017 Joyent Inc.
 * All rights reserved.
 *
 * Written by: Matthew Macy <matt.macy@joyent.com>
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/types.h>
#include <sys/endian.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <net/ethernet.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "uvxbridge.h"
#include "uvxlan.h"

int debug;

static void
usage(char *name)
{
	printf("usage %s -i <ingress> -e <egress> -c <config> -m <config mac address> -p <provisioning agent mac address> [-d <level>]\n", name);
	exit(1);
}

uint64_t
mac_parse(char *input)
{
	char *idx, *mac = strdup(input);
	const char *del = ":";
	uint8_t mac_num[8];
	int i;

	for (i = 0; ((idx = strsep(&mac, del)) != NULL) && i < ETHER_ADDR_LEN; i++)
		mac_num[i] = strtol(idx, NULL, 16);
	free(mac);
	if (i < ETHER_ADDR_LEN)
		return 0;
	return  *(uint64_t *)&mac_num;
}

int
main(int argc, char *const argv[])
{
	int ch;
	char *ingress, *egress, *config, *log;
	uint64_t pmac, cmac;
	vxstate_t state;
	dp_args_t port_args;

	ingress = egress = config = NULL;
	pmac = cmac = 0;
	while ((ch = getopt(argc, argv, "i:e:c:m:p:l:d:")) != -1) {
		switch (ch) {
			case 'i':
				ingress = optarg;
				break;
			case 'e':
				egress = optarg;
				break;
			case 'c':
				config = optarg;
				break;
			case 'p':
				pmac = mac_parse(optarg);
				break;
			case 'm':
				cmac = mac_parse(optarg);
				break;
			case 'l':
				log = optarg;
				break;
			case 'd':
				debug = strtol(optarg, NULL, 10);
				break;
			case '?':
			default:
				usage(argv[0]);
		}
	}
	if (pmac == 0) {
		printf("missing provisioning agent mac address\n");
		usage(argv[0]);
	}
	if (cmac == 0) {
		printf("missing bridge configuration mac address\n");
		usage(argv[0]);
	}
	if (config == NULL) {
		printf("missing config netmap interface\n");
		usage(argv[0]);
	}
	if (ingress == NULL && !debug) {
		printf("missing ingress netmap interface\n");
		usage(argv[0]);
	}
	if (egress == NULL && !debug) {
		printf("missing egress netmap interface\n");
		usage(argv[0]);
	}
	bzero(&port_args, sizeof(dp_args_t));
	state.vs_prov_mac = pmac;
	state.vs_ctrl_mac = cmac;
	/* start datapath thread */
	/* .... */
	port_args.da_pa_name = config;
	port_args.da_pb_name = NULL;
	port_args.da_pa = &state.vs_nm_config;
	port_args.da_rx_dispatch = cmd_dispatch;
	port_args.da_poll_timeout = 2500;
	run_datapath(&port_args, &state);
	return 0;
}
<|endoftext|>


<commit_before>// ceres_surface.cpp

// Includes
#include "ceres_surface.h"

#include <algorithm>
#include "ceres/internal/fixed_array.h"

// SurfaceCostFunction
SurfaceCostFunction::SurfaceCostFunction(const Surface* surface)
    : surface_(surface) {
  mutable_parameter_block_sizes()->push_back(2);
  for (int i = 0; i < surface_->number_of_vertices(); ++i) {
    mutable_parameter_block_sizes()->push_back(3);
  }

  set_num_residuals(3);
}

bool SurfaceCostFunction::Evaluate(const double* const* x,
                                   double* e, double** J) const {
  // `u` and `alpha` are taken from input parameters `x`.
  double u[2] = {x[0][0], x[0][1]};
  const int p = DecodePatchIndexInPlace(u);
  CHECK_GE(p, 0);
  CHECK_LT(p, surface_->number_of_patches());
  CHECK_GE(u[0], 0.0);
  CHECK_LE(u[0], 1.0);
  CHECK_GE(u[1], 0.0);
  CHECK_LE(u[1], 1.0);

  // Get the patch vertex indices.
  auto& patch_vertex_indices = surface_->patch_vertex_indices(p);
  const int num_patch_vertices = static_cast<int>(patch_vertex_indices.size());

  // Construct `Xp`; the array of pointers to the patch vertices.
  ceres::internal::FixedArray<const double*> Xp(num_patch_vertices);
  for (int i = 0; i < num_patch_vertices; ++i) {
    Xp[i] = x[1 + patch_vertex_indices[i]];
  }

  // Can exit early when no Jacobian is required.
  if (J == nullptr) {
    return EvaluateImpl(p, u, Xp.get(), e, nullptr);
  }

  // Otherwise, construct Jacobian data, but write Jacobian for `u`
  // directly into the output Jacobian.
  ceres::internal::FixedArray<double> Jp_data(3 * 3 * num_patch_vertices);
  ceres::internal::FixedArray<double*> Jp(1 + num_patch_vertices);
  Jp[0] = J[0];
  for (int i = 0; i < num_patch_vertices; ++i) {
    Jp[i + 1] = Jp_data.get() + num_residuals() * 3 * i;
  }

  if (!EvaluateImpl(p, u, Xp.get(), e, Jp.get())) {
    return false;
  }

  // Copy the relevant entries in the output.
  for (int i = 0; i < surface_->number_of_vertices(); ++i) {
    if (J[1 + i] != nullptr) {
      std::fill(J[1 + i], J[1 + i] + num_residuals() * 3, 0.0);
    }
  }

  for (int i = 0; i < num_patch_vertices; ++i) {
    if (J[1 + patch_vertex_indices[i]] != nullptr) {
      std::copy(Jp[i + 1], Jp[i + 1] + num_residuals() * 3,
                J[1 + patch_vertex_indices[i]]);
    }
  }
  return true;
}

// SurfacePositionCostFunction
SurfacePositionCostFunction::SurfacePositionCostFunction(
  const Surface* surface)
    : SurfaceCostFunction(surface)
  {}

bool SurfacePositionCostFunction::EvaluateImpl(const int p,
                                               const double* u,
                                               const double* const* X,
                                               double* r,
                                               double** J) const {
  surface_->M(r, p, u, X);

  if (J != nullptr) {
    if (J[0] != nullptr) {
      double Ju[3], Jv[3];
      surface_->Mu(Ju, p, u, X);
      surface_->Mv(Jv, p, u, X);
      J[0][0] = Ju[0]; J[0][1] = Jv[0];
      J[0][2] = Ju[1]; J[0][3] = Jv[1];
      J[0][4] = Ju[2]; J[0][5] = Jv[2];
    }

    const int num_patch_vertices = surface_->patch_vertex_indices(p).size();
    ceres::internal::FixedArray<double> Mx(3 * 3 * num_patch_vertices);
    double* Mx_data = Mx.begin();
    surface_->Mx(Mx_data, p, u);

    for (int i = 0; i < num_patch_vertices; ++i) {
      if (J[i + 1] != nullptr) {
        std::copy(Mx_data + 9 * i, Mx_data + 9 * (i + 1), J[i + 1]);
      }
    }
  }

  return true;
}
<commit_msg>Further clean-up of `SurfaceCostFunction::Evaluate` in src/ceres_surface.cpp<commit_after>// ceres_surface.cpp

// Includes
#include "ceres_surface.h"

#include <algorithm>
#include "ceres/internal/fixed_array.h"

// SurfaceCostFunction
SurfaceCostFunction::SurfaceCostFunction(const Surface* surface)
    : surface_(surface) {
  mutable_parameter_block_sizes()->push_back(2);
  for (int i = 0; i < surface_->number_of_vertices(); ++i) {
    mutable_parameter_block_sizes()->push_back(3);
  }

  set_num_residuals(3);
}

bool SurfaceCostFunction::Evaluate(const double* const* x,
                                   double* e, double** J) const {
  // `u` and `alpha` are taken from input parameters `x`.
  double u[2] = {x[0][0], x[0][1]};
  const int p = DecodePatchIndexInPlace(u);
  CHECK_GE(p, 0);
  CHECK_LT(p, surface_->number_of_patches());
  CHECK_GE(u[0], 0.0);
  CHECK_LE(u[0], 1.0);
  CHECK_GE(u[1], 0.0);
  CHECK_LE(u[1], 1.0);

  // Get the patch vertex indices.
  auto& patch_vertex_indices = surface_->patch_vertex_indices(p);
  const int num_patch_vertices = static_cast<int>(patch_vertex_indices.size());

  // Construct `Xp`; the array of pointers to the patch vertices.
  ceres::internal::FixedArray<const double*> Xp(num_patch_vertices);
  for (int i = 0; i < num_patch_vertices; ++i) {
    Xp[i] = x[1 + patch_vertex_indices[i]];
  }

  // Can exit early when no Jacobian is required.
  if (J == nullptr) {
    return EvaluateImpl(p, u, Xp.get(), e, nullptr);
  }

  // Set Jacobians for *all* vertices (initially) to zero.
  for (int i = 0; i < surface_->number_of_vertices(); ++i) {
    if (J[1 + i] != nullptr) {
      std::fill(J[1 + i], J[1 + i] + num_residuals() * 3, 0.0);
    }
  }

  // Construct `Jp`; the array of poitns to the Jacobians.
  ceres::internal::FixedArray<double*> Jp(1 + num_patch_vertices);
  Jp[0] = J[0];
  for (int i = 0; i < num_patch_vertices; ++i) {
    Jp[i + 1] = J[1 + patch_vertex_indices[i]];
  }

  return EvaluateImpl(p, u, Xp.get(), e, Jp.get());
}

// SurfacePositionCostFunction
SurfacePositionCostFunction::SurfacePositionCostFunction(
  const Surface* surface)
    : SurfaceCostFunction(surface)
  {}

bool SurfacePositionCostFunction::EvaluateImpl(const int p,
                                               const double* u,
                                               const double* const* X,
                                               double* r,
                                               double** J) const {
  surface_->M(r, p, u, X);

  if (J != nullptr) {
    if (J[0] != nullptr) {
      double Ju[3], Jv[3];
      surface_->Mu(Ju, p, u, X);
      surface_->Mv(Jv, p, u, X);
      J[0][0] = Ju[0]; J[0][1] = Jv[0];
      J[0][2] = Ju[1]; J[0][3] = Jv[1];
      J[0][4] = Ju[2]; J[0][5] = Jv[2];
    }

    const int num_patch_vertices = surface_->patch_vertex_indices(p).size();
    ceres::internal::FixedArray<double> Mx(3 * 3 * num_patch_vertices);
    double* Mx_data = Mx.begin();
    surface_->Mx(Mx_data, p, u);

    for (int i = 0; i < num_patch_vertices; ++i) {
      if (J[i + 1] != nullptr) {
        std::copy(Mx_data + 9 * i, Mx_data + 9 * (i + 1), J[i + 1]);
      }
    }
  }

  return true;
}
<|endoftext|>