<commit_before>/* This file is part of the KDE project
   Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
   Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "kwrite.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>
#include <ktexteditor/editor.h>

#include <KAboutData>
#include <KLocalizedString>
#include <KMessageBox>
#include <KDBusService>

#include <QCommandLineParser>
#include <QApplication>
#include <QTextCodec>
#include <QFileInfo>
#include <QDir>

extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
{
    /**
     * first init the app
     */
    QApplication app(argc, argv);

    /**
     * enable high dpi support
     */
    app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);

    /**
     * Connect application with translation catalogs
     */
    KLocalizedString::setApplicationDomain("kwrite");

    /**
     * then use i18n and co
     */
    KAboutData aboutData(QStringLiteral("kwrite"),
                         i18n("KWrite"),
                         QStringLiteral(KATE_VERSION),
                         i18n("KWrite - Text Editor"), KAboutLicense::LGPL_V2,
                         i18n("(c) 2000-2014 The Kate Authors"), QString(), QStringLiteral("http://kate-editor.org"));

    /**
     * right dbus prefix == org.kde.
     */
    aboutData.setOrganizationDomain(QByteArray("kde.org"));

    aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("http://www.cullmann.io"));
    aboutData.addAuthor(i18n("Anders Lund"), i18n("Core Developer"), QStringLiteral("anders@alweb.dk"), QStringLiteral("http://www.alweb.dk"));
    aboutData.addAuthor(i18n("Joseph Wenninger"), i18n("Core Developer"), QStringLiteral("jowenn@kde.org"), QStringLiteral("http://stud3.tuwien.ac.at/~e9925371"));
    aboutData.addAuthor(i18n("Hamish Rodda"), i18n("Core Developer"), QStringLiteral("rodda@kde.org"));
    aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Developer & Highlight wizard"), QStringLiteral("dhdev@gmx.de"));
    aboutData.addAuthor(i18n("Waldo Bastian"), i18n("The cool buffersystem"), QStringLiteral("bastian@kde.org"));
    aboutData.addAuthor(i18n("Charles Samuels"), i18n("The Editing Commands"), QStringLiteral("charles@kde.org"));
    aboutData.addAuthor(i18n("Matt Newell"), i18nc("Credit text for someone that did testing and some other similar things", "Testing, ..."), QStringLiteral("newellm@proaxis.com"));
    aboutData.addAuthor(i18n("Michael Bartl"), i18n("Former Core Developer"), QStringLiteral("michael.bartl1@chello.at"));
    aboutData.addAuthor(i18n("Michael McCallum"), i18n("Core Developer"), QStringLiteral("gholam@xtra.co.nz"));
    aboutData.addAuthor(i18n("Jochen Wilhemly"), i18n("KWrite Author"), QStringLiteral("digisnap@cs.tu-berlin.de"));
    aboutData.addAuthor(i18n("Michael Koch"), i18n("KWrite port to KParts"), QStringLiteral("koch@kde.org"));
    aboutData.addAuthor(i18n("Christian Gebauer"), QString(), QStringLiteral("gebauer@kde.org"));
    aboutData.addAuthor(i18n("Simon Hausmann"), QString(), QStringLiteral("hausmann@kde.org"));
    aboutData.addAuthor(i18n("Glen Parker"), i18n("KWrite Undo History, Kspell integration"), QStringLiteral("glenebob@nwlink.com"));
    aboutData.addAuthor(i18n("Scott Manson"), i18n("KWrite XML Syntax highlighting support"), QStringLiteral("sdmanson@alltel.net"));
    aboutData.addAuthor(i18n("John Firebaugh"), i18n("Patches and more"), QStringLiteral("jfirebaugh@kde.org"));
    aboutData.addAuthor(i18n("Gerald Senarclens de Grancy"), i18n("QA and Scripting"), QStringLiteral("oss@senarclens.eu"), QStringLiteral("http://find-santa.eu/"));

    aboutData.addCredit(i18n("Matteo Merli"), i18n("Highlighting for RPM Spec-Files, Perl, Diff and more"), QStringLiteral("merlim@libero.it"));
    aboutData.addCredit(i18n("Rocky Scaletta"), i18n("Highlighting for VHDL"), QStringLiteral("rocky@purdue.edu"));
    aboutData.addCredit(i18n("Yury Lebedev"), i18n("Highlighting for SQL"));
    aboutData.addCredit(i18n("Chris Ross"), i18n("Highlighting for Ferite"));
    aboutData.addCredit(i18n("Nick Roux"), i18n("Highlighting for ILERPG"));
    aboutData.addCredit(i18n("Carsten Niehaus"), i18n("Highlighting for LaTeX"));
    aboutData.addCredit(i18n("Per Wigren"), i18n("Highlighting for Makefiles, Python"));
    aboutData.addCredit(i18n("Jan Fritz"), i18n("Highlighting for Python"));
    aboutData.addCredit(i18n("Daniel Naber"));
    aboutData.addCredit(i18n("Roland Pabel"), i18n("Highlighting for Scheme"));
    aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("PHP Keyword/Datatype list"));
    aboutData.addCredit(i18n("Carsten Pfeiffer"), i18nc("Credit text for someone that helped a lot", "Very nice help"));
    aboutData.addCredit(i18n("All people who have contributed and I have forgotten to mention"));

    /**
     * bugzilla
     */
    aboutData.setProductName(QByteArray("kate/kwrite"));

    /**
     * register about data
     */
    KAboutData::setApplicationData(aboutData);

    /**
     * set app stuff from about data component name and org. name from KAboutData
     */
    app.setApplicationName(aboutData.componentName());
    app.setApplicationDisplayName(aboutData.displayName());
    app.setOrganizationDomain(aboutData.organizationDomain());
    app.setApplicationVersion(aboutData.version());

    /**
     * set the program icon
     */
    QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("accessories-text-editor")));

    /**
     * Create command line parser and feed it with known options
     */
    QCommandLineParser parser;
    aboutData.setupCommandLine(&parser);
    parser.setApplicationDescription(aboutData.shortDescription());
    parser.addHelpOption();
    parser.addVersionOption();

    // -e/--encoding option
    const QCommandLineOption useEncoding(QStringList() << QStringLiteral("e") << QStringLiteral("encoding"), i18n("Set encoding for the file to open."), QStringLiteral("encoding"));
    parser.addOption(useEncoding);

    // -l/--line option
    const QCommandLineOption gotoLine(QStringList() << QStringLiteral("l") << QStringLiteral("line"), i18n("Navigate to this line."), QStringLiteral("line"));
    parser.addOption(gotoLine);

    // -c/--column option
    const QCommandLineOption gotoColumn(QStringList() << QStringLiteral("c") << QStringLiteral("column"), i18n("Navigate to this column."), QStringLiteral("column"));
    parser.addOption(gotoColumn);

    // -i/--stdin option
    const QCommandLineOption readStdIn(QStringList() << QStringLiteral("i") << QStringLiteral("stdin"), i18n("Read the contents of stdin."));
    parser.addOption(readStdIn);

    // --tempfile option
    const QCommandLineOption tempfile(QStringList() << QStringLiteral("tempfile"), i18n("The files/URLs opened by the application will be deleted after use"));
    parser.addOption(tempfile);

    // urls to open
    parser.addPositionalArgument(QStringLiteral("urls"), i18n("Documents to open."), QStringLiteral("[urls...]"));

    /**
     * do the command line parsing
     */
    parser.process(app);

    /**
     * handle standard options
     */
    aboutData.processCommandLine(&parser);

    if (app.isSessionRestored()) {
        KWrite::restore();
    } else {
        bool nav = false;
        int line = 0, column = 0;

        QTextCodec *codec = parser.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(parser.value(QStringLiteral("encoding")).toLocal8Bit()) : 0;

        if (parser.isSet(QStringLiteral("line"))) {
            line = parser.value(QStringLiteral("line")).toInt() - 1;
            nav = true;
        }

        if (parser.isSet(QStringLiteral("column"))) {
            column = parser.value(QStringLiteral("column")).toInt() - 1;
            nav = true;
        }

        if (parser.positionalArguments().count() == 0) {
            KWrite *t = new KWrite;

            if (parser.isSet(QStringLiteral("stdin"))) {
                QTextStream input(stdin, QIODevice::ReadOnly);

                // set chosen codec
                if (codec) {
                    input.setCodec(codec);
                }

                QString line;
                QString text;

                do {
                    line = input.readLine();
                    text.append(line + QLatin1Char('\n'));
                } while (!line.isNull());

                KTextEditor::Document *doc = t->view()->document();
                if (doc) {
                    doc->setText(text);
                }
            }

            if (nav && t->view()) {
                t->view()->setCursorPosition(KTextEditor::Cursor(line, column));
            }
        } else {
            int docs_opened = 0;
            Q_FOREACH(const QString positionalArgument, parser.positionalArguments()) {
                QUrl url;

                // convert to an url
                QRegExp withProtocol(QStringLiteral("^[a-zA-Z]+:")); // TODO: remove after Qt supports this on its own
                if (withProtocol.indexIn(positionalArgument) == 0) {
                    url = QUrl::fromUserInput(positionalArgument);
                } else {
                    url = QUrl::fromLocalFile(positionalArgument);
                }

                // this file is no local dir, open it, else warn
                bool noDir = !url.isLocalFile() || !QFileInfo(url.toLocalFile()).isDir();

                if (noDir) {
                    ++docs_opened;
                    KWrite *t = new KWrite();

                    if (codec) {
                        t->view()->document()->setEncoding(QString::fromLatin1(codec->name()));
                    }

                    t->loadURL(url);

                    if (nav) {
                        t->view()->setCursorPosition(KTextEditor::Cursor(line, column));
                    }
                } else {
                    KMessageBox::sorry(0, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", url.toString()));
                }
            }
            if (!docs_opened) {
                ::exit(1);    // see http://bugs.kde.org/show_bug.cgi?id=124708
            }
        }
    }

    // no window there, uh, ohh, for example borked session config !!!
    // create at least one !!
    if (KWrite::noWindows()) {
        new KWrite();
    }

    /**
     * finally register this kwrite instance for dbus
     */
    const KDBusService dbusService(KDBusService::Multiple);

    /**
     * Run the event loop
     */
    return app.exec();
}
<commit_msg>bumping another year<commit_after>/* This file is part of the KDE project
   Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
   Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "kwrite.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>
#include <ktexteditor/editor.h>

#include <KAboutData>
#include <KLocalizedString>
#include <KMessageBox>
#include <KDBusService>

#include <QCommandLineParser>
#include <QApplication>
#include <QTextCodec>
#include <QFileInfo>
#include <QDir>

extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
{
    /**
     * first init the app
     */
    QApplication app(argc, argv);

    /**
     * enable high dpi support
     */
    app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);

    /**
     * Connect application with translation catalogs
     */
    KLocalizedString::setApplicationDomain("kwrite");

    /**
     * then use i18n and co
     */
    KAboutData aboutData(QStringLiteral("kwrite"),
                         i18n("KWrite"),
                         QStringLiteral(KATE_VERSION),
                         i18n("KWrite - Text Editor"), KAboutLicense::LGPL_V2,
                         i18n("(c) 2000-2015 The Kate Authors"), QString(), QStringLiteral("http://kate-editor.org"));

    /**
     * right dbus prefix == org.kde.
     */
    aboutData.setOrganizationDomain(QByteArray("kde.org"));

    aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("http://www.cullmann.io"));
    aboutData.addAuthor(i18n("Anders Lund"), i18n("Core Developer"), QStringLiteral("anders@alweb.dk"), QStringLiteral("http://www.alweb.dk"));
    aboutData.addAuthor(i18n("Joseph Wenninger"), i18n("Core Developer"), QStringLiteral("jowenn@kde.org"), QStringLiteral("http://stud3.tuwien.ac.at/~e9925371"));
    aboutData.addAuthor(i18n("Hamish Rodda"), i18n("Core Developer"), QStringLiteral("rodda@kde.org"));
    aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Developer & Highlight wizard"), QStringLiteral("dhdev@gmx.de"));
    aboutData.addAuthor(i18n("Waldo Bastian"), i18n("The cool buffersystem"), QStringLiteral("bastian@kde.org"));
    aboutData.addAuthor(i18n("Charles Samuels"), i18n("The Editing Commands"), QStringLiteral("charles@kde.org"));
    aboutData.addAuthor(i18n("Matt Newell"), i18nc("Credit text for someone that did testing and some other similar things", "Testing, ..."), QStringLiteral("newellm@proaxis.com"));
    aboutData.addAuthor(i18n("Michael Bartl"), i18n("Former Core Developer"), QStringLiteral("michael.bartl1@chello.at"));
    aboutData.addAuthor(i18n("Michael McCallum"), i18n("Core Developer"), QStringLiteral("gholam@xtra.co.nz"));
    aboutData.addAuthor(i18n("Jochen Wilhemly"), i18n("KWrite Author"), QStringLiteral("digisnap@cs.tu-berlin.de"));
    aboutData.addAuthor(i18n("Michael Koch"), i18n("KWrite port to KParts"), QStringLiteral("koch@kde.org"));
    aboutData.addAuthor(i18n("Christian Gebauer"), QString(), QStringLiteral("gebauer@kde.org"));
    aboutData.addAuthor(i18n("Simon Hausmann"), QString(), QStringLiteral("hausmann@kde.org"));
    aboutData.addAuthor(i18n("Glen Parker"), i18n("KWrite Undo History, Kspell integration"), QStringLiteral("glenebob@nwlink.com"));
    aboutData.addAuthor(i18n("Scott Manson"), i18n("KWrite XML Syntax highlighting support"), QStringLiteral("sdmanson@alltel.net"));
    aboutData.addAuthor(i18n("John Firebaugh"), i18n("Patches and more"), QStringLiteral("jfirebaugh@kde.org"));
    aboutData.addAuthor(i18n("Gerald Senarclens de Grancy"), i18n("QA and Scripting"), QStringLiteral("oss@senarclens.eu"), QStringLiteral("http://find-santa.eu/"));

    aboutData.addCredit(i18n("Matteo Merli"), i18n("Highlighting for RPM Spec-Files, Perl, Diff and more"), QStringLiteral("merlim@libero.it"));
    aboutData.addCredit(i18n("Rocky Scaletta"), i18n("Highlighting for VHDL"), QStringLiteral("rocky@purdue.edu"));
    aboutData.addCredit(i18n("Yury Lebedev"), i18n("Highlighting for SQL"));
    aboutData.addCredit(i18n("Chris Ross"), i18n("Highlighting for Ferite"));
    aboutData.addCredit(i18n("Nick Roux"), i18n("Highlighting for ILERPG"));
    aboutData.addCredit(i18n("Carsten Niehaus"), i18n("Highlighting for LaTeX"));
    aboutData.addCredit(i18n("Per Wigren"), i18n("Highlighting for Makefiles, Python"));
    aboutData.addCredit(i18n("Jan Fritz"), i18n("Highlighting for Python"));
    aboutData.addCredit(i18n("Daniel Naber"));
    aboutData.addCredit(i18n("Roland Pabel"), i18n("Highlighting for Scheme"));
    aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("PHP Keyword/Datatype list"));
    aboutData.addCredit(i18n("Carsten Pfeiffer"), i18nc("Credit text for someone that helped a lot", "Very nice help"));
    aboutData.addCredit(i18n("All people who have contributed and I have forgotten to mention"));

    /**
     * bugzilla
     */
    aboutData.setProductName(QByteArray("kate/kwrite"));

    /**
     * register about data
     */
    KAboutData::setApplicationData(aboutData);

    /**
     * set app stuff from about data component name and org. name from KAboutData
     */
    app.setApplicationName(aboutData.componentName());
    app.setApplicationDisplayName(aboutData.displayName());
    app.setOrganizationDomain(aboutData.organizationDomain());
    app.setApplicationVersion(aboutData.version());

    /**
     * set the program icon
     */
    QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("accessories-text-editor")));

    /**
     * Create command line parser and feed it with known options
     */
    QCommandLineParser parser;
    aboutData.setupCommandLine(&parser);
    parser.setApplicationDescription(aboutData.shortDescription());
    parser.addHelpOption();
    parser.addVersionOption();

    // -e/--encoding option
    const QCommandLineOption useEncoding(QStringList() << QStringLiteral("e") << QStringLiteral("encoding"), i18n("Set encoding for the file to open."), QStringLiteral("encoding"));
    parser.addOption(useEncoding);

    // -l/--line option
    const QCommandLineOption gotoLine(QStringList() << QStringLiteral("l") << QStringLiteral("line"), i18n("Navigate to this line."), QStringLiteral("line"));
    parser.addOption(gotoLine);

    // -c/--column option
    const QCommandLineOption gotoColumn(QStringList() << QStringLiteral("c") << QStringLiteral("column"), i18n("Navigate to this column."), QStringLiteral("column"));
    parser.addOption(gotoColumn);

    // -i/--stdin option
    const QCommandLineOption readStdIn(QStringList() << QStringLiteral("i") << QStringLiteral("stdin"), i18n("Read the contents of stdin."));
    parser.addOption(readStdIn);

    // --tempfile option
    const QCommandLineOption tempfile(QStringList() << QStringLiteral("tempfile"), i18n("The files/URLs opened by the application will be deleted after use"));
    parser.addOption(tempfile);

    // urls to open
    parser.addPositionalArgument(QStringLiteral("urls"), i18n("Documents to open."), QStringLiteral("[urls...]"));

    /**
     * do the command line parsing
     */
    parser.process(app);

    /**
     * handle standard options
     */
    aboutData.processCommandLine(&parser);

    if (app.isSessionRestored()) {
        KWrite::restore();
    } else {
        bool nav = false;
        int line = 0, column = 0;

        QTextCodec *codec = parser.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(parser.value(QStringLiteral("encoding")).toLocal8Bit()) : 0;

        if (parser.isSet(QStringLiteral("line"))) {
            line = parser.value(QStringLiteral("line")).toInt() - 1;
            nav = true;
        }

        if (parser.isSet(QStringLiteral("column"))) {
            column = parser.value(QStringLiteral("column")).toInt() - 1;
            nav = true;
        }

        if (parser.positionalArguments().count() == 0) {
            KWrite *t = new KWrite;

            if (parser.isSet(QStringLiteral("stdin"))) {
                QTextStream input(stdin, QIODevice::ReadOnly);

                // set chosen codec
                if (codec) {
                    input.setCodec(codec);
                }

                QString line;
                QString text;

                do {
                    line = input.readLine();
                    text.append(line + QLatin1Char('\n'));
                } while (!line.isNull());

                KTextEditor::Document *doc = t->view()->document();
                if (doc) {
                    doc->setText(text);
                }
            }

            if (nav && t->view()) {
                t->view()->setCursorPosition(KTextEditor::Cursor(line, column));
            }
        } else {
            int docs_opened = 0;
            Q_FOREACH(const QString positionalArgument, parser.positionalArguments()) {
                QUrl url;

                // convert to an url
                QRegExp withProtocol(QStringLiteral("^[a-zA-Z]+:")); // TODO: remove after Qt supports this on its own
                if (withProtocol.indexIn(positionalArgument) == 0) {
                    url = QUrl::fromUserInput(positionalArgument);
                } else {
                    url = QUrl::fromLocalFile(positionalArgument);
                }

                // this file is no local dir, open it, else warn
                bool noDir = !url.isLocalFile() || !QFileInfo(url.toLocalFile()).isDir();

                if (noDir) {
                    ++docs_opened;
                    KWrite *t = new KWrite();

                    if (codec) {
                        t->view()->document()->setEncoding(QString::fromLatin1(codec->name()));
                    }

                    t->loadURL(url);

                    if (nav) {
                        t->view()->setCursorPosition(KTextEditor::Cursor(line, column));
                    }
                } else {
                    KMessageBox::sorry(0, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", url.toString()));
                }
            }
            if (!docs_opened) {
                ::exit(1);    // see http://bugs.kde.org/show_bug.cgi?id=124708
            }
        }
    }

    // no window there, uh, ohh, for example borked session config !!!
    // create at least one !!
    if (KWrite::noWindows()) {
        new KWrite();
    }

    /**
     * finally register this kwrite instance for dbus
     */
    const KDBusService dbusService(KDBusService::Multiple);

    /**
     * Run the event loop
     */
    return app.exec();
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* system headers */
#include <iostream>
#include <string>
#include <vector>
#include <map>

/* common headers */
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"
#include "OSFile.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
#  ifdef INSTALL_LIB_DIR
std::string globalPluginDir = INSTALL_LIB_DIR;
#  else
std::string globalPluginDir = ".";
#  endif
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
  std::string foundPath;
  std::string plugin;

#ifdef _WIN32
  HINSTANCE	handle;
#else
  void*		handle;
#endif
}trPluginRecord;

std::vector<trPluginRecord>	vPluginList;

typedef enum
  {
    eLoadFailedDupe = -1,
    eLoadFailedError = 0,
    eLoadFailedRuntime,
    eLoadComplete
  }PluginLoadReturn;

bool pluginExists ( std::string plugin )
{
  for ( int i = 0; i < (int)vPluginList.size(); i++ ) {
    if ( vPluginList[i].foundPath == plugin )
      return true;
  }
  return false;
}

std::string findPlugin ( std::string pluginName )
{
  // see if we can just open the bloody thing
  FILE	*fp = fopen(pluginName.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return pluginName;
  }

  // now try it with the standard extension
  std::string name = pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  // check the local users plugins dir
  name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  // check the global plugins dir
  name = globalPluginDir + pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  return std::string("");
}

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#  include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
  int (*lpProc)(void);
  lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
  if (lpProc)
    return lpProc();
  return 0;
}

PluginLoadReturn load1Plugin ( std::string plugin, std::string config )
{
  int (*lpProc)(const char*);

  std::string realPluginName = findPlugin(plugin);
  if (pluginExists(realPluginName)) {
    logDebugMessage(1,"LoadPlugin failed: %s is already loaded\n",realPluginName.c_str());
    return eLoadFailedDupe;
  }

  HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
  if (hLib) {
    if (getPluginVersion(hLib) > BZ_API_VERSION) {
      logDebugMessage(1,"Plugin:%s found but expects an newer API version (%d), upgrade your bzfs\n",plugin.c_str(),getPluginVersion(hLib));
      FreeLibrary(hLib);
      return eLoadFailedError;
    } else {
      lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
      if (lpProc) {
	if (lpProc(config.c_str())!= 0) {
	  logDebugMessage(1,"Plugin:%s found but bz_Load returned an error\n",plugin.c_str());
	  FreeLibrary(hLib);
	  return eLoadFailedRuntime;
	}
	logDebugMessage(1,"Plugin:%s loaded\n",plugin.c_str());

	trPluginRecord pluginRecord;
	pluginRecord.foundPath = realPluginName;
	pluginRecord.handle = hLib;
	pluginRecord.plugin = plugin;
	vPluginList.push_back(pluginRecord);
      } else {
	logDebugMessage(1,"Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
	FreeLibrary(hLib);
	return eLoadFailedError;
      }
    }
  } else {
    logDebugMessage(1,"Plugin:%s not found\n",plugin.c_str());
    return eLoadFailedError;
  }

  return eLoadComplete;
}

void unload1Plugin ( int iPluginID )
{
  int (*lpProc)(void);

  trPluginRecord &plugin = vPluginList[iPluginID];
  if (!plugin.handle)
    return;

  lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
  if (lpProc)
    lpProc();
  else
    logDebugMessage(1,"Plugin does not contain bz_UnLoad method\n");

  FreeLibrary(plugin.handle);
  plugin.handle = NULL;
  plugin.foundPath = "";
  plugin.plugin = "";
}
#else

#  include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
  int (*lpProc)(void);

  lpProc = force_cast<int (*)(void)>(dlsym(hLib,"bz_GetVersion"));
  if (lpProc)
    return (*lpProc)();
  return 0;
}

PluginLoadReturn load1Plugin ( std::string plugin, std::string config )
{
  int (*lpProc)(const char*);

  std::string realPluginName = findPlugin(plugin);

  if (pluginExists(realPluginName)) {
    logDebugMessage(1,"LoadPlugin failed: %s is already loaded\n",realPluginName.c_str());
    return eLoadFailedDupe;
  }

  void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
  if (hLib) {
    if (dlsym(hLib, "bz_Load") == NULL) {
      logDebugMessage(1,"Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
      dlclose(hLib);
      return eLoadFailedError;
    }

    int version = getPluginVersion(hLib);
    if (version < BZ_API_VERSION) {
      logDebugMessage(1,"Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
      dlclose(hLib);
      return eLoadFailedError;
    } else {
      lpProc = force_cast<int (*)(const char*)>(dlsym(hLib,"bz_Load"));
      if (lpProc) {
	if((*lpProc)(config.c_str())) {
	  logDebugMessage(1,"Plugin:%s found but bz_Load returned an error\n",plugin.c_str());
	  return eLoadFailedRuntime;
	}
	logDebugMessage(1,"Plugin:%s loaded\n",plugin.c_str());
	trPluginRecord pluginRecord;
	pluginRecord.handle = hLib;
	pluginRecord.plugin = plugin;
	vPluginList.push_back(pluginRecord);
	return eLoadComplete;
      }
    }
  } else {
    logDebugMessage(1,"Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
    return eLoadFailedError;
  }

  logDebugMessage(1,"If you see this, there is something terribly wrong.\n");
  return eLoadFailedError;
}

void unload1Plugin ( int iPluginID )
{
  int (*lpProc)(void);
  trPluginRecord &plugin = vPluginList[iPluginID];

  if(!plugin.handle)
    return;

  lpProc = force_cast<int (*)(void)>(dlsym(plugin.handle, "bz_Unload"));
  if (lpProc)
    (*lpProc)();
  else
    logDebugMessage(1,"Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

  dlclose(plugin.handle);
  plugin.handle = NULL;
  plugin.foundPath = "";
  plugin.plugin = "";

}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
  // check and see if it's an extension we have a handler for
  std::string ext;

  std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
  ext = parts[parts.size()-1];

  tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

  if (itr != customPluginMap.end() && itr->second) {
    bz_APIPluginHandler *handler = itr->second;
    return handler->handle(plugin,config);
  }
  else
    return load1Plugin(plugin,config) == eLoadComplete;
}

bool unloadPlugin ( std::string plugin )
{
  // unload the first one of the name we find
  for (unsigned int i = 0; i < vPluginList.size();i++) {
    if ( vPluginList[i].plugin == plugin ) {
      unload1Plugin(i);
      vPluginList.erase(vPluginList.begin()+i);
      return true;
    }
  }
  return false;
}

void unloadPlugins ( void )
{
  for (unsigned int i = 0; i < vPluginList.size();i++)
    unload1Plugin(i);
  vPluginList.clear();

  removeCustomSlashCommand("loadplugin");
  removeCustomSlashCommand("unloadplugin");
  removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
  std::vector<std::string> plugins;
  for (unsigned int i = 0; i < vPluginList.size();i++)
    plugins.push_back(vPluginList[i].plugin);

  return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
  virtual ~DynamicPluginCommands() {};
  virtual bool handle ( int playerID, bz_ApiString _command, bz_ApiString _message, bz_APIStringList *params )
  {
    bz_BasePlayerRecord	record;

    std::string command = _command.c_str();
    std::string message = _message.c_str();

    bz_BasePlayerRecord	*p = bz_getPlayerByIndex(playerID);
    if (!p)
      return false;

    record = *p;

    bz_freePlayerRecord(p);

    // list needs listPlugins permission
    if ( TextUtils::tolower(command) == "listplugins" ) {
      if (!bz_hasPerm(playerID, "listPlugins")) {
	bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to run the /listplugins command");
	return true;
      } else {
	std::vector<std::string>	plugins = getPluginList();

	if (!plugins.size())
	  bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
	else {
	  bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

	  for ( unsigned int i = 0; i < plugins.size(); i++)
	    bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
	}
      }
      return true;
    }

    if (!record.hasPerm("PLUGINS")) {
      bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
      return true;
    }

    if ( TextUtils::tolower(command) == "loadplugin" ) {
      if ( !params->size() ) {
	bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
	return true;
      }

      std::vector<std::string> subparams = TextUtils::tokenize(message,std::string(","));

      std::string config;
      if ( subparams.size() >1)
	config = subparams[1];

      if (loadPlugin(subparams[0],config))
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
      else
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
      return true;
    }

    if ( TextUtils::tolower(command) == "unloadplugin" ) {
      if ( !params->size() ) {
	bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
	return true;
      }

      if ( unloadPlugin(std::string(params->get(0).c_str())) )
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");

      return true;
    }
    return true;
  }
};

DynamicPluginCommands	command;

// auto load plugin dir

std::string getAutoLoadDir ( void )
{
  if (BZDB.isSet("PlugInAutoLoadDir"))
    return BZDB.get("PlugInAutoLoadDir");
#if (defined(_WIN32) || defined(WIN32))
  char exePath[MAX_PATH];
  GetModuleFileName(NULL,exePath,MAX_PATH);
  char* last = strrchr(exePath,'\\');
  if (last)
    *last = '\0';
  strcat(exePath,"\\plugins");
  return std::string(exePath);
#else
  return std::string("");
#endif
}

void initPlugins ( void )
{
  customPluginMap.clear();

  registerCustomSlashCommand("loadplugin",&command);
  registerCustomSlashCommand("unloadplugin",&command);
  registerCustomSlashCommand("listplugins",&command);

#ifdef _WIN32
#ifdef _DEBUG
  OSDir	dir;
  std::string path = getAutoLoadDir();
  if (getAutoLoadDir().size()) {
    dir.setOSDir(getAutoLoadDir());

    OSFile file;
    while(dir.getNextFile(file,"*.dll",false) )
      loadPlugin(file.getOSName(),std::string(""));
  }
#endif //_DEBUG
#endif
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
  std::string ext = TextUtils::tolower(exte);
  customPluginMap[ext] = handler;
  return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
  tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

  if (itr == customPluginMap.end() || itr->second != handler)
    return false;

  customPluginMap.erase(itr);
  return true;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>remove the autoload dir, it was a stupid idea. do it as a plugin if anyone needs it.<commit_after>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* system headers */
#include <iostream>
#include <string>
#include <vector>
#include <map>

/* common headers */
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"
#include "OSFile.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
#  ifdef INSTALL_LIB_DIR
std::string globalPluginDir = INSTALL_LIB_DIR;
#  else
std::string globalPluginDir = ".";
#  endif
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
  std::string foundPath;
  std::string plugin;

#ifdef _WIN32
  HINSTANCE	handle;
#else
  void*		handle;
#endif
}trPluginRecord;

std::vector<trPluginRecord>	vPluginList;

typedef enum
  {
    eLoadFailedDupe = -1,
    eLoadFailedError = 0,
    eLoadFailedRuntime,
    eLoadComplete
  }PluginLoadReturn;

bool pluginExists ( std::string plugin )
{
  for ( int i = 0; i < (int)vPluginList.size(); i++ ) {
    if ( vPluginList[i].foundPath == plugin )
      return true;
  }
  return false;
}

std::string findPlugin ( std::string pluginName )
{
  // see if we can just open the bloody thing
  FILE	*fp = fopen(pluginName.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return pluginName;
  }

  // now try it with the standard extension
  std::string name = pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  // check the local users plugins dir
  name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  // check the global plugins dir
  name = globalPluginDir + pluginName + extension;
  fp = fopen(name.c_str(),"rb");
  if (fp) {
    fclose(fp);
    return name;
  }

  return std::string("");
}

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#  include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
  int (*lpProc)(void);
  lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
  if (lpProc)
    return lpProc();
  return 0;
}

PluginLoadReturn load1Plugin ( std::string plugin, std::string config )
{
  int (*lpProc)(const char*);

  std::string realPluginName = findPlugin(plugin);
  if (pluginExists(realPluginName)) {
    logDebugMessage(1,"LoadPlugin failed: %s is already loaded\n",realPluginName.c_str());
    return eLoadFailedDupe;
  }

  HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
  if (hLib) {
    if (getPluginVersion(hLib) > BZ_API_VERSION) {
      logDebugMessage(1,"Plugin:%s found but expects an newer API version (%d), upgrade your bzfs\n",plugin.c_str(),getPluginVersion(hLib));
      FreeLibrary(hLib);
      return eLoadFailedError;
    } else {
      lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
      if (lpProc) {
	if (lpProc(config.c_str())!= 0) {
	  logDebugMessage(1,"Plugin:%s found but bz_Load returned an error\n",plugin.c_str());
	  FreeLibrary(hLib);
	  return eLoadFailedRuntime;
	}
	logDebugMessage(1,"Plugin:%s loaded\n",plugin.c_str());

	trPluginRecord pluginRecord;
	pluginRecord.foundPath = realPluginName;
	pluginRecord.handle = hLib;
	pluginRecord.plugin = plugin;
	vPluginList.push_back(pluginRecord);
      } else {
	logDebugMessage(1,"Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
	FreeLibrary(hLib);
	return eLoadFailedError;
      }
    }
  } else {
    logDebugMessage(1,"Plugin:%s not found\n",plugin.c_str());
    return eLoadFailedError;
  }

  return eLoadComplete;
}

void unload1Plugin ( int iPluginID )
{
  int (*lpProc)(void);

  trPluginRecord &plugin = vPluginList[iPluginID];
  if (!plugin.handle)
    return;

  lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
  if (lpProc)
    lpProc();
  else
    logDebugMessage(1,"Plugin does not contain bz_UnLoad method\n");

  FreeLibrary(plugin.handle);
  plugin.handle = NULL;
  plugin.foundPath = "";
  plugin.plugin = "";
}
#else

#  include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
  int (*lpProc)(void);

  lpProc = force_cast<int (*)(void)>(dlsym(hLib,"bz_GetVersion"));
  if (lpProc)
    return (*lpProc)();
  return 0;
}

PluginLoadReturn load1Plugin ( std::string plugin, std::string config )
{
  int (*lpProc)(const char*);

  std::string realPluginName = findPlugin(plugin);

  if (pluginExists(realPluginName)) {
    logDebugMessage(1,"LoadPlugin failed: %s is already loaded\n",realPluginName.c_str());
    return eLoadFailedDupe;
  }

  void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
  if (hLib) {
    if (dlsym(hLib, "bz_Load") == NULL) {
      logDebugMessage(1,"Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
      dlclose(hLib);
      return eLoadFailedError;
    }

    int version = getPluginVersion(hLib);
    if (version < BZ_API_VERSION) {
      logDebugMessage(1,"Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
      dlclose(hLib);
      return eLoadFailedError;
    } else {
      lpProc = force_cast<int (*)(const char*)>(dlsym(hLib,"bz_Load"));
      if (lpProc) {
	if((*lpProc)(config.c_str())) {
	  logDebugMessage(1,"Plugin:%s found but bz_Load returned an error\n",plugin.c_str());
	  return eLoadFailedRuntime;
	}
	logDebugMessage(1,"Plugin:%s loaded\n",plugin.c_str());
	trPluginRecord pluginRecord;
	pluginRecord.handle = hLib;
	pluginRecord.plugin = plugin;
	vPluginList.push_back(pluginRecord);
	return eLoadComplete;
      }
    }
  } else {
    logDebugMessage(1,"Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
    return eLoadFailedError;
  }

  logDebugMessage(1,"If you see this, there is something terribly wrong.\n");
  return eLoadFailedError;
}

void unload1Plugin ( int iPluginID )
{
  int (*lpProc)(void);
  trPluginRecord &plugin = vPluginList[iPluginID];

  if(!plugin.handle)
    return;

  lpProc = force_cast<int (*)(void)>(dlsym(plugin.handle, "bz_Unload"));
  if (lpProc)
    (*lpProc)();
  else
    logDebugMessage(1,"Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

  dlclose(plugin.handle);
  plugin.handle = NULL;
  plugin.foundPath = "";
  plugin.plugin = "";

}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
  // check and see if it's an extension we have a handler for
  std::string ext;

  std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
  ext = parts[parts.size()-1];

  tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

  if (itr != customPluginMap.end() && itr->second) {
    bz_APIPluginHandler *handler = itr->second;
    return handler->handle(plugin,config);
  }
  else
    return load1Plugin(plugin,config) == eLoadComplete;
}

bool unloadPlugin ( std::string plugin )
{
  // unload the first one of the name we find
  for (unsigned int i = 0; i < vPluginList.size();i++) {
    if ( vPluginList[i].plugin == plugin ) {
      unload1Plugin(i);
      vPluginList.erase(vPluginList.begin()+i);
      return true;
    }
  }
  return false;
}

void unloadPlugins ( void )
{
  for (unsigned int i = 0; i < vPluginList.size();i++)
    unload1Plugin(i);
  vPluginList.clear();

  removeCustomSlashCommand("loadplugin");
  removeCustomSlashCommand("unloadplugin");
  removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
  std::vector<std::string> plugins;
  for (unsigned int i = 0; i < vPluginList.size();i++)
    plugins.push_back(vPluginList[i].plugin);

  return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
  virtual ~DynamicPluginCommands() {};
  virtual bool handle ( int playerID, bz_ApiString _command, bz_ApiString _message, bz_APIStringList *params )
  {
    bz_BasePlayerRecord	record;

    std::string command = _command.c_str();
    std::string message = _message.c_str();

    bz_BasePlayerRecord	*p = bz_getPlayerByIndex(playerID);
    if (!p)
      return false;

    record = *p;

    bz_freePlayerRecord(p);

    // list needs listPlugins permission
    if ( TextUtils::tolower(command) == "listplugins" ) {
      if (!bz_hasPerm(playerID, "listPlugins")) {
	bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to run the /listplugins command");
	return true;
      } else {
	std::vector<std::string>	plugins = getPluginList();

	if (!plugins.size())
	  bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
	else {
	  bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

	  for ( unsigned int i = 0; i < plugins.size(); i++)
	    bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
	}
      }
      return true;
    }

    if (!record.hasPerm("PLUGINS")) {
      bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
      return true;
    }

    if ( TextUtils::tolower(command) == "loadplugin" ) {
      if ( !params->size() ) {
	bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
	return true;
      }

      std::vector<std::string> subparams = TextUtils::tokenize(message,std::string(","));

      std::string config;
      if ( subparams.size() >1)
	config = subparams[1];

      if (loadPlugin(subparams[0],config))
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
      else
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
      return true;
    }

    if ( TextUtils::tolower(command) == "unloadplugin" ) {
      if ( !params->size() ) {
	bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
	return true;
      }

      if ( unloadPlugin(std::string(params->get(0).c_str())) )
	bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");

      return true;
    }
    return true;
  }
};

DynamicPluginCommands	command;

void initPlugins ( void )
{
  customPluginMap.clear();

  registerCustomSlashCommand("loadplugin",&command);
  registerCustomSlashCommand("unloadplugin",&command);
  registerCustomSlashCommand("listplugins",&command);
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
  std::string ext = TextUtils::tolower(exte);
  customPluginMap[ext] = handler;
  return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
  tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

  if (itr == customPluginMap.end() || itr->second != handler)
    return false;

  customPluginMap.erase(itr);
  return true;
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


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

#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include <cctype>
#include <climits>      // for CHAR_BIT
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <limits>       // for std::numeric_limits

#include "scanutils.h"

enum Flags {
  FL_SPLAT  = 0x01,   // Drop the value, do not assign
  FL_INV    = 0x02,   // Character-set with inverse
  FL_WIDTH  = 0x04,   // Field width specified
  FL_MINUS  = 0x08,   // Negative number
};

enum Ranks {
  RANK_CHAR = -2,
  RANK_SHORT  = -1,
  RANK_INT  = 0,
  RANK_LONG = 1,
  RANK_LONGLONG = 2,
  RANK_PTR      = std::numeric_limits<int>::max() // Special value used for pointers
};

const enum Ranks kMinRank = RANK_CHAR;
const enum Ranks kMaxRank = RANK_LONGLONG;

const enum Ranks kIntMaxRank = RANK_LONGLONG;
const enum Ranks kSizeTRank = RANK_LONG;
const enum Ranks kPtrDiffRank = RANK_LONG;

enum Bail {
  BAIL_NONE = 0,    // No error condition
  BAIL_EOF,         // Hit EOF
  BAIL_ERR          // Conversion mismatch
};

// Helper functions ------------------------------------------------------------
inline size_t LongBit() {
  return CHAR_BIT * sizeof(long);
}

static inline int
SkipSpace(FILE *s) {
  int p;
  while (isascii(p = fgetc(s)) && isspace(p));
  ungetc(p, s);  // Make sure next char is available for reading
  return p;
}

static inline void
SetBit(unsigned long *bitmap, unsigned int bit) {
  bitmap[bit/LongBit()] |= 1UL << (bit%LongBit());
}

static inline int
TestBit(unsigned long *bitmap, unsigned int bit) {
  return static_cast<int>(bitmap[bit/LongBit()] >> (bit%LongBit())) & 1;
}

static inline int DigitValue(int ch, int base) {
  if (ch >= '0' && ch <= '9') {
    if (base >= 10 || ch <= '7')
      return ch-'0';
  } else if (ch >= 'A' && ch <= 'Z' && base == 16) {
    return ch-'A'+10;
  } else if (ch >= 'a' && ch <= 'z' && base == 16) {
    return ch-'a'+10;
  }
  return -1;
}

// IO (re-)implementations -----------------------------------------------------
static uintmax_t streamtoumax(FILE* s, int base) {
  int minus = 0;
  uintmax_t v = 0;
  int d, c = 0;

  for (c = fgetc(s); isascii(c) && isspace(c); c = fgetc(s));

  // Single optional + or -
  if (c == '-' || c == '+') {
    minus = (c == '-');
    c = fgetc(s);
  }

  // Assign correct base
  if (base == 0) {
    if (c == '0') {
      c = fgetc(s);
      if (c == 'x' || c == 'X') {
        base = 16;
        c = fgetc(s);
      } else {
        base = 8;
      }
    }
  } else if (base == 16) {
    if (c == '0') {
      c = fgetc(s);
      if (c == 'x' || c == 'X') c = fgetc(s);
    }
  }

  // Actual number parsing
  for (; (c != EOF) && (d = DigitValue(c, base)) >= 0; c = fgetc(s))
    v = v*base + d;

  ungetc(c, s);
  return minus ? -v : v;
}

static double streamtofloat(FILE* s) {
  bool minus = false;
  uint64_t v = 0;
  int d, c;
  uint64_t k = 1;
  uint64_t w = 0;

  for (c = fgetc(s); isascii(c) && isspace(c); c = fgetc(s));

  // Single optional + or -
  if (c == '-' || c == '+') {
    minus = (c == '-');
    c = fgetc(s);
  }

  // Actual number parsing
  for (; c != EOF && (d = DigitValue(c, 10)) >= 0; c = fgetc(s))
    v = v*10 + d;
  if (c == '.') {
    for (c = fgetc(s); c != EOF && (d = DigitValue(c, 10)) >= 0; c = fgetc(s)) {
      w = w*10 + d;
      k *= 10;
    }
  }
  double f = v + static_cast<double>(w) / k;
  if (c == 'e' || c == 'E') {
    c = fgetc(s);
    int expsign = 1;
    if (c == '-' || c == '+') {
      expsign = (c == '-') ? -1 : 1;
      c = fgetc(s);
    }
    int exponent = 0;
    for (; (c != EOF) && (d = DigitValue(c, 10)) >= 0; c = fgetc(s)) {
      exponent = exponent * 10 + d;
    }
    exponent *= expsign;
    f *= pow(10.0, static_cast<double>(exponent));
  }
  ungetc(c, s);

  return minus ? -f : f;
}

static int tvfscanf(FILE* stream, const char *format, va_list ap);

int tfscanf(FILE* stream, const char *format, ...) {
  va_list ap;
  int rv;

  va_start(ap, format);
  rv = tvfscanf(stream, format, ap);
  va_end(ap);

  return rv;
}

static int tvfscanf(FILE* stream, const char *format, va_list ap) {
  const char *p = format;
  char ch;
  int q = 0;
  uintmax_t val = 0;
  int rank = RANK_INT;    // Default rank
  unsigned int width = UINT_MAX;
  int base;
  int flags = 0;
  enum {
    ST_NORMAL,        // Ground state
    ST_FLAGS,         // Special flags
    ST_WIDTH,         // Field width
    ST_MODIFIERS,     // Length or conversion modifiers
    ST_MATCH_INIT,    // Initial state of %[ sequence
    ST_MATCH,         // Main state of %[ sequence
    ST_MATCH_RANGE,   // After - in a %[ sequence
  } state = ST_NORMAL;
  char *sarg = nullptr;    // %s %c or %[ string argument
  enum Bail bail = BAIL_NONE;
  int converted = 0;    // Successful conversions
  unsigned long matchmap[((1 << CHAR_BIT)+(CHAR_BIT * sizeof(long) - 1)) /
      (CHAR_BIT * sizeof(long))];
  int matchinv = 0;   // Is match map inverted?
  unsigned char range_start = 0;
  off_t start_off = ftell(stream);

  // Skip leading spaces
  SkipSpace(stream);

  while ((ch = *p++) && !bail) {
    switch (state) {
      case ST_NORMAL:
        if (ch == '%') {
          state = ST_FLAGS;
          flags = 0; rank = RANK_INT; width = UINT_MAX;
        } else if (isascii(ch) && isspace(ch)) {
          SkipSpace(stream);
        } else {
          if (fgetc(stream) != ch)
            bail = BAIL_ERR;  // Match failure
        }
        break;

      case ST_FLAGS:
        if (ch == '*') {
          flags |= FL_SPLAT;
        } else if ('0' <= ch && ch <= '9') {
          width = (ch-'0');
          state = ST_WIDTH;
          flags |= FL_WIDTH;
        } else {
          state = ST_MODIFIERS;
          p--;      // Process this character again
        }
      break;

      case ST_WIDTH:
        if (ch >= '0' && ch <= '9') {
          width = width*10+(ch-'0');
        } else {
          state = ST_MODIFIERS;
          p--;      // Process this character again
        }
      break;

      case ST_MODIFIERS:
        switch (ch) {
          // Length modifiers - nonterminal sequences
          case 'h':
            rank--;     // Shorter rank
          break;
          case 'l':
            rank++;     // Longer rank
          break;
          case 'j':
            rank = kIntMaxRank;
          break;
          case 'z':
            rank = kSizeTRank;
          break;
          case 't':
            rank = kPtrDiffRank;
          break;
          case 'L':
          case 'q':
            rank = RANK_LONGLONG; // long double/long long
          break;

          default:
            // Output modifiers - terminal sequences
            state = ST_NORMAL;  // Next state will be normal
            if (rank < kMinRank)  // Canonicalize rank
              rank = kMinRank;
            else if (rank > kMaxRank)
              rank = kMaxRank;

          switch (ch) {
            case 'P':   // Upper case pointer
            case 'p':   // Pointer
              rank = RANK_PTR;
              base = 0;
              goto scan_int;

            case 'i':   // Base-independent integer
              base = 0;
              goto scan_int;

            case 'd':   // Decimal integer
              base = 10;
              goto scan_int;

            case 'o':   // Octal integer
              base = 8;
              goto scan_int;

            case 'u':   // Unsigned decimal integer
              base = 10;
              goto scan_int;

            case 'x':   // Hexadecimal integer
            case 'X':
              base = 16;
              goto scan_int;

            case 'n':   // Number of characters consumed
              val = ftell(stream) - start_off;
            goto set_integer;

            scan_int:
              q = SkipSpace(stream);
              if (q <= 0) {
                bail = BAIL_EOF;
                break;
              }
              val = streamtoumax(stream, base);
              // fall through

            set_integer:
              if (!(flags & FL_SPLAT)) {
                converted++;
                switch(rank) {
                  case RANK_CHAR:
                    *va_arg(ap, unsigned char *)
                      = static_cast<unsigned char>(val);
                  break;
                  case RANK_SHORT:
                    *va_arg(ap, unsigned short *)
                      = static_cast<unsigned short>(val);
                  break;
                  case RANK_INT:
                    *va_arg(ap, unsigned int *)
                      = static_cast<unsigned int>(val);
                  break;
                  case RANK_LONG:
                    *va_arg(ap, unsigned long *)
                      = static_cast<unsigned long>(val);
                  break;
                  case RANK_LONGLONG:
                    *va_arg(ap, unsigned long long *)
                      = static_cast<unsigned long long>(val);
                  break;
                  case RANK_PTR:
                    *va_arg(ap, void **)
                      = reinterpret_cast<void *>(static_cast<uintptr_t>(val));
                  break;
                }
              }
            break;

            case 'f':   // Preliminary float value parsing
            case 'g':
            case 'G':
            case 'e':
            case 'E':
              q = SkipSpace(stream);
              if (q <= 0) {
                bail = BAIL_EOF;
                break;
              }

              {
              double fval = streamtofloat(stream);
              if (!(flags & FL_SPLAT)) {
                if (rank == RANK_INT)
                  *va_arg(ap, float *) = static_cast<float>(fval);
                else if (rank == RANK_LONG)
                  *va_arg(ap, double *) = static_cast<double>(fval);
                converted++;
              }
              }
            break;

            case 'c':               // Character
              width = (flags & FL_WIDTH) ? width : 1; // Default width == 1
              sarg = va_arg(ap, char *);
              while (width--) {
                if ((q = fgetc(stream)) <= 0) {
                  bail = BAIL_EOF;
                  break;
                }
                if (!(flags & FL_SPLAT)) {
                  *sarg++ = q;
                  converted++;
                }
              }
            break;

            case 's':               // String
            {
              if (!(flags & FL_SPLAT)) {
                sarg = va_arg(ap, char *);
              }
              unsigned length = 0;
              while (width--) {
                q = fgetc(stream);
                if ((isascii(q) && isspace(q)) || (q <= 0)) {
                  ungetc(q, stream);
                  break;
                }
                if (!(flags & FL_SPLAT)) {
                  sarg[length] = q;
                }
                length++;
              }
              if (length == 0) {
                bail = BAIL_EOF;
              } else if (!(flags & FL_SPLAT)) {
                sarg[length] = '\0'; // Terminate output
                converted++;
              }
            }
            break;

            case '[':   // Character range
              sarg = va_arg(ap, char *);
              state = ST_MATCH_INIT;
              matchinv = 0;
              memset(matchmap, 0, sizeof matchmap);
            break;

            case '%':   // %% sequence
              if (fgetc(stream) != '%')
                bail = BAIL_ERR;
            break;

            default:    // Anything else
              bail = BAIL_ERR;  // Unknown sequence
            break;
          }
        }
      break;

      case ST_MATCH_INIT:   // Initial state for %[ match
        if (ch == '^' && !(flags & FL_INV)) {
          matchinv = 1;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
          state = ST_MATCH;
        }
      break;

      case ST_MATCH:    // Main state for %[ match
        if (ch == ']') {
          goto match_run;
        } else if (ch == '-') {
          range_start = static_cast<unsigned char>(ch);
          state = ST_MATCH_RANGE;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
        }
      break;

      case ST_MATCH_RANGE:    // %[ match after -
        if (ch == ']') {
          SetBit(matchmap, static_cast<unsigned char>('-'));
          goto match_run;
        } else {
          int i;
          for (i = range_start ; i < (static_cast<unsigned char>(ch)) ; i++)
          SetBit(matchmap, i);
          state = ST_MATCH;
        }
      break;

      match_run:      // Match expression finished
        char* oarg = sarg;
        while (width) {
          q = fgetc(stream);
          auto qc = static_cast<unsigned char>(q);
          if (q <= 0 || !(TestBit(matchmap, qc)^matchinv)) {
            ungetc(q, stream);
            break;
          }
          if (!(flags & FL_SPLAT)) *sarg = q;
          sarg++;
        }
        if (oarg == sarg) {
          bail = (q <= 0) ? BAIL_EOF : BAIL_ERR;
        } else if (!(flags & FL_SPLAT)) {
          *sarg = '\0';
          converted++;
        }
      break;
    }
  }

  if (bail == BAIL_EOF && !converted)
    converted = -1;   // Return EOF (-1)

  return converted;
}
<commit_msg>Use long instead of off_t for result from ftell<commit_after>// Copyright 2006 Google Inc.
// All Rights Reserved.
// Author: renn
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include <cctype>
#include <climits>      // for CHAR_BIT
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <limits>       // for std::numeric_limits

#include "scanutils.h"

enum Flags {
  FL_SPLAT  = 0x01,   // Drop the value, do not assign
  FL_INV    = 0x02,   // Character-set with inverse
  FL_WIDTH  = 0x04,   // Field width specified
  FL_MINUS  = 0x08,   // Negative number
};

enum Ranks {
  RANK_CHAR = -2,
  RANK_SHORT  = -1,
  RANK_INT  = 0,
  RANK_LONG = 1,
  RANK_LONGLONG = 2,
  RANK_PTR      = std::numeric_limits<int>::max() // Special value used for pointers
};

const enum Ranks kMinRank = RANK_CHAR;
const enum Ranks kMaxRank = RANK_LONGLONG;

const enum Ranks kIntMaxRank = RANK_LONGLONG;
const enum Ranks kSizeTRank = RANK_LONG;
const enum Ranks kPtrDiffRank = RANK_LONG;

enum Bail {
  BAIL_NONE = 0,    // No error condition
  BAIL_EOF,         // Hit EOF
  BAIL_ERR          // Conversion mismatch
};

// Helper functions ------------------------------------------------------------
inline size_t LongBit() {
  return CHAR_BIT * sizeof(long);
}

static inline int
SkipSpace(FILE *s) {
  int p;
  while (isascii(p = fgetc(s)) && isspace(p));
  ungetc(p, s);  // Make sure next char is available for reading
  return p;
}

static inline void
SetBit(unsigned long *bitmap, unsigned int bit) {
  bitmap[bit/LongBit()] |= 1UL << (bit%LongBit());
}

static inline int
TestBit(unsigned long *bitmap, unsigned int bit) {
  return static_cast<int>(bitmap[bit/LongBit()] >> (bit%LongBit())) & 1;
}

static inline int DigitValue(int ch, int base) {
  if (ch >= '0' && ch <= '9') {
    if (base >= 10 || ch <= '7')
      return ch-'0';
  } else if (ch >= 'A' && ch <= 'Z' && base == 16) {
    return ch-'A'+10;
  } else if (ch >= 'a' && ch <= 'z' && base == 16) {
    return ch-'a'+10;
  }
  return -1;
}

// IO (re-)implementations -----------------------------------------------------
static uintmax_t streamtoumax(FILE* s, int base) {
  int minus = 0;
  uintmax_t v = 0;
  int d, c = 0;

  for (c = fgetc(s); isascii(c) && isspace(c); c = fgetc(s));

  // Single optional + or -
  if (c == '-' || c == '+') {
    minus = (c == '-');
    c = fgetc(s);
  }

  // Assign correct base
  if (base == 0) {
    if (c == '0') {
      c = fgetc(s);
      if (c == 'x' || c == 'X') {
        base = 16;
        c = fgetc(s);
      } else {
        base = 8;
      }
    }
  } else if (base == 16) {
    if (c == '0') {
      c = fgetc(s);
      if (c == 'x' || c == 'X') c = fgetc(s);
    }
  }

  // Actual number parsing
  for (; (c != EOF) && (d = DigitValue(c, base)) >= 0; c = fgetc(s))
    v = v*base + d;

  ungetc(c, s);
  return minus ? -v : v;
}

static double streamtofloat(FILE* s) {
  bool minus = false;
  uint64_t v = 0;
  int d, c;
  uint64_t k = 1;
  uint64_t w = 0;

  for (c = fgetc(s); isascii(c) && isspace(c); c = fgetc(s));

  // Single optional + or -
  if (c == '-' || c == '+') {
    minus = (c == '-');
    c = fgetc(s);
  }

  // Actual number parsing
  for (; c != EOF && (d = DigitValue(c, 10)) >= 0; c = fgetc(s))
    v = v*10 + d;
  if (c == '.') {
    for (c = fgetc(s); c != EOF && (d = DigitValue(c, 10)) >= 0; c = fgetc(s)) {
      w = w*10 + d;
      k *= 10;
    }
  }
  double f = v + static_cast<double>(w) / k;
  if (c == 'e' || c == 'E') {
    c = fgetc(s);
    int expsign = 1;
    if (c == '-' || c == '+') {
      expsign = (c == '-') ? -1 : 1;
      c = fgetc(s);
    }
    int exponent = 0;
    for (; (c != EOF) && (d = DigitValue(c, 10)) >= 0; c = fgetc(s)) {
      exponent = exponent * 10 + d;
    }
    exponent *= expsign;
    f *= pow(10.0, static_cast<double>(exponent));
  }
  ungetc(c, s);

  return minus ? -f : f;
}

static int tvfscanf(FILE* stream, const char *format, va_list ap);

int tfscanf(FILE* stream, const char *format, ...) {
  va_list ap;
  int rv;

  va_start(ap, format);
  rv = tvfscanf(stream, format, ap);
  va_end(ap);

  return rv;
}

static int tvfscanf(FILE* stream, const char *format, va_list ap) {
  const char *p = format;
  char ch;
  int q = 0;
  uintmax_t val = 0;
  int rank = RANK_INT;    // Default rank
  unsigned int width = UINT_MAX;
  int base;
  int flags = 0;
  enum {
    ST_NORMAL,        // Ground state
    ST_FLAGS,         // Special flags
    ST_WIDTH,         // Field width
    ST_MODIFIERS,     // Length or conversion modifiers
    ST_MATCH_INIT,    // Initial state of %[ sequence
    ST_MATCH,         // Main state of %[ sequence
    ST_MATCH_RANGE,   // After - in a %[ sequence
  } state = ST_NORMAL;
  char *sarg = nullptr;    // %s %c or %[ string argument
  enum Bail bail = BAIL_NONE;
  int converted = 0;    // Successful conversions
  unsigned long matchmap[((1 << CHAR_BIT)+(CHAR_BIT * sizeof(long) - 1)) /
      (CHAR_BIT * sizeof(long))];
  int matchinv = 0;   // Is match map inverted?
  unsigned char range_start = 0;
  long start_off = ftell(stream);

  // Skip leading spaces
  SkipSpace(stream);

  while ((ch = *p++) && !bail) {
    switch (state) {
      case ST_NORMAL:
        if (ch == '%') {
          state = ST_FLAGS;
          flags = 0; rank = RANK_INT; width = UINT_MAX;
        } else if (isascii(ch) && isspace(ch)) {
          SkipSpace(stream);
        } else {
          if (fgetc(stream) != ch)
            bail = BAIL_ERR;  // Match failure
        }
        break;

      case ST_FLAGS:
        if (ch == '*') {
          flags |= FL_SPLAT;
        } else if ('0' <= ch && ch <= '9') {
          width = (ch-'0');
          state = ST_WIDTH;
          flags |= FL_WIDTH;
        } else {
          state = ST_MODIFIERS;
          p--;      // Process this character again
        }
      break;

      case ST_WIDTH:
        if (ch >= '0' && ch <= '9') {
          width = width*10+(ch-'0');
        } else {
          state = ST_MODIFIERS;
          p--;      // Process this character again
        }
      break;

      case ST_MODIFIERS:
        switch (ch) {
          // Length modifiers - nonterminal sequences
          case 'h':
            rank--;     // Shorter rank
          break;
          case 'l':
            rank++;     // Longer rank
          break;
          case 'j':
            rank = kIntMaxRank;
          break;
          case 'z':
            rank = kSizeTRank;
          break;
          case 't':
            rank = kPtrDiffRank;
          break;
          case 'L':
          case 'q':
            rank = RANK_LONGLONG; // long double/long long
          break;

          default:
            // Output modifiers - terminal sequences
            state = ST_NORMAL;  // Next state will be normal
            if (rank < kMinRank)  // Canonicalize rank
              rank = kMinRank;
            else if (rank > kMaxRank)
              rank = kMaxRank;

          switch (ch) {
            case 'P':   // Upper case pointer
            case 'p':   // Pointer
              rank = RANK_PTR;
              base = 0;
              goto scan_int;

            case 'i':   // Base-independent integer
              base = 0;
              goto scan_int;

            case 'd':   // Decimal integer
              base = 10;
              goto scan_int;

            case 'o':   // Octal integer
              base = 8;
              goto scan_int;

            case 'u':   // Unsigned decimal integer
              base = 10;
              goto scan_int;

            case 'x':   // Hexadecimal integer
            case 'X':
              base = 16;
              goto scan_int;

            case 'n':   // Number of characters consumed
              val = ftell(stream) - start_off;
            goto set_integer;

            scan_int:
              q = SkipSpace(stream);
              if (q <= 0) {
                bail = BAIL_EOF;
                break;
              }
              val = streamtoumax(stream, base);
              // fall through

            set_integer:
              if (!(flags & FL_SPLAT)) {
                converted++;
                switch(rank) {
                  case RANK_CHAR:
                    *va_arg(ap, unsigned char *)
                      = static_cast<unsigned char>(val);
                  break;
                  case RANK_SHORT:
                    *va_arg(ap, unsigned short *)
                      = static_cast<unsigned short>(val);
                  break;
                  case RANK_INT:
                    *va_arg(ap, unsigned int *)
                      = static_cast<unsigned int>(val);
                  break;
                  case RANK_LONG:
                    *va_arg(ap, unsigned long *)
                      = static_cast<unsigned long>(val);
                  break;
                  case RANK_LONGLONG:
                    *va_arg(ap, unsigned long long *)
                      = static_cast<unsigned long long>(val);
                  break;
                  case RANK_PTR:
                    *va_arg(ap, void **)
                      = reinterpret_cast<void *>(static_cast<uintptr_t>(val));
                  break;
                }
              }
            break;

            case 'f':   // Preliminary float value parsing
            case 'g':
            case 'G':
            case 'e':
            case 'E':
              q = SkipSpace(stream);
              if (q <= 0) {
                bail = BAIL_EOF;
                break;
              }

              {
              double fval = streamtofloat(stream);
              if (!(flags & FL_SPLAT)) {
                if (rank == RANK_INT)
                  *va_arg(ap, float *) = static_cast<float>(fval);
                else if (rank == RANK_LONG)
                  *va_arg(ap, double *) = static_cast<double>(fval);
                converted++;
              }
              }
            break;

            case 'c':               // Character
              width = (flags & FL_WIDTH) ? width : 1; // Default width == 1
              sarg = va_arg(ap, char *);
              while (width--) {
                if ((q = fgetc(stream)) <= 0) {
                  bail = BAIL_EOF;
                  break;
                }
                if (!(flags & FL_SPLAT)) {
                  *sarg++ = q;
                  converted++;
                }
              }
            break;

            case 's':               // String
            {
              if (!(flags & FL_SPLAT)) {
                sarg = va_arg(ap, char *);
              }
              unsigned length = 0;
              while (width--) {
                q = fgetc(stream);
                if ((isascii(q) && isspace(q)) || (q <= 0)) {
                  ungetc(q, stream);
                  break;
                }
                if (!(flags & FL_SPLAT)) {
                  sarg[length] = q;
                }
                length++;
              }
              if (length == 0) {
                bail = BAIL_EOF;
              } else if (!(flags & FL_SPLAT)) {
                sarg[length] = '\0'; // Terminate output
                converted++;
              }
            }
            break;

            case '[':   // Character range
              sarg = va_arg(ap, char *);
              state = ST_MATCH_INIT;
              matchinv = 0;
              memset(matchmap, 0, sizeof matchmap);
            break;

            case '%':   // %% sequence
              if (fgetc(stream) != '%')
                bail = BAIL_ERR;
            break;

            default:    // Anything else
              bail = BAIL_ERR;  // Unknown sequence
            break;
          }
        }
      break;

      case ST_MATCH_INIT:   // Initial state for %[ match
        if (ch == '^' && !(flags & FL_INV)) {
          matchinv = 1;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
          state = ST_MATCH;
        }
      break;

      case ST_MATCH:    // Main state for %[ match
        if (ch == ']') {
          goto match_run;
        } else if (ch == '-') {
          range_start = static_cast<unsigned char>(ch);
          state = ST_MATCH_RANGE;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
        }
      break;

      case ST_MATCH_RANGE:    // %[ match after -
        if (ch == ']') {
          SetBit(matchmap, static_cast<unsigned char>('-'));
          goto match_run;
        } else {
          int i;
          for (i = range_start ; i < (static_cast<unsigned char>(ch)) ; i++)
          SetBit(matchmap, i);
          state = ST_MATCH;
        }
      break;

      match_run:      // Match expression finished
        char* oarg = sarg;
        while (width) {
          q = fgetc(stream);
          auto qc = static_cast<unsigned char>(q);
          if (q <= 0 || !(TestBit(matchmap, qc)^matchinv)) {
            ungetc(q, stream);
            break;
          }
          if (!(flags & FL_SPLAT)) *sarg = q;
          sarg++;
        }
        if (oarg == sarg) {
          bail = (q <= 0) ? BAIL_EOF : BAIL_ERR;
        } else if (!(flags & FL_SPLAT)) {
          *sarg = '\0';
          converted++;
        }
      break;
    }
  }

  if (bail == BAIL_EOF && !converted)
    converted = -1;   // Return EOF (-1)

  return converted;
}
<|endoftext|>


<commit_before>
#include <iostream>
#include <unordered_map>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <Galois/Galois.h>
#include <Galois/Graph/Graph.h>

//#include <cstring>
#include <string>
#include <fstream>
using namespace std;
using namespace boost;

typedef enum{pi,po,nd} node_type;

struct Node {
 string label_type;//a0,b0...
 node_type type;// pi,po,nd
 int fanins; // Not required as of now
 bool fanout; //Not required as of now
 int level;
 };

typedef Galois::Graph::FirstGraph<Node,int,true> Graph;

Graph g;

int node_index = 0;
vector<Graph::GraphNode> gnodes;

vector<string> fields;

bool checkWorkability(Graph::GraphNode gnode){
	int count = 0;
	for (Graph::edge_iterator edge : g.out_edges(gnode)) {
		int edgedata = g.getEdgeData(edge);
	   	if(edgedata == 1|| edgedata ==2)
	   		count++;
	   	}
	if (count > 1)
		return false;
	else
		return true;
}

void parseFileintoGraph(string inFile, unordered_map <string, int> &map){
	ifstream fin;
	fin.open(inFile); // open a file
	if (!fin.good()){
		cout << "file not found\n";

	}
	else
	// read each line of the file
	while (!fin.eof())
	{
	// read an entire line into memory
	string line;
	getline(fin,line);
	trim(line);
	split(fields, line, is_any_of(" "));
	Node n;
	if(fields[0].compare("input") == 0 || fields[0].compare("output") == 0||fields[0].compare("wire") == 0)
	{
		for(unsigned i =1;i<fields.size();i++){
			//add to hash map to index to corresponding node in array
			if(fields[i].size()>1)
			{
				//Add data to each node for level and type of input
				if(fields[0].compare("input") == 0)
				{
					n.type = pi;
					n.level = 0;
					n.label_type = fields[i].substr(0,fields[i].length()-1);

					//nodes[node_index].type = pi;
					//nodes[node_index].level = 0;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				if(fields[0].compare("output") == 0)
				{
					n.type = po;
					n.level = -1;
					n.label_type = fields[i].substr(0,fields[i].length()-1);
					//nodes[node_index].type = po;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				if(fields[0].compare("wire") == 0)
				{
					n.type = nd;
					n.level = -2;
					n.label_type = fields[i].substr(0,fields[i].length()-1);
					//nodes[node_index].type = nd;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				//remove last char b/c its ',' or ';'
				map[fields[i].substr(0,fields[i].length()-1)] = node_index;
				//gnodes[node_index] = g.createNode(nodes[node_index]);
				gnodes.push_back(g.createNode(n));

				g.addNode(gnodes[gnodes.size()-1]);
				//cout << "node index: "<< node_index<<endl;
				node_index++;
			}

		}
	}
	//cout <<"compare assign"<<endl;
	if(fields[0].compare("assign") == 0)
	{
	int level1,level2;

		if(fields[4].compare("|") == 0)
		{	//Edge weight: 2- Negative 1 - Positive
			g.getEdgeData(g.addEdge(gnodes[map[fields[3].substr(0,fields[3].length())]]//src
										   ,gnodes[map[fields[1]]])) = 2;//dest
			g.getEdgeData(g.addEdge(gnodes[map[fields[5].substr(0,fields[5].length()-1)]]
										   ,gnodes[map[fields[1]]])) = 2;

			level1 = g.getData(gnodes[map[fields[3].substr(0,fields[3].length())]]).level;
			level2 = g.getData(gnodes[map[fields[5].substr(0,fields[5].length()-1)]]).level;
			g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
					  gnodes[map[fields[3].substr(0,fields[3].length())]])) = 3;//back edges to determine fanins -> wt. = 3
			g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
					  gnodes[map[fields[5].substr(0,fields[5].length())]])) = 3;//back edges to determins fanins -> wt. = 3
		}

		else
		{	size_t invert = fields[3].find_first_of("~");
			if (invert != string::npos){
				//addEdge(src,dest)
				//remove the '~' from the start of string
				//map[string] returns node index to find which node
				g.getEdgeData(g.addEdge(gnodes[map[fields[3].substr(1,fields[3].length())]],gnodes[map[fields[1]]])) = 2;//
				level1 = g.getData(gnodes[map[fields[3].substr(1,fields[3].length())]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
							  gnodes[map[fields[3].substr(1,fields[3].length())]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
			else{
				g.getEdgeData(g.addEdge(gnodes[map[fields[3].substr(0,fields[3].length())]],gnodes[map[fields[1]]])) = 1;
				level1 = g.getData(gnodes[map[fields[3].substr(0,fields[3].length())]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
						  gnodes[map[fields[3].substr(0,fields[3].length())]])) = 3;// Back edges to determine fanins -> wt. = 3

			}
			invert = fields[5].find_first_of("~");
			if (invert != string::npos){
				//remove first and last char b/c '~' to start and ';' at th
				//cout <<fields[5] << " substr"<<fields[5].substr(1,fields[5].length()-1)<<" "<<map[fields[5].substr(1,fields[5].length()-1)]<< " "<< nodes[map[fields[5].substr(1,fields[5].length()-1)]].label_type <<endl;
				g.getEdgeData(g.addEdge(gnodes[map[fields[5].substr(1,fields[5].length()-2)]],gnodes[map[fields[1]]])) = 2;
				level2 = g.getData(gnodes[map[fields[5].substr(1,fields[5].length()-2)]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
						  gnodes[map[fields[5].substr(1,fields[5].length()-2)]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
			else{
				g.getEdgeData(g.addEdge(gnodes[map[fields[5].substr(0,fields[5].length()-1)]],gnodes[map[fields[1]]])) = 1;
				level2 = g.getData(gnodes[map[fields[5].substr(0,fields[5].length()-1)]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[fields[1]]],
						  gnodes[map[fields[5].substr(0,fields[5].length()-1)]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
		}

	if(level1>=level2)
		g.getData(gnodes[map[fields[1]]]).level= level1+1;
	else
		g.getData(gnodes[map[fields[1]]]).level= level2+1;
	}

	}
}

int main(int argc, char *argv[]) {
	unordered_map <string, int> map;
	if ( argc != 2 )
    		cout<<"usage: "<< argv[0] <<" <filename>\n";
  	else
  			parseFileintoGraph(argv[1],map);

	//cout << g.getData(gnodes[0]).label_type << endl;
	// Traverse graph
 	for (Graph::iterator ii = g.begin(), ei = g.end(); ii != ei; ++ii) {
   		Graph::GraphNode src = *ii;
		cout <<"src: "<< g.getData(src).label_type;
		cout <<"src: level"<<g.getData(src).level;
   		for (Graph::edge_iterator edge : g.out_edges(src)) {
   			Graph::GraphNode dst = g.getEdgeDst(edge);
     		cout <<" dest: "<< g.getData(dst).label_type;
     		int edgeData = g.getEdgeData(edge);
     		cout << " edge data " << edgeData;
     		//assert(edgeData == 5);
   		}
	   	cout <<endl;
 	}
 	if(checkWorkability(gnodes[map["n15"]]))
 		cout << "1 output"<<endl;
 	else
 		cout <<"more than 1 output"<<endl;

	return 0;
}
<commit_msg>fixed graph weight errors<commit_after>
#include <iostream>
#include <unordered_map>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <Galois/Galois.h>
#include <Galois/Graph/Graph.h>

//#include <cstring>
#include <string>
#include <fstream>
using namespace std;
using namespace boost;

typedef enum{pi,po,nd} node_type;

struct Node {
 string label_type;//a0,b0...
 node_type type;// pi,po,nd
 int fanins; // Not required as of now
 bool fanout; //Not required as of now
 int level;
 };

typedef Galois::Graph::FirstGraph<Node,int,true> Graph;

Graph g;

int node_index = 0;
vector<Graph::GraphNode> gnodes;

vector<string> fields;

bool checkWorkability(Graph::GraphNode gnode){
	int count = 0;
	for (Graph::edge_iterator edge : g.out_edges(gnode)) {
		int edgedata = g.getEdgeData(edge);
	   	if(edgedata == 1|| edgedata ==2)
	   		count++;
	   	}
	if (count > 1)
		return false;
	else
		return true;
}

void parseFileintoGraph(string inFile, unordered_map <string, int> &map){
	ifstream fin;
	fin.open(inFile); // open a file
	if (!fin.good()){
		cout << "file not found\n";

	}
	else
	// read each line of the file
	while (!fin.eof())
	{
	// read an entire line into memory
	string line;
	getline(fin,line);
	trim(line);
	split(fields, line, is_any_of(" "));
	Node n;
	if(fields[0].compare("input") == 0 || fields[0].compare("output") == 0||fields[0].compare("wire") == 0)
	{
		for(unsigned i =1;i<fields.size();i++){
			//add to hash map to index to corresponding node in array
			if(fields[i].size()>1)
			{
				//Add data to each node for level and type of input
				if(fields[0].compare("input") == 0)
				{
					n.type = pi;
					n.level = 0;
					n.label_type = fields[i].substr(0,fields[i].length()-1);

					//nodes[node_index].type = pi;
					//nodes[node_index].level = 0;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				if(fields[0].compare("output") == 0)
				{
					n.type = po;
					n.level = -1;
					n.label_type = fields[i].substr(0,fields[i].length()-1);
					//nodes[node_index].type = po;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				if(fields[0].compare("wire") == 0)
				{
					n.type = nd;
					n.level = -2;
					n.label_type = fields[i].substr(0,fields[i].length()-1);
					//nodes[node_index].type = nd;
					//nodes[node_index].label_type = fields[i].substr(0,fields[i].length()-1);
				}
				//remove last char b/c its ',' or ';'
				map[fields[i].substr(0,fields[i].length()-1)] = node_index;
				//gnodes[node_index] = g.createNode(nodes[node_index]);
				gnodes.push_back(g.createNode(n));

				g.addNode(gnodes[gnodes.size()-1]);
				//cout << "node index: "<< node_index<<endl;
				node_index++;
			}

		}
	}
	//cout <<"compare assign"<<endl;
	if(fields[0].compare("assign") == 0)
	{
		int level1,level2;
		string f1,f3,f5;
		f1 = fields[1];
		f3 = fields[3];
		f5 = fields[5];
		if(fields[4].compare("|") == 0)
		{	//Edge weight: 2- Negative 1 - Positive
			f3 = f3.substr(0,f3.length());
			f5 = f5.substr(0,f5.length()-1);
			g.getEdgeData(g.addEdge(gnodes[map[f3]]//src
										   ,gnodes[map[f1]])) = 2;//dest

			g.getEdgeData(g.addEdge(gnodes[map[f5]]
										   ,gnodes[map[f1]])) = 2;

			level1 = g.getData(gnodes[map[f3]]).level;
			level2 = g.getData(gnodes[map[f5]]).level;
			g.getEdgeData(g.addEdge(gnodes[map[f1]],
					  gnodes[map[f3]])) = 3;//back edges to determine fanins -> wt. = 3
			g.getEdgeData(g.addEdge(gnodes[map[f1]],
					  gnodes[map[f5]])) = 3;//back edges to determins fanins -> wt. = 3
		}

		else
		{	size_t invert = fields[3].find_first_of("~");
			if (invert != string::npos){
				f3 = f3.substr(1,f3.length());
				//addEdge(src,dest)
				//remove the '~' from the start of string
				//map[string] returns node index to find which node
				g.getEdgeData(g.addEdge(gnodes[map[f3]],gnodes[map[f1]])) = 2;//
				level1 = g.getData(gnodes[map[f3]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[f1]],
							  gnodes[map[f3]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
			else{
				g.getEdgeData(g.addEdge(gnodes[map[f3]],gnodes[map[f1]])) = 1;
				level1 = g.getData(gnodes[map[f3]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[f1]],
						  gnodes[map[f3]])) = 3;// Back edges to determine fanins -> wt. = 3

			}
			invert = fields[5].find_first_of("~");
			if (invert != string::npos){
				f5 = f5.substr(1,f5.length()-2);
				//remove first and last char b/c '~' to start and ';' at th
				//cout <<fields[5] << " substr"<<fields[5].substr(1,fields[5].length()-1)<<" "<<map[fields[5].substr(1,fields[5].length()-1)]<< " "<< nodes[map[fields[5].substr(1,fields[5].length()-1)]].label_type <<endl;
				g.getEdgeData(g.addEdge(gnodes[map[f5]],gnodes[map[f1]])) = 2;
				level2 = g.getData(gnodes[map[f5]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[f1]],
						  gnodes[map[f5]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
			else{
				f5 = f5.substr(0,f5.length()-1);
				g.getEdgeData(g.addEdge(gnodes[map[f5]],gnodes[map[f1]])) = 1;
				level2 = g.getData(gnodes[map[f5]]).level;
				g.getEdgeData(g.addEdge(gnodes[map[f1]],
						  gnodes[map[f5]])) = 3;// Back edges to determine fanins -> wt. = 3
			}
		}

	if(level1>=level2)
		g.getData(gnodes[map[fields[1]]]).level= level1+1;
	else
		g.getData(gnodes[map[fields[1]]]).level= level2+1;
	}

	}
}

int main(int argc, char *argv[]) {
	unordered_map <string, int> map;
	if ( argc != 2 )
    		cout<<"usage: "<< argv[0] <<" <filename>\n";
  	else
  			parseFileintoGraph(argv[1],map);

	//cout << g.getData(gnodes[0]).label_type << endl;
	// Traverse graph
 	//for (Graph::iterator ii = g.begin(), ei = g.end(); ii != ei; ++ii) {
	for ( Graph::GraphNode src : g){
   		//Graph::GraphNode src = *ii;
		cout <<"src: "<< g.getData(src).label_type;
		cout <<" level: "<<g.getData(src).level;

		for (Graph::edge_iterator edge : g.out_edges(src)) {
   			Graph::GraphNode dst = g.getEdgeDst(edge);
     		cout <<" dest: "<< g.getData(dst).label_type;
     		int edgeData = g.getEdgeData(edge);
     		cout << " edge data " << edgeData;
     		//assert(edgeData == 5);
   		}
	   	cout <<endl;
 	}
 	if(checkWorkability(gnodes[map["n15"]]))
 		cout << "1 output"<<endl;
 	else
 		cout <<"more than 1 output"<<endl;

	return 0;
}
<|endoftext|>


<commit_before>#include <znc/main.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <znc/Nick.h>
#include <znc/Chan.h>
#include <znc/IRCSock.h>

#include <limits>

#include "twitchtmi.h"
#include "jload.h"

TwitchTMI::~TwitchTMI()
{

}

bool TwitchTMI::OnLoad(const CString& sArgsi, CString& sMessage)
{
	OnBoot();

	if(GetNetwork())
	{
		for(CChan *ch: GetNetwork()->GetChans())
		{
			ch->SetTopic(CString());

			CString chname = ch->GetName().substr(1);
			CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));
		}
	}

	if(GetArgs().Token(0) != "FrankerZ")
		lastFrankerZ = std::numeric_limits<decltype(lastFrankerZ)>::max();

	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/tags");

	return true;
}

bool TwitchTMI::OnBoot()
{
	initCurl();

	timer = new TwitchTMIUpdateTimer(this);
	AddTimer(timer);

	return true;
}

void TwitchTMI::OnIRCConnected()
{
	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/tags");
}

CModule::EModRet TwitchTMI::OnUserRaw(CString &sLine)
{
	if(sLine.Left(5).Equals("WHO #"))
		return CModule::HALT;

	if(sLine.Left(5).Equals("AWAY "))
		return CModule::HALT;

	if(sLine.Left(12).Equals("TWITCHCLIENT"))
		return CModule::HALT;

	if(sLine.Left(9).Equals("JTVCLIENT"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnUserJoin(CString& sChannel, CString& sKey)
{
	CString chname = sChannel.substr(1);
	CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnPrivMessage(CPrivMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnChanMessage(CChanMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	if(Message.GetText() == "FrankerZ" && std::time(nullptr) - lastFrankerZ > 10)
	{
		std::stringstream ss1, ss2;
		CString mynick = GetNetwork()->GetIRCNick().GetNickMask();
		CChan *chan = Message.GetChan();

		ss1 << "PRIVMSG " << chan->GetName() << " :FrankerZ";
		ss2 << ":" << mynick << " PRIVMSG " << chan->GetName() << " :";

		PutIRC(ss1.str());
		CString s2 = ss2.str();

		CThreadPool::Get().addJob(new GenericJob([]() {}, [this, s2, chan]()
		{
			PutUser(s2 + "FrankerZ");

			if(!chan->AutoClearChanBuffer() || !GetNetwork()->IsUserOnline() || chan->IsDetached()) {
				chan->AddBuffer(s2+ "{text}", "FrankerZ");
			}
		}));

		lastFrankerZ = std::time(nullptr);
	}

	return CModule::CONTINUE;
}

bool TwitchTMI::OnServerCapAvailable(const CString &sCap)
{
	if(sCap == "twitch.tv/membership")
	{
		CUtils::PrintMessage("TwitchTMI: Requesting twitch.tv/membership cap");
		return true;
	}
	else if(sCap == "twitch.tv/tags")
	{
		CUtils::PrintMessage("TwitchTMI: Requesting twitch.tv/tags cap");
		return true;
	}

	CUtils::PrintMessage(CString("TwitchTMI: Not requesting ") + sCap + " cap");

	return false;
}

TwitchTMIUpdateTimer::TwitchTMIUpdateTimer(TwitchTMI *tmod)
	:CTimer(tmod, 30, 0, "TwitchTMIUpdateTimer", "Downloads Twitch information")
	,mod(tmod)
{
}

void TwitchTMIUpdateTimer::RunJob()
{
	if(!mod->GetNetwork())
		return;

	for(CChan *chan: mod->GetNetwork()->GetChans())
	{
		CString chname = chan->GetName().substr(1);
		CThreadPool::Get().addJob(new TwitchTMIJob(mod, chname));
	}
}

void TwitchTMIJob::runThread()
{
	std::stringstream ss;
	ss << "https://api.twitch.tv/kraken/channels/" << channel;

	CString url = ss.str();

	Json::Value root = getJsonFromUrl(url.c_str(), "Accept: application/vnd.twitchtv.v3+json");

	if(root.isNull())
	{
		return;
	}

	Json::Value &titleVal = root["status"];
	title = CString();

	if(!titleVal.isString())
		titleVal = root["title"];

	if(!titleVal.isString())
		return;

	title = titleVal.asString();
	title.Trim();
}

void TwitchTMIJob::runMain()
{
	if(title.empty())
		return;

	CChan *chan = mod->GetNetwork()->FindChan(CString("#") + channel);

	if(!chan)
		return;

	if(chan->GetTopic() != title)
	{
		chan->SetTopic(title);
		chan->SetTopicOwner("jtv");
		chan->SetTopicDate((unsigned long)time(nullptr));

		std::stringstream ss;
		ss << ":jtv TOPIC #" << channel << " :" << title;

		mod->PutUser(ss.str());
	}
}

template<> void TModInfo<TwitchTMI>(CModInfo &info)
{
	info.SetWikiPage("Twitch");
	info.SetHasArgs(true);
}

NETWORKMODULEDEFS(TwitchTMI, "Twitch IRC helper module")
<commit_msg>Add ZNC version check<commit_after>#include <znc/main.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Modules.h>
#include <znc/Nick.h>
#include <znc/Chan.h>
#include <znc/IRCSock.h>
#include <znc/version.h>

#include <limits>

#include "twitchtmi.h"
#include "jload.h"

#if (VERSION_MAJOR < 1) || (VERSION_MAJOR == 1 && VERSION_MINOR < 7)
#error This module needs at least ZNC 1.7.0 or later.
#endif

TwitchTMI::~TwitchTMI()
{

}

bool TwitchTMI::OnLoad(const CString& sArgsi, CString& sMessage)
{
	OnBoot();

	if(GetNetwork())
	{
		for(CChan *ch: GetNetwork()->GetChans())
		{
			ch->SetTopic(CString());

			CString chname = ch->GetName().substr(1);
			CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));
		}
	}

	if(GetArgs().Token(0) != "FrankerZ")
		lastFrankerZ = std::numeric_limits<decltype(lastFrankerZ)>::max();

	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/tags");

	return true;
}

bool TwitchTMI::OnBoot()
{
	initCurl();

	timer = new TwitchTMIUpdateTimer(this);
	AddTimer(timer);

	return true;
}

void TwitchTMI::OnIRCConnected()
{
	PutIRC("CAP REQ :twitch.tv/membership");
	PutIRC("CAP REQ :twitch.tv/tags");
}

CModule::EModRet TwitchTMI::OnUserRaw(CString &sLine)
{
	if(sLine.Left(5).Equals("WHO #"))
		return CModule::HALT;

	if(sLine.Left(5).Equals("AWAY "))
		return CModule::HALT;

	if(sLine.Left(12).Equals("TWITCHCLIENT"))
		return CModule::HALT;

	if(sLine.Left(9).Equals("JTVCLIENT"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnUserJoin(CString& sChannel, CString& sKey)
{
	CString chname = sChannel.substr(1);
	CThreadPool::Get().addJob(new TwitchTMIJob(this, chname));

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnPrivMessage(CPrivMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	return CModule::CONTINUE;
}

CModule::EModRet TwitchTMI::OnChanMessage(CChanMessage &Message)
{
	if(Message.GetNick().GetNick().Equals("jtv"))
		return CModule::HALT;

	if(Message.GetText() == "FrankerZ" && std::time(nullptr) - lastFrankerZ > 10)
	{
		std::stringstream ss1, ss2;
		CString mynick = GetNetwork()->GetIRCNick().GetNickMask();
		CChan *chan = Message.GetChan();

		ss1 << "PRIVMSG " << chan->GetName() << " :FrankerZ";
		ss2 << ":" << mynick << " PRIVMSG " << chan->GetName() << " :";

		PutIRC(ss1.str());
		CString s2 = ss2.str();

		CThreadPool::Get().addJob(new GenericJob([]() {}, [this, s2, chan]()
		{
			PutUser(s2 + "FrankerZ");

			if(!chan->AutoClearChanBuffer() || !GetNetwork()->IsUserOnline() || chan->IsDetached()) {
				chan->AddBuffer(s2+ "{text}", "FrankerZ");
			}
		}));

		lastFrankerZ = std::time(nullptr);
	}

	return CModule::CONTINUE;
}

bool TwitchTMI::OnServerCapAvailable(const CString &sCap)
{
	if(sCap == "twitch.tv/membership")
	{
		CUtils::PrintMessage("TwitchTMI: Requesting twitch.tv/membership cap");
		return true;
	}
	else if(sCap == "twitch.tv/tags")
	{
		CUtils::PrintMessage("TwitchTMI: Requesting twitch.tv/tags cap");
		return true;
	}

	CUtils::PrintMessage(CString("TwitchTMI: Not requesting ") + sCap + " cap");

	return false;
}

TwitchTMIUpdateTimer::TwitchTMIUpdateTimer(TwitchTMI *tmod)
	:CTimer(tmod, 30, 0, "TwitchTMIUpdateTimer", "Downloads Twitch information")
	,mod(tmod)
{
}

void TwitchTMIUpdateTimer::RunJob()
{
	if(!mod->GetNetwork())
		return;

	for(CChan *chan: mod->GetNetwork()->GetChans())
	{
		CString chname = chan->GetName().substr(1);
		CThreadPool::Get().addJob(new TwitchTMIJob(mod, chname));
	}
}

void TwitchTMIJob::runThread()
{
	std::stringstream ss;
	ss << "https://api.twitch.tv/kraken/channels/" << channel;

	CString url = ss.str();

	Json::Value root = getJsonFromUrl(url.c_str(), "Accept: application/vnd.twitchtv.v3+json");

	if(root.isNull())
	{
		return;
	}

	Json::Value &titleVal = root["status"];
	title = CString();

	if(!titleVal.isString())
		titleVal = root["title"];

	if(!titleVal.isString())
		return;

	title = titleVal.asString();
	title.Trim();
}

void TwitchTMIJob::runMain()
{
	if(title.empty())
		return;

	CChan *chan = mod->GetNetwork()->FindChan(CString("#") + channel);

	if(!chan)
		return;

	if(chan->GetTopic() != title)
	{
		chan->SetTopic(title);
		chan->SetTopicOwner("jtv");
		chan->SetTopicDate((unsigned long)time(nullptr));

		std::stringstream ss;
		ss << ":jtv TOPIC #" << channel << " :" << title;

		mod->PutUser(ss.str());
	}
}

template<> void TModInfo<TwitchTMI>(CModInfo &info)
{
	info.SetWikiPage("Twitch");
	info.SetHasArgs(true);
}

NETWORKMODULEDEFS(TwitchTMI, "Twitch IRC helper module")
<|endoftext|>