<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GUICHAN_HPP
#define GCN_GUICHAN_HPP

#include <guichan/actionlistener.hpp>
#include <guichan/graphics.hpp>
#include <guichan/color.hpp>
#include <guichan/exception.hpp>
#include <guichan/focushandler.hpp>
#include <guichan/font.hpp>
#include <guichan/gui.hpp>
#include <guichan/image.hpp>
#include <guichan/imagefont.hpp>
#include <guichan/imageloader.hpp>
#include <guichan/input.hpp>
#include <guichan/key.hpp>
#include <guichan/keyinput.hpp>
#include <guichan/keylistener.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseinput.hpp>
#include <guichan/mouselistener.hpp>
#include <guichan/rectangle.hpp>
#include <guichan/cliprectangle.hpp>

#include <guichan/widget.hpp>

#include <guichan/widgets/button.hpp>
#include <guichan/widgets/checkbox.hpp>
#include <guichan/widgets/container.hpp>
#include <guichan/widgets/dropdown.hpp>
#include <guichan/widgets/icon.hpp>
#include <guichan/widgets/label.hpp>
#include <guichan/widgets/listbox.hpp>
#include <guichan/widgets/scrollarea.hpp>
#include <guichan/widgets/slider.hpp>
#include <guichan/widgets/radiobutton.hpp>
#include <guichan/widgets/textbox.hpp>
#include <guichan/widgets/textfield.hpp>
#include <guichan/widgets/window.hpp>

#include "guichan/platform.hpp"

class Widget;

extern "C"
{
    /**
     * Gets the the version of Guichan. As it is a C function
     * it can be used to check for Guichan with autotools.
     *
     * @return the version of Guichan.
     */
    GCN_CORE_DECLSPEC extern const char* gcnGuichanVersion();
}

#endif // end GCN_GUICHAN_HPP
<commit_msg>------------------------------------------------------------------- New files have been added.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GUICHAN_HPP
#define GCN_GUICHAN_HPP

#include <guichan/actionevent.hpp>
#include <guichan/actionlistener.hpp>
#include <guichan/graphics.hpp>
#include <guichan/color.hpp>
#include <guichan/event.hpp>
#include <guichan/exception.hpp>
#include <guichan/focushandler.hpp>
#include <guichan/font.hpp>
#include <guichan/gui.hpp>
#include <guichan/image.hpp>
#include <guichan/imagefont.hpp>
#include <guichan/imageloader.hpp>
#include <guichan/input.hpp>
#include <guichan/inputevent.hpp>
#include <guichan/key.hpp>
#include <guichan/keyevent.hpp>
#include <guichan/keyinput.hpp>
#include <guichan/keylistener.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseevent.hpp>
#include <guichan/mouseinput.hpp>
#include <guichan/mouselistener.hpp>
#include <guichan/rectangle.hpp>
#include <guichan/cliprectangle.hpp>

#include <guichan/widget.hpp>

#include <guichan/widgets/button.hpp>
#include <guichan/widgets/checkbox.hpp>
#include <guichan/widgets/container.hpp>
#include <guichan/widgets/dropdown.hpp>
#include <guichan/widgets/icon.hpp>
#include <guichan/widgets/label.hpp>
#include <guichan/widgets/listbox.hpp>
#include <guichan/widgets/scrollarea.hpp>
#include <guichan/widgets/slider.hpp>
#include <guichan/widgets/radiobutton.hpp>
#include <guichan/widgets/textbox.hpp>
#include <guichan/widgets/textfield.hpp>
#include <guichan/widgets/window.hpp>

#include "guichan/platform.hpp"

class Widget;

extern "C"
{
    /**
     * Gets the the version of Guichan. As it is a C function
     * it can be used to check for Guichan with autotools.
     *
     * @return the version of Guichan.
     */
    GCN_CORE_DECLSPEC extern const char* gcnGuichanVersion();
}

#endif // end GCN_GUICHAN_HPP
<|endoftext|>


<commit_before><commit_msg>Update for latest ctrulib.<commit_after><|endoftext|>


<commit_before>#include <QtWidgets>

#include "../event.h"
#include "../osd.h"
#include "../error.h"
#include "../pc6001v.h"
#include "../typedef.h"
#include "../console.h"
#include "../error.h"
#include "../osd.h"

#include "renderview.h"
#include "qtp6vxapplication.h"

///////////////////////////////////////////////////////////
// フォントファイルチェック(無ければ作成する)
///////////////////////////////////////////////////////////
bool CheckFont( void )
{
    char FontFile[PATH_MAX];
    bool ret = true;

    sprintf( FontFile, "%s%s/%s", OSD_GetConfigPath(), FONT_DIR, FONTH_FILE );
    ret |= ( !OSD_FileExist( FontFile ) && !OSD_CreateFont( FontFile, NULL, FSIZE ) );

    sprintf( FontFile, "%s%s/%s", OSD_GetConfigPath(), FONT_DIR, FONTZ_FILE );
    ret |= ( !OSD_FileExist( FontFile ) && !OSD_CreateFont( NULL, FontFile, FSIZE ) );

    return ret;
}

///////////////////////////////////////////////////////////
// ROMファイル存在チェック&機種変更
///////////////////////////////////////////////////////////
bool SerchRom( CFG6 *cfg )
{
    char RomSerch[PATH_MAX];

    int IniModel = cfg->GetModel();
    sprintf( RomSerch, "%s*.%2d", cfg->GetRomPath(), IniModel );
    if( OSD_FileExist( RomSerch ) ){
        Error::SetError( Error::NoError );
        return true;
    }

    int models[] = { 60, 62, 66 };
    for( int i=0; i < COUNTOF(models); i++ ){
        sprintf( RomSerch, "%s*.%2d", cfg->GetRomPath(), models[i] );
        if( OSD_FileExist( RomSerch ) ){
            cfg->SetModel( models[i] );
            cfg->Write();
            Error::SetError( Error::RomChange );
            return true;
        }
    }
    Error::SetError( Error::NoRom );
    return false;
}

QtP6VXApplication::QtP6VXApplication(int &argc, char **argv) :
    QtSingleApplication(argc, argv)
  , P6Core(NULL)
  , Restart(EL6::Quit)
  , Adaptor(new EmulationAdaptor())
{
    //HWINDOWという型名をシグナルの引数として使えるようにする
    qRegisterMetaType<HWINDOW>("HWINDOW");

    // エミュレーションコア部分用スレッドを生成
    QThread* emulationThread = new QThread(this);
    emulationThread->start();
    Adaptor->moveToThread(emulationThread);

    //ウィンドウを閉じても終了しない。
    //終了はEL6::Quitが返ってきた時に行う。
    setQuitOnLastWindowClosed (false);

    connect(this, SIGNAL(initialized()), this, SLOT(executeEmulation()));
    connect(this, SIGNAL(vmPrepared()), Adaptor, SLOT(doEventLoop()));
    connect(this, SIGNAL(vmRestart()), this, SLOT(executeEmulation()));
    connect(this, SIGNAL(lastWindowClosed()), this, SLOT(terminateEmulation()));
    connect(Adaptor, SIGNAL(finished()), this, SLOT(postExecuteEmulation()));
}

QtP6VXApplication::~QtP6VXApplication()
{
    Adaptor->thread()->exit();
    Adaptor->deleteLater();
}

void QtP6VXApplication::startup()
{
    // 二重起動禁止
    if( isRunning() ) exit();

    // 設定ファイルパスを作成
    if(!OSD_CreateConfigPath()) exit();

    // OSD関連初期化
    if( !OSD_Init() ){
        Error::SetError( Error::InitFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        OSD_Quit();	// 終了処理
        exit();
    }

    // フォントファイルチェック
    if( !CheckFont() ){
        Error::SetError( Error::FontCreateFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
        Error::SetError( Error::NoError );
    }

    // コンソール用フォント読込み
    char FontZ[PATH_MAX], FontH[PATH_MAX];
    sprintf( FontZ, ":/res/%s/%s", FONT_DIR, FONTZ_FILE );
    sprintf( FontH, ":/res/%s/%s", FONT_DIR, FONTH_FILE );
    if( !JFont::OpenFont( FontZ, FontH ) ){
        Error::SetError( Error::FontLoadFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        Error::SetError( Error::NoError );
    }

    // INIファイル読込み
    if( !Cfg.Init() ){
        switch( Error::GetError() ){
        case Error::IniDefault:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
            break;

        default:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            OSD_Quit();			// 終了処理
            exit();
        }
    }

    emit initialized();
}

void QtP6VXApplication::createWindow(HWINDOW Wh, int bpp, bool fsflag)
{
    RenderView* view = static_cast<RenderView*>(Wh);
    Q_ASSERT(view);
    QGraphicsScene* scene = view->scene();

    OSD_ClearWindow(Wh);
    if(fsflag){
        view->showFullScreen();
    } else {
        view->showNormal();
        //qDebug("scene:%dx%d view:%dx%d", scene->width(), scene->height(), view->width(), view->height());
        //Windowsではウィンドウ表示が完了しきらないうちにresize()を呼ぶと
        //タイトルバーが画面からはみ出るので、適当に左上にマージンを取る。
        view->setGeometry(100, 100, scene->width(), scene->height());
    }
    view->fitContent();
}

void QtP6VXApplication::layoutBitmap(HWINDOW Wh, int x, int y, double aspect, QImage image)
{
    //QtではSceneRectの幅を返す
    QGraphicsView* view = static_cast<QGraphicsView*>(Wh);
    Q_ASSERT(view);
    QGraphicsScene* scene = view->scene();

    // 指定座標に生成済みのQPixmapItemが存在するかチェック
    // (同一座標にビットマップが重なることはないという前提)
    QGraphicsItem* item = NULL;
    QGraphicsPixmapItem* pItem = NULL;
    foreach(item, scene->items()){
        if(item->scenePos() == QPointF(x, y)){
            pItem = dynamic_cast<QGraphicsPixmapItem*>(item);
            break;
        }
    }

    if(pItem == NULL){
        // 既存のQPixmapItemが存在しない場合は生成
        pItem = new QGraphicsPixmapItem(NULL);
        scene->addItem(pItem);
        pItem->setTransformationMode(Qt::SmoothTransformation);
        QTransform trans;
        trans.scale(1, aspect);
        trans.translate(x, y);
        pItem->setTransform(trans);
    }
    pItem->setPixmap(QPixmap::fromImage(image));

}

void QtP6VXApplication::clearLayout(HWINDOW Wh)
{
    QGraphicsView* view = static_cast<QGraphicsView*>(Wh);
    Q_ASSERT(view);
    Q_ASSERT(view->scene());
    view->scene()->clear();
}

void QtP6VXApplication::showPopupMenu(int x, int y)
{
    P6Core->Stop();
    P6Core->ShowPopupImpl(x, y);
    P6Core->Start();
}

//仮想マシンを開始させる
void QtP6VXApplication::executeEmulation()
{
    // ROMファイル存在チェック&機種変更
    if( SerchRom( &Cfg ) ){
        if( Error::GetError() != Error::NoError ){
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDM_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
        }
    }else{
        if(OSD_Message( QString("ROMファイルが見つかりません。\n"
                                "ROMフォルダ(%1)にROMファイルをコピーするか、"
                                "別のROMフォルダを指定してください。\n"
                                "別のROMフォルダを指定しますか?").arg(Cfg.GetRomPath()).toUtf8().data(), MSERR_ERROR, OSDM_YESNO | OSDM_ICONERROR ) == OSDR_YES){
            //ROMフォルダ再設定
            char folder[PATH_MAX];
            strncpy(folder, Cfg.GetRomPath(), PATH_MAX);
            Delimiter(folder);
            OSD_FolderDiaog(NULL, folder);
            UnDelimiter(folder);

            if(strlen(folder) > 0){
                Cfg.SetRomPath(folder);
                Cfg.Write();
                Restart = EL6::Restart;
            } else {
                exit();
            }
        } else {
            exit();
        }
        emit vmRestart();
        return;
    }

    // 機種別P6オブジェクト確保
    P6Core = new QtEL6;
    if( !P6Core ){
        exit();
    }

    // VM初期化
    if( !P6Core->Init( &Cfg ) ){
        if(Error::GetError() == Error::RomCrcNG){
            // CRCが合わない場合
            int ret = OSD_Message( "ROMイメージのCRCが不正です。\n"
                                   "CRCが一致しないROMを使用すると、予期せぬ不具合を引き起こす可能性があります。\n"
                                   "それでも起動しますか?",
                                   MSERR_ERROR, OSDM_YESNO | OSDM_ICONWARNING );
            if(ret == OSDR_YES) {
                Cfg.SetCheckCRC(false);
                Cfg.Write();
                Restart = EL6::Restart;
            }
        } else {
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            exit();
        }
    }

    switch( Restart ){
    case EL6::Dokoload:	// どこでもLOAD?
        P6Core->DokoDemoLoad( Cfg.GetDokoFile() );
        break;

    case EL6::Replay:	// リプレイ再生?
    {
        char temp[PATH_MAX];
        strncpy( temp, Cfg.GetDokoFile(), PATH_MAX );
        P6Core->DokoDemoLoad( temp );
        P6Core->REPLAY::StartReplay( temp );
    }
        break;

    default:
        break;
    }

    // VM実行
    Adaptor->setEmulationObj(P6Core);
    emit vmPrepared();
    P6Core->Start();
}

//仮想マシン終了後の処理
void QtP6VXApplication::postExecuteEmulation()
{
    Restart = Adaptor->getReturnCode();
    Adaptor->setEmulationObj(NULL);
    P6Core->Stop();
    delete P6Core;	// P6オブジェクトを開放
    P6Core = NULL;

    // 再起動ならばINIファイル再読込み
    if( Restart == EL6::Restart ){
        if( !Cfg.Init() ){
            Error::SetError( Error::IniDefault );
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
        }
    }

    if( Restart == EL6::Quit ){
        // 終了処理
        OSD_Quit();
        exit();
    } else {
        emit vmRestart();
    }
}

void QtP6VXApplication::terminateEmulation()
{
    OSD_PushEvent( EV_QUIT );
}

bool QtP6VXApplication::notify ( QObject * receiver, QEvent * event )
{
    Event ev;
    ev.type = EV_NOEVENT;

    switch(event->type()){
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    {
        QKeyEvent* ke = dynamic_cast<QKeyEvent*>(event);
        Q_ASSERT(ke);
        int keyCode = ke->key();

        // 「ろ」が入力できない対策
        quint32 nativeKey = ke->nativeScanCode();
        //X11の場合
        if (QGuiApplication::platformName() == QLatin1String("xcb")){
            if(keyCode == Qt::Key_Backslash){
                keyCode = nativeKey == 97 ? Qt::Key_Underscore : Qt::Key_Backslash;
            }
        }

        ev.type        = event->type() == QEvent::KeyPress ? EV_KEYDOWN : EV_KEYUP;
        ev.key.state   = event->type() == QEvent::KeyPress ? true : false;
        ev.key.sym     = OSD_ConvertKeyCode( keyCode );
        ev.key.mod	   = (PCKEYmod)(
                    ( ke->modifiers() & Qt::ShiftModifier ? KVM_SHIFT : KVM_NONE )
                    | ( ke->modifiers() & Qt::ControlModifier ? KVM_CTRL : KVM_NONE )
                    | ( ke->modifiers() & Qt::AltModifier ? KVM_ALT : KVM_NONE )
                    | ( ke->modifiers() & Qt::MetaModifier ? KVM_META : KVM_NONE )
                    | ( ke->modifiers() & Qt::KeypadModifier ? KVM_NUM : KVM_NONE )
                    //#PENDING CAPSLOCKは検出できない？
                    //| ( ke->modifiers() & Qt::caps ? KVM_NUM : KVM_NONE )
                    );
        ev.key.unicode = ke->text().utf16()[0];
        OSD_PushEvent(ev);
        break;
    }
    case QEvent::ContextMenu:
    {
        ev.type        = EV_CONTEXTMENU;
        OSD_PushEvent(ev.type);
        break;
    }
    default:;
    }

    if(ev.type == EV_NOEVENT){
        return QtSingleApplication::notify(receiver, event);
    } else {
        return true;
    }
}
<commit_msg>lastWindowClosedで閉じるようにするタイミングを変更 (メインウィンドウが上がる前のダイアログクローズなどで終了しないように)<commit_after>#include <QtWidgets>

#include "../event.h"
#include "../osd.h"
#include "../error.h"
#include "../pc6001v.h"
#include "../typedef.h"
#include "../console.h"
#include "../error.h"
#include "../osd.h"

#include "renderview.h"
#include "qtp6vxapplication.h"

///////////////////////////////////////////////////////////
// フォントファイルチェック(無ければ作成する)
///////////////////////////////////////////////////////////
bool CheckFont( void )
{
    char FontFile[PATH_MAX];
    bool ret = true;

    sprintf( FontFile, "%s%s/%s", OSD_GetConfigPath(), FONT_DIR, FONTH_FILE );
    ret |= ( !OSD_FileExist( FontFile ) && !OSD_CreateFont( FontFile, NULL, FSIZE ) );

    sprintf( FontFile, "%s%s/%s", OSD_GetConfigPath(), FONT_DIR, FONTZ_FILE );
    ret |= ( !OSD_FileExist( FontFile ) && !OSD_CreateFont( NULL, FontFile, FSIZE ) );

    return ret;
}

///////////////////////////////////////////////////////////
// ROMファイル存在チェック&機種変更
///////////////////////////////////////////////////////////
bool SerchRom( CFG6 *cfg )
{
    char RomSerch[PATH_MAX];

    int IniModel = cfg->GetModel();
    sprintf( RomSerch, "%s*.%2d", cfg->GetRomPath(), IniModel );
    if( OSD_FileExist( RomSerch ) ){
        Error::SetError( Error::NoError );
        return true;
    }

    int models[] = { 60, 62, 66 };
    for( int i=0; i < COUNTOF(models); i++ ){
        sprintf( RomSerch, "%s*.%2d", cfg->GetRomPath(), models[i] );
        if( OSD_FileExist( RomSerch ) ){
            cfg->SetModel( models[i] );
            cfg->Write();
            Error::SetError( Error::RomChange );
            return true;
        }
    }
    Error::SetError( Error::NoRom );
    return false;
}

QtP6VXApplication::QtP6VXApplication(int &argc, char **argv) :
    QtSingleApplication(argc, argv)
  , P6Core(NULL)
  , Restart(EL6::Quit)
  , Adaptor(new EmulationAdaptor())
{
    //HWINDOWという型名をシグナルの引数として使えるようにする
    qRegisterMetaType<HWINDOW>("HWINDOW");

    // エミュレーションコア部分用スレッドを生成
    QThread* emulationThread = new QThread(this);
    emulationThread->start();
    Adaptor->moveToThread(emulationThread);

    //ウィンドウを閉じても終了しない。
    //終了はEL6::Quitが返ってきた時に行う。
    setQuitOnLastWindowClosed (false);

    connect(this, SIGNAL(initialized()), this, SLOT(executeEmulation()));
    connect(this, SIGNAL(vmPrepared()), Adaptor, SLOT(doEventLoop()));
    connect(this, SIGNAL(vmRestart()), this, SLOT(executeEmulation()));
    connect(Adaptor, SIGNAL(finished()), this, SLOT(postExecuteEmulation()));
}

QtP6VXApplication::~QtP6VXApplication()
{
    Adaptor->thread()->exit();
    Adaptor->deleteLater();
}

void QtP6VXApplication::startup()
{
    // 二重起動禁止
    if( isRunning() ) exit();

    // 設定ファイルパスを作成
    if(!OSD_CreateConfigPath()) exit();

    // OSD関連初期化
    if( !OSD_Init() ){
        Error::SetError( Error::InitFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        OSD_Quit();	// 終了処理
        exit();
    }

    // フォントファイルチェック
    if( !CheckFont() ){
        Error::SetError( Error::FontCreateFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
        Error::SetError( Error::NoError );
    }

    // コンソール用フォント読込み
    char FontZ[PATH_MAX], FontH[PATH_MAX];
    sprintf( FontZ, ":/res/%s/%s", FONT_DIR, FONTZ_FILE );
    sprintf( FontH, ":/res/%s/%s", FONT_DIR, FONTH_FILE );
    if( !JFont::OpenFont( FontZ, FontH ) ){
        Error::SetError( Error::FontLoadFailed );
        OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
        Error::SetError( Error::NoError );
    }

    // INIファイル読込み
    if( !Cfg.Init() ){
        switch( Error::GetError() ){
        case Error::IniDefault:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
            break;

        default:
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            OSD_Quit();			// 終了処理
            exit();
        }
    }

    emit initialized();
}

void QtP6VXApplication::createWindow(HWINDOW Wh, int bpp, bool fsflag)
{
    RenderView* view = static_cast<RenderView*>(Wh);
    Q_ASSERT(view);
    QGraphicsScene* scene = view->scene();

    OSD_ClearWindow(Wh);
    if(fsflag){
        view->showFullScreen();
    } else {
        view->showNormal();
        //qDebug("scene:%dx%d view:%dx%d", scene->width(), scene->height(), view->width(), view->height());
        //Windowsではウィンドウ表示が完了しきらないうちにresize()を呼ぶと
        //タイトルバーが画面からはみ出るので、適当に左上にマージンを取る。
        view->setGeometry(100, 100, scene->width(), scene->height());
    }
    view->fitContent();
}

void QtP6VXApplication::layoutBitmap(HWINDOW Wh, int x, int y, double aspect, QImage image)
{
    //QtではSceneRectの幅を返す
    QGraphicsView* view = static_cast<QGraphicsView*>(Wh);
    Q_ASSERT(view);
    QGraphicsScene* scene = view->scene();

    // 指定座標に生成済みのQPixmapItemが存在するかチェック
    // (同一座標にビットマップが重なることはないという前提)
    QGraphicsItem* item = NULL;
    QGraphicsPixmapItem* pItem = NULL;
    foreach(item, scene->items()){
        if(item->scenePos() == QPointF(x, y)){
            pItem = dynamic_cast<QGraphicsPixmapItem*>(item);
            break;
        }
    }

    if(pItem == NULL){
        // 既存のQPixmapItemが存在しない場合は生成
        pItem = new QGraphicsPixmapItem(NULL);
        scene->addItem(pItem);
        pItem->setTransformationMode(Qt::SmoothTransformation);
        QTransform trans;
        trans.scale(1, aspect);
        trans.translate(x, y);
        pItem->setTransform(trans);
    }
    pItem->setPixmap(QPixmap::fromImage(image));

}

void QtP6VXApplication::clearLayout(HWINDOW Wh)
{
    QGraphicsView* view = static_cast<QGraphicsView*>(Wh);
    Q_ASSERT(view);
    Q_ASSERT(view->scene());
    view->scene()->clear();
}

void QtP6VXApplication::showPopupMenu(int x, int y)
{
    P6Core->Stop();
    P6Core->ShowPopupImpl(x, y);
    P6Core->Start();
}

//仮想マシンを開始させる
void QtP6VXApplication::executeEmulation()
{
    // ROMファイル存在チェック&機種変更
    if( SerchRom( &Cfg ) ){
        if( Error::GetError() != Error::NoError ){
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDM_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
        }
    }else{
        if(OSD_Message( QString("ROMファイルが見つかりません。\n"
                                "ROMフォルダ(%1)にROMファイルをコピーするか、"
                                "別のROMフォルダを指定してください。\n"
                                "別のROMフォルダを指定しますか?").arg(Cfg.GetRomPath()).toUtf8().data(), MSERR_ERROR, OSDM_YESNO | OSDM_ICONERROR ) == OSDR_YES){
            //ROMフォルダ再設定
            char folder[PATH_MAX];
            strncpy(folder, Cfg.GetRomPath(), PATH_MAX);
            Delimiter(folder);
            OSD_FolderDiaog(NULL, folder);
            UnDelimiter(folder);

            if(strlen(folder) > 0){
                Cfg.SetRomPath(folder);
                Cfg.Write();
                Restart = EL6::Restart;
            } else {
                exit();
            }
        } else {
            exit();
        }
        emit vmRestart();
        return;
    }

    // 機種別P6オブジェクト確保
    P6Core = new QtEL6;
    if( !P6Core ){
        exit();
    }

    // VM初期化
    if( !P6Core->Init( &Cfg ) ){
        if(Error::GetError() == Error::RomCrcNG){
            // CRCが合わない場合
            int ret = OSD_Message( "ROMイメージのCRCが不正です。\n"
                                   "CRCが一致しないROMを使用すると、予期せぬ不具合を引き起こす可能性があります。\n"
                                   "それでも起動しますか?",
                                   MSERR_ERROR, OSDM_YESNO | OSDM_ICONWARNING );
            if(ret == OSDR_YES) {
                Cfg.SetCheckCRC(false);
                Cfg.Write();
                Restart = EL6::Restart;
            }
        } else {
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONERROR );
            exit();
        }
    }

    switch( Restart ){
    case EL6::Dokoload:	// どこでもLOAD?
        P6Core->DokoDemoLoad( Cfg.GetDokoFile() );
        break;

    case EL6::Replay:	// リプレイ再生?
    {
        char temp[PATH_MAX];
        strncpy( temp, Cfg.GetDokoFile(), PATH_MAX );
        P6Core->DokoDemoLoad( temp );
        P6Core->REPLAY::StartReplay( temp );
    }
        break;

    default:
        break;
    }

    // 以降、ウィンドウが閉じたらアプリを終了する
    connect(this, SIGNAL(lastWindowClosed()), this, SLOT(terminateEmulation()));

    // VM実行
    Adaptor->setEmulationObj(P6Core);
    emit vmPrepared();
    P6Core->Start();
}

//仮想マシン終了後の処理
void QtP6VXApplication::postExecuteEmulation()
{
    Restart = Adaptor->getReturnCode();
    Adaptor->setEmulationObj(NULL);
    P6Core->Stop();
    delete P6Core;	// P6オブジェクトを開放
    P6Core = NULL;

    // 再起動ならばINIファイル再読込み
    if( Restart == EL6::Restart ){
        if( !Cfg.Init() ){
            Error::SetError( Error::IniDefault );
            OSD_Message( (char *)Error::GetErrorText(), MSERR_ERROR, OSDR_OK | OSDM_ICONWARNING );
            Error::SetError( Error::NoError );
        }
    }

    if( Restart == EL6::Quit ){
        // 終了処理
        OSD_Quit();
        exit();
    } else {
        emit vmRestart();
    }
}

void QtP6VXApplication::terminateEmulation()
{
    OSD_PushEvent( EV_QUIT );
}

bool QtP6VXApplication::notify ( QObject * receiver, QEvent * event )
{
    Event ev;
    ev.type = EV_NOEVENT;

    switch(event->type()){
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    {
        QKeyEvent* ke = dynamic_cast<QKeyEvent*>(event);
        Q_ASSERT(ke);
        int keyCode = ke->key();

        // 「ろ」が入力できない対策
        quint32 nativeKey = ke->nativeScanCode();
        //X11の場合
        if (QGuiApplication::platformName() == QLatin1String("xcb")){
            if(keyCode == Qt::Key_Backslash){
                keyCode = nativeKey == 97 ? Qt::Key_Underscore : Qt::Key_Backslash;
            }
        }

        ev.type        = event->type() == QEvent::KeyPress ? EV_KEYDOWN : EV_KEYUP;
        ev.key.state   = event->type() == QEvent::KeyPress ? true : false;
        ev.key.sym     = OSD_ConvertKeyCode( keyCode );
        ev.key.mod	   = (PCKEYmod)(
                    ( ke->modifiers() & Qt::ShiftModifier ? KVM_SHIFT : KVM_NONE )
                    | ( ke->modifiers() & Qt::ControlModifier ? KVM_CTRL : KVM_NONE )
                    | ( ke->modifiers() & Qt::AltModifier ? KVM_ALT : KVM_NONE )
                    | ( ke->modifiers() & Qt::MetaModifier ? KVM_META : KVM_NONE )
                    | ( ke->modifiers() & Qt::KeypadModifier ? KVM_NUM : KVM_NONE )
                    //#PENDING CAPSLOCKは検出できない？
                    //| ( ke->modifiers() & Qt::caps ? KVM_NUM : KVM_NONE )
                    );
        ev.key.unicode = ke->text().utf16()[0];
        OSD_PushEvent(ev);
        break;
    }
    case QEvent::ContextMenu:
    {
        ev.type        = EV_CONTEXTMENU;
        OSD_PushEvent(ev.type);
        break;
    }
    default:;
    }

    if(ev.type == EV_NOEVENT){
        return QtSingleApplication::notify(receiver, event);
    } else {
        return true;
    }
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "TiRootObject.h"

#include "NativeStringInterface.h"
#include "TiGenericFunctionObject.h"
#include "TiLogger.h"
#include "TiMessageStrings.h"
#include "TiTitaniumObject.h"
#include "TiTimeoutManager.h"
#include "TiV8EventContainerFactory.h"

#include <fstream>
#include <sstream>

#include <QString>
#include <QUrl>

static Handle<ObjectTemplate> g_rootTemplate;

TiRootObject::TiRootObject()
    : TiObject("")
{
}

TiRootObject::~TiRootObject()
{
    if (!context_.IsEmpty())
    {
        context_.Dispose();
    }
    NativeStringInterface::deleteInstance();
}

void TiRootObject::onCreateStaticMembers()
{
    TiObject* ti = TiTitaniumObject::createObject(objectFactory_);
    addMember(ti);
    addMember(ti, "Ti");

    createStringMethods();
    TiGenericFunctionObject::addGenericFunctionToParent(this, "L", this, _L);   // TODO: use the same object as Ti.Locale.getString
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearInterval", this, _clearInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearTimeout", this, _clearTimeout);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "require", this, _require);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setInterval", this, _setInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setTimeout", this, _setTimeout);
}

VALUE_MODIFY TiRootObject::onChildValueChange(TiObject* childObject, Handle<Value>, Handle<Value> newValue)
{
    Local<Object> obj = getValue()->ToObject();
    obj->Set(String::New(childObject->getName()), newValue);
    return VALUE_MODIFY_ALLOW;
}

void TiRootObject::addMember(TiObject* object, const char* name)
{
    TiObject::addMember(object, name);
    if (name == NULL)
    {
        name = object->getName();
    }
    Handle<Object> obj = getValue()->ToObject();
    Handle<Value> newValue = object->getValue();
    if (newValue.IsEmpty())
    {
        newValue = globalTemplate_->NewInstance();
        object->forceSetValue(newValue);
        TiObject::setTiObjectToJsObject(newValue, object);
    }
    obj->Set(String::New(name), newValue);
}

TiRootObject* TiRootObject::createRootObject()
{
    TiRootObject* obj = new TiRootObject;
    return obj;
}

int TiRootObject::executeScript(NativeObjectFactory* objectFactory, const char* javaScript,
                                MESSAGELOOPENTRY messageLoopEntry, void* context)
{
    HandleScope handleScope;
    objectFactory_ = objectFactory;
    globalTemplate_ = ObjectTemplate::New();
    TiV8EventContainerFactory* eventFactory = TiV8EventContainerFactory::createEventContainerFactory(globalTemplate_);
    objectFactory->setEventContainerFactory(eventFactory);
    onSetGetPropertyCallback(&globalTemplate_);
    onSetFunctionCallback(&globalTemplate_);
    g_rootTemplate = ObjectTemplate::New();
    context_ = Context::New(NULL, g_rootTemplate);
    forceSetValue(context_->Global());
    context_->Global()->SetHiddenValue(String::New("globalTemplate_"), External::New(&globalTemplate_));
    context_->Global()->SetHiddenValue(String::New("context_"), External::New(&context_));
    setTiObjectToJsObject(context_->Global(), this);
    Context::Scope context_scope(context_);
    initializeTiObject(NULL);

    const char* bootstrapFilename = "bootstrap.js";
    string bootstrapJavascript;
    {
        ifstream ifs((string("app/native/framework/") + bootstrapFilename).c_str());
        if (!ifs)
        {
            TiLogger::getInstance().log(Ti::Msg::ERROR__Cannot_load_bootstrap_js);
            return -1;
        }
        getline(ifs, bootstrapJavascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    TryCatch tryCatch;
    Handle<Script> compiledBootstrapScript = Script::Compile(String::New(bootstrapJavascript.c_str()), String::New(bootstrapFilename));
    if (compiledBootstrapScript.IsEmpty())
    {
        String::Utf8Value error(tryCatch.Exception());
        TiLogger::getInstance().log(*error);
        return -1;
    }
    Handle<Value> bootstrapResult = compiledBootstrapScript->Run();
    if (bootstrapResult.IsEmpty())
    {
        Local<Value> exception = tryCatch.Exception();
        // FIXME: need a way to prevent double "filename + line" output
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << bootstrapFilename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber();
        }
        ss << ": " << *String::Utf8Value(exception);
        TiLogger::getInstance().log(ss.str());
        return -1;
    }

    const char* filename = "app.js";
    Handle<Script> compiledScript = Script::Compile(String::New(javaScript), String::New(filename));
    if (compiledScript.IsEmpty())
    {
        String::Utf8Value error(tryCatch.Exception());
        TiLogger::getInstance().log(*error);
        return -1;
    }
    Handle<Value> result = compiledScript->Run();
    if (result.IsEmpty())
    {
        Local<Value> exception = tryCatch.Exception();
        // FIXME: need a way to prevent double "filename + line" output
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << filename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber();
        }
        ss << ": " << *String::Utf8Value(exception);
        TiLogger::getInstance().log(ss.str());
        return -1;
    }
    onStartMessagePump();
    return (messageLoopEntry)(context);
}

void TiRootObject::createStringMethods()
{
    Local<Value> str = context_->Global()->Get(String::New("String"));
    if (!str->IsObject())
    {
        // This should never happen
        ThrowException(String::New(Ti::Msg::INTERNAL__Global_String_symbol_is_not_an_object));
    }
    Local<Object> strObj = str->ToObject();
    const NativeStringInterface* nsi = objectFactory_->getNativeStringInterface();
    strObj->Set(String::New("format"), FunctionTemplate::New(nsi->format)->GetFunction());
    strObj->Set(String::New("formatCurrency"), FunctionTemplate::New(nsi->formatCurrency)->GetFunction());
    strObj->Set(String::New("formatDate"), FunctionTemplate::New(nsi->formatDate)->GetFunction());
    strObj->Set(String::New("formatDecimal"), FunctionTemplate::New(nsi->formatDecimal)->GetFunction());
    strObj->Set(String::New("formatTime"), FunctionTemplate::New(nsi->formatTime)->GetFunction());
}

/* Methods defined by Global */
Handle<Value> TiRootObject::_L(void*, TiObject*, const Arguments& args)
{
    // TODO: finish this
    return args[0];
}

Handle<Value> TiRootObject::_clearInterval(void*, TiObject*, const Arguments& args)
{
    if ((args.Length() != 1) || (!args[0]->IsNumber()))
    {
        return ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    clearTimeoutHelper(args, true);
    return Undefined();
}

Handle<Value> TiRootObject::_clearTimeout(void*, TiObject*, const Arguments& args)
{
    if ((args.Length() != 1) || (!args[0]->IsNumber()))
    {
        return ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    clearTimeoutHelper(args, false);
    return Undefined();
}

void TiRootObject::clearTimeoutHelper(const Arguments& args, bool interval)
{
    Handle<Number> number = Handle<Number>::Cast(args[0]);
    TiTimeoutManager* timeoutManager = TiTimeoutManager::instance();
    timeoutManager->clearTimeout((int)number->Value(), interval);
}

Handle<Value> TiRootObject::_require(void*, TiObject*, const Arguments& args)
{
    if (args.Length() < 1)
    {
        return ThrowException(String::New(Ti::Msg::Missing_argument));
    }

    Handle<String> v8Id = args[0]->ToString();
    string id = *String::Utf8Value(v8Id);

    // check if cached
    static map<string, Persistent<Value> > cache;
    // FIXME: caching the value doesn't work, the resulting object is not a Function after the first time
    /*map<string, Persistent<Value> >::const_iterator cachedValue = cache.find(id);
    if (cachedValue != cache.end())
    {
        return cachedValue->second;
    }*/

    string filename = id + ".js";
    // TODO: need to make this relative and support com.example.module
    static const string baseFolder = "app/native/assets/";
    string javascript;
    {
        ifstream ifs((baseFolder + filename).c_str());
        if (!ifs)
        {
            Local<Value> taggedMessage = String::New((string(Ti::Msg::No_such_native_module) + " " + id).c_str());
            return ThrowException(taggedMessage);
        }
        getline(ifs, javascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    // wrap the module
    {
        static const string preWrap = "(function () { var module = { exports: {} }; var exports = module.exports;\n";
        static const string postWrap = "\nreturn module.exports; })();";
        javascript = preWrap + javascript + postWrap;
    }

    // TODO: set the correct context

    TryCatch tryCatch;
    Handle<Script> compiledScript = Script::Compile(String::New(javascript.c_str()), String::New(filename.c_str()));
    if (compiledScript.IsEmpty())
    {
        return ThrowException(tryCatch.Exception());
    }
    Persistent<Value> result = (Persistent<Value>)compiledScript->Run();
    if (result.IsEmpty())
    {
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << filename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber() - 1; // -1 for the wrapper
        }
        ss << ": " << *String::Utf8Value(tryCatch.Exception());
        return ThrowException(String::New(ss.str().c_str()));
    }

    // cache result
    cache.insert(pair<string, Persistent<Value> >(id, result));

    return result;
}

Handle<Value> TiRootObject::_setInterval(void*, TiObject*, const Arguments& args)
{
    return setTimeoutHelper(args, true);
}

Handle<Value> TiRootObject::_setTimeout(void*, TiObject*, const Arguments& args)
{
    return setTimeoutHelper(args, false);
}

Handle<Value> TiRootObject::setTimeoutHelper(const Arguments& args, bool interval)
{
    HandleScope handleScope;
    if ((args.Length() != 2) || (!args[0]->IsFunction()) || (!args[1]->IsNumber()))
    {
        ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    Handle<Function> function = Handle<Function>::Cast(args[0]);
    Handle<Number> number = Handle<Number>::Cast(args[1]);
    TiTimeoutManager* timeoutManager = TiTimeoutManager::instance();
    int id = timeoutManager->createTimeout((int)number->Value(), function, interval);
    Handle<Number> timerId = Number::New(id);
    return timerId;
}
<commit_msg>Fix JS exception reporting.<commit_after>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "TiRootObject.h"

#include "NativeStringInterface.h"
#include "TiGenericFunctionObject.h"
#include "TiLogger.h"
#include "TiMessageStrings.h"
#include "TiTitaniumObject.h"
#include "TiTimeoutManager.h"
#include "TiV8EventContainerFactory.h"
#include "V8Utils.h"

#include <fstream>
#include <sstream>

#include <QString>
#include <QUrl>

static Handle<ObjectTemplate> g_rootTemplate;

TiRootObject::TiRootObject()
    : TiObject("")
{
}

TiRootObject::~TiRootObject()
{
    if (!context_.IsEmpty())
    {
        context_.Dispose();
    }
    NativeStringInterface::deleteInstance();
}

void TiRootObject::onCreateStaticMembers()
{
    TiObject* ti = TiTitaniumObject::createObject(objectFactory_);
    addMember(ti);
    addMember(ti, "Ti");

    createStringMethods();
    TiGenericFunctionObject::addGenericFunctionToParent(this, "L", this, _L);   // TODO: use the same object as Ti.Locale.getString
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearInterval", this, _clearInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "clearTimeout", this, _clearTimeout);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "require", this, _require);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setInterval", this, _setInterval);
    TiGenericFunctionObject::addGenericFunctionToParent(this, "setTimeout", this, _setTimeout);
}

VALUE_MODIFY TiRootObject::onChildValueChange(TiObject* childObject, Handle<Value>, Handle<Value> newValue)
{
    Local<Object> obj = getValue()->ToObject();
    obj->Set(String::New(childObject->getName()), newValue);
    return VALUE_MODIFY_ALLOW;
}

void TiRootObject::addMember(TiObject* object, const char* name)
{
    TiObject::addMember(object, name);
    if (name == NULL)
    {
        name = object->getName();
    }
    Handle<Object> obj = getValue()->ToObject();
    Handle<Value> newValue = object->getValue();
    if (newValue.IsEmpty())
    {
        newValue = globalTemplate_->NewInstance();
        object->forceSetValue(newValue);
        TiObject::setTiObjectToJsObject(newValue, object);
    }
    obj->Set(String::New(name), newValue);
}

TiRootObject* TiRootObject::createRootObject()
{
    TiRootObject* obj = new TiRootObject;
    return obj;
}

int TiRootObject::executeScript(NativeObjectFactory* objectFactory, const char* javaScript,
                                MESSAGELOOPENTRY messageLoopEntry, void* context)
{
    HandleScope handleScope;
    objectFactory_ = objectFactory;
    globalTemplate_ = ObjectTemplate::New();
    TiV8EventContainerFactory* eventFactory = TiV8EventContainerFactory::createEventContainerFactory(globalTemplate_);
    objectFactory->setEventContainerFactory(eventFactory);
    onSetGetPropertyCallback(&globalTemplate_);
    onSetFunctionCallback(&globalTemplate_);
    g_rootTemplate = ObjectTemplate::New();
    context_ = Context::New(NULL, g_rootTemplate);
    forceSetValue(context_->Global());
    context_->Global()->SetHiddenValue(String::New("globalTemplate_"), External::New(&globalTemplate_));
    context_->Global()->SetHiddenValue(String::New("context_"), External::New(&context_));
    setTiObjectToJsObject(context_->Global(), this);
    Context::Scope context_scope(context_);
    initializeTiObject(NULL);

    const char* bootstrapFilename = "bootstrap.js";
    string bootstrapJavascript;
    {
        ifstream ifs((string("app/native/framework/") + bootstrapFilename).c_str());
        if (!ifs)
        {
            TiLogger::getInstance().log(Ti::Msg::ERROR__Cannot_load_bootstrap_js);
            return -1;
        }
        getline(ifs, bootstrapJavascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    TryCatch tryCatch;
    Handle<Script> compiledBootstrapScript = Script::Compile(String::New(bootstrapJavascript.c_str()), String::New(bootstrapFilename));
    if (compiledBootstrapScript.IsEmpty())
    {
        String::Utf8Value error(tryCatch.Exception());
        TiLogger::getInstance().log(*error);
        return -1;
    }
    Handle<Value> bootstrapResult = compiledBootstrapScript->Run();
    if (bootstrapResult.IsEmpty())
    {
        Local<Value> exception = tryCatch.Exception();
        // FIXME: need a way to prevent double "filename + line" output
        Handle<Message> msg = tryCatch.Message();
        stringstream ss;
        ss << bootstrapFilename << " line ";
        if (msg.IsEmpty())
        {
            ss << "?";
        }
        else
        {
            ss << msg->GetLineNumber();
        }
        ss << ": " << *String::Utf8Value(exception);
        TiLogger::getInstance().log(ss.str());
        return -1;
    }

    const char* filename = "app.js";
    Handle<Script> compiledScript = Script::Compile(String::New(javaScript), String::New(filename));
    if (compiledScript.IsEmpty())
    {
        ReportException(tryCatch, true);
        return 1;
    }
    compiledScript->Run();
    if (tryCatch.HasCaught())
    {
        ReportException(tryCatch, true);
        return 1;
    }
    onStartMessagePump();
    return (messageLoopEntry)(context);
}

void TiRootObject::createStringMethods()
{
    Local<Value> str = context_->Global()->Get(String::New("String"));
    if (!str->IsObject())
    {
        // This should never happen
        ThrowException(String::New(Ti::Msg::INTERNAL__Global_String_symbol_is_not_an_object));
    }
    Local<Object> strObj = str->ToObject();
    const NativeStringInterface* nsi = objectFactory_->getNativeStringInterface();
    strObj->Set(String::New("format"), FunctionTemplate::New(nsi->format)->GetFunction());
    strObj->Set(String::New("formatCurrency"), FunctionTemplate::New(nsi->formatCurrency)->GetFunction());
    strObj->Set(String::New("formatDate"), FunctionTemplate::New(nsi->formatDate)->GetFunction());
    strObj->Set(String::New("formatDecimal"), FunctionTemplate::New(nsi->formatDecimal)->GetFunction());
    strObj->Set(String::New("formatTime"), FunctionTemplate::New(nsi->formatTime)->GetFunction());
}

/* Methods defined by Global */
Handle<Value> TiRootObject::_L(void*, TiObject*, const Arguments& args)
{
    // TODO: finish this
    return args[0];
}

Handle<Value> TiRootObject::_clearInterval(void*, TiObject*, const Arguments& args)
{
    if ((args.Length() != 1) || (!args[0]->IsNumber()))
    {
        return ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    clearTimeoutHelper(args, true);
    return Undefined();
}

Handle<Value> TiRootObject::_clearTimeout(void*, TiObject*, const Arguments& args)
{
    if ((args.Length() != 1) || (!args[0]->IsNumber()))
    {
        return ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    clearTimeoutHelper(args, false);
    return Undefined();
}

void TiRootObject::clearTimeoutHelper(const Arguments& args, bool interval)
{
    Handle<Number> number = Handle<Number>::Cast(args[0]);
    TiTimeoutManager* timeoutManager = TiTimeoutManager::instance();
    timeoutManager->clearTimeout((int)number->Value(), interval);
}

Handle<Value> TiRootObject::_require(void*, TiObject*, const Arguments& args)
{
    if (args.Length() < 1)
    {
        return ThrowException(String::New(Ti::Msg::Missing_argument));
    }

    Handle<String> v8Id = args[0]->ToString();
    string id = *String::Utf8Value(v8Id);

    // check if cached
    static map<string, Persistent<Value> > cache;
    // FIXME: caching the value doesn't work, the resulting object is not a Function after the first time
    /*map<string, Persistent<Value> >::const_iterator cachedValue = cache.find(id);
    if (cachedValue != cache.end())
    {
        return cachedValue->second;
    }*/

    string filename = id + ".js";
    // TODO: need to make this relative and support com.example.module
    static const string baseFolder = "app/native/assets/";
    string javascript;
    {
        ifstream ifs((baseFolder + filename).c_str());
        if (!ifs)
        {
            Local<Value> taggedMessage = String::New((string(Ti::Msg::No_such_native_module) + " " + id).c_str());
            return ThrowException(taggedMessage);
        }
        getline(ifs, javascript, string::traits_type::to_char_type(string::traits_type::eof()));
        ifs.close();
    }

    // wrap the module
    {
        static const string preWrap = "(function () { var module = { exports: {} }; var exports = module.exports;\n";
        static const string postWrap = "\nreturn module.exports; })();";
        javascript = preWrap + javascript + postWrap;
    }

    // TODO: set the correct context

    TryCatch tryCatch;
    Handle<Script> compiledScript = Script::Compile(String::New(javascript.c_str()), String::New(filename.c_str()));
    if (compiledScript.IsEmpty())
    {
        DisplayExceptionLine(tryCatch);
        return tryCatch.ReThrow();
    }
    Persistent<Value> result = (Persistent<Value>)compiledScript->Run();
    if (result.IsEmpty())
    {
        return tryCatch.ReThrow();
    }

    // cache result
    cache.insert(pair<string, Persistent<Value> >(id, result));

    return result;
}

Handle<Value> TiRootObject::_setInterval(void*, TiObject*, const Arguments& args)
{
    return setTimeoutHelper(args, true);
}

Handle<Value> TiRootObject::_setTimeout(void*, TiObject*, const Arguments& args)
{
    return setTimeoutHelper(args, false);
}

Handle<Value> TiRootObject::setTimeoutHelper(const Arguments& args, bool interval)
{
    HandleScope handleScope;
    if ((args.Length() != 2) || (!args[0]->IsFunction()) || (!args[1]->IsNumber()))
    {
        ThrowException(String::New(Ti::Msg::Invalid_arguments));
    }
    Handle<Function> function = Handle<Function>::Cast(args[0]);
    Handle<Number> number = Handle<Number>::Cast(args[1]);
    TiTimeoutManager* timeoutManager = TiTimeoutManager::instance();
    int id = timeoutManager->createTimeout((int)number->Value(), function, interval);
    Handle<Number> timerId = Number::New(id);
    return timerId;
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#ifndef FACTORY_HPP
#define FACTORY_HPP

#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

#include "ansicolors.hpp"
#include "coloredkdbio.hpp"

#include <command.hpp>
#include <external.hpp>

// TODO: to add a new command, 1.) include your header here
#include <check.hpp>
#include <complete.hpp>
#include <convert.hpp>
#include <cp.hpp>
#include <editor.hpp>
#include <export.hpp>
#include <file.hpp>
#include <find.hpp>
#include <fstab.hpp>
#include <get.hpp>
#include <globalmount.hpp>
#include <globalumount.hpp>
#include <import.hpp>
#include <info.hpp>
#include <list.hpp>
#include <listcommands.hpp>
#include <ls.hpp>
#include <merge.hpp>
#include <metaget.hpp>
#include <metals.hpp>
#include <metaremove.hpp>
#include <metaset.hpp>
#include <mount.hpp>
#include <mv.hpp>
#include <remount.hpp>
#include <rm.hpp>
#include <set.hpp>
#include <sget.hpp>
#include <shell.hpp>
#include <specmount.hpp>
#include <test.hpp>
#include <umount.hpp>
#include <validation.hpp>

class Instancer
{
public:
	virtual Command * get () = 0;
	virtual ~Instancer ()
	{
	}
};

template <class T>
class Cnstancer : public Instancer
{
	virtual T * get () override
	{
		return new T ();
	}
};

class Factory
{
	std::map<std::string, Instancer *> m_factory;

public:
	Factory () : m_factory ()
	{
		// TODO: to add a new command, 2.) add a line here  -> and you are done
		m_factory.insert (std::make_pair ("get", new Cnstancer<GetCommand> ()));
		m_factory.insert (std::make_pair ("set", new Cnstancer<SetCommand> ()));
		m_factory.insert (std::make_pair ("rm", new Cnstancer<RemoveCommand> ()));
		m_factory.insert (std::make_pair ("ls", new Cnstancer<LsCommand> ()));
		m_factory.insert (std::make_pair ("complete", new Cnstancer<CompleteCommand> ()));
		m_factory.insert (std::make_pair ("cp", new Cnstancer<CpCommand> ()));
		m_factory.insert (std::make_pair ("mv", new Cnstancer<MvCommand> ()));
		m_factory.insert (std::make_pair ("mount", new Cnstancer<MountCommand> ()));
		m_factory.insert (std::make_pair ("remount", new Cnstancer<RemountCommand> ()));
		m_factory.insert (std::make_pair ("shell", new Cnstancer<ShellCommand> ()));
		m_factory.insert (std::make_pair ("find", new Cnstancer<FindCommand> ()));
		m_factory.insert (std::make_pair ("getmeta", new Cnstancer<MetaGetCommand> ()));
		m_factory.insert (std::make_pair ("rmmeta", new Cnstancer<MetaRemoveCommand> ()));
		m_factory.insert (std::make_pair ("setmeta", new Cnstancer<MetaSetCommand> ()));
		m_factory.insert (std::make_pair ("lsmeta", new Cnstancer<MetaLsCommand> ()));
		m_factory.insert (std::make_pair ("info", new Cnstancer<InfoCommand> ()));
		m_factory.insert (std::make_pair ("test", new Cnstancer<TestCommand> ()));
		m_factory.insert (std::make_pair ("check", new Cnstancer<CheckCommand> ()));
		m_factory.insert (std::make_pair ("vset", new Cnstancer<ValidationCommand> ()));
		m_factory.insert (std::make_pair ("fstab", new Cnstancer<FstabCommand> ()));
		m_factory.insert (std::make_pair ("export", new Cnstancer<ExportCommand> ()));
		m_factory.insert (std::make_pair ("import", new Cnstancer<ImportCommand> ()));
		m_factory.insert (std::make_pair ("convert", new Cnstancer<ConvertCommand> ()));
		m_factory.insert (std::make_pair ("umount", new Cnstancer<UmountCommand> ()));
		m_factory.insert (std::make_pair ("file", new Cnstancer<FileCommand> ()));
		m_factory.insert (std::make_pair ("sget", new Cnstancer<ShellGetCommand> ()));
		m_factory.insert (std::make_pair ("merge", new Cnstancer<MergeCommand>));
		m_factory.insert (std::make_pair ("list", new Cnstancer<ListCommand> ()));
		m_factory.insert (std::make_pair ("editor", new Cnstancer<EditorCommand> ()));
		m_factory.insert (std::make_pair ("spec-mount", new Cnstancer<SpecMountCommand> ()));
		m_factory.insert (std::make_pair ("smount", new Cnstancer<SpecMountCommand> ()));
		m_factory.insert (std::make_pair ("global-mount", new Cnstancer<GlobalMountCommand> ()));
		m_factory.insert (std::make_pair ("global-umount", new Cnstancer<GlobalUmountCommand> ()));
		m_factory.insert (std::make_pair ("gmount", new Cnstancer<GlobalMountCommand> ()));
		m_factory.insert (std::make_pair ("gumount", new Cnstancer<GlobalUmountCommand> ()));
		m_factory.insert (std::make_pair ("list-commands", new Cnstancer<ListCommandsCommand> ()));
	}

	~Factory ()
	{
		for (auto & elem : m_factory)
		{
			delete elem.second;
		}
	}

	std::vector<std::string> getPrettyCommands () const
	{
		std::vector<std::string> ret;
		for (auto & elem : m_factory)
		{
			std::string text = getStdColor (ANSI_COLOR::BOLD);
			text += elem.first;
			text += getStdColor (ANSI_COLOR::RESET);
			text += "\t";
			Command * cmd = elem.second->get ();
			text += cmd->getShortHelpText ();
			delete cmd;
			ret.push_back (text);
		}
		ret.push_back (getStdColor (ANSI_COLOR::BOLD) + "help" + getStdColor (ANSI_COLOR::RESET) + "\t" +
			       "View the man page of a tool");
		ret.push_back (getStdColor (ANSI_COLOR::BOLD) + "list-tools" + getStdColor (ANSI_COLOR::RESET) + "\t" +
			       "List all external tools");
		return ret;
	}

	/**Returns a list of available commands */
	std::vector<std::string> getCommands () const
	{
		std::vector<std::string> ret;
		for (auto & elem : m_factory)
		{
			ret.push_back (elem.first);
		}
		ret.push_back ("help");
		ret.push_back ("list-tools");
		return ret;
	}

	CommandPtr get (std::string const & which)
	{
		Instancer * instancer = m_factory[which];
		if (instancer)
		{
			CommandPtr ret (instancer->get ());
			return ret;
		}
		else
		{
			m_factory.erase (which);
			return CommandPtr (new ExternalCommand ());
		}
	}
};

#endif
<commit_msg>kdb: avoid raw pointers in factory<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#ifndef FACTORY_HPP
#define FACTORY_HPP

#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

#include "ansicolors.hpp"
#include "coloredkdbio.hpp"

#include <command.hpp>
#include <external.hpp>

// TODO: to add a new command, 1.) include your header here
#include <check.hpp>
#include <complete.hpp>
#include <convert.hpp>
#include <cp.hpp>
#include <editor.hpp>
#include <export.hpp>
#include <file.hpp>
#include <find.hpp>
#include <fstab.hpp>
#include <get.hpp>
#include <globalmount.hpp>
#include <globalumount.hpp>
#include <import.hpp>
#include <info.hpp>
#include <list.hpp>
#include <listcommands.hpp>
#include <ls.hpp>
#include <merge.hpp>
#include <metaget.hpp>
#include <metals.hpp>
#include <metaremove.hpp>
#include <metaset.hpp>
#include <mount.hpp>
#include <mv.hpp>
#include <remount.hpp>
#include <rm.hpp>
#include <set.hpp>
#include <sget.hpp>
#include <shell.hpp>
#include <specmount.hpp>
#include <test.hpp>
#include <umount.hpp>
#include <validation.hpp>

class Instancer
{
public:
	virtual std::unique_ptr<Command> get () = 0;
	virtual ~Instancer ()
	{
	}
};

template <class T>
class Cnstancer : public Instancer
{
	virtual std::unique_ptr<Command> get () override
	{
		return std::unique_ptr<Command> (new T ());
	}
};

class Factory
{
	std::map<std::string, std::shared_ptr<Instancer>> m_factory;

public:
	Factory () : m_factory ()
	{
		// TODO: to add a new command, 2.) add a line here  -> and you are done
		m_factory.insert (std::make_pair ("get", new Cnstancer<GetCommand> ()));
		m_factory.insert (std::make_pair ("set", new Cnstancer<SetCommand> ()));
		m_factory.insert (std::make_pair ("rm", new Cnstancer<RemoveCommand> ()));
		m_factory.insert (std::make_pair ("ls", new Cnstancer<LsCommand> ()));
		m_factory.insert (std::make_pair ("complete", new Cnstancer<CompleteCommand> ()));
		m_factory.insert (std::make_pair ("cp", new Cnstancer<CpCommand> ()));
		m_factory.insert (std::make_pair ("mv", new Cnstancer<MvCommand> ()));
		m_factory.insert (std::make_pair ("mount", new Cnstancer<MountCommand> ()));
		m_factory.insert (std::make_pair ("remount", new Cnstancer<RemountCommand> ()));
		m_factory.insert (std::make_pair ("shell", new Cnstancer<ShellCommand> ()));
		m_factory.insert (std::make_pair ("find", new Cnstancer<FindCommand> ()));
		m_factory.insert (std::make_pair ("getmeta", new Cnstancer<MetaGetCommand> ()));
		m_factory.insert (std::make_pair ("rmmeta", new Cnstancer<MetaRemoveCommand> ()));
		m_factory.insert (std::make_pair ("setmeta", new Cnstancer<MetaSetCommand> ()));
		m_factory.insert (std::make_pair ("lsmeta", new Cnstancer<MetaLsCommand> ()));
		m_factory.insert (std::make_pair ("info", new Cnstancer<InfoCommand> ()));
		m_factory.insert (std::make_pair ("test", new Cnstancer<TestCommand> ()));
		m_factory.insert (std::make_pair ("check", new Cnstancer<CheckCommand> ()));
		m_factory.insert (std::make_pair ("vset", new Cnstancer<ValidationCommand> ()));
		m_factory.insert (std::make_pair ("fstab", new Cnstancer<FstabCommand> ()));
		m_factory.insert (std::make_pair ("export", new Cnstancer<ExportCommand> ()));
		m_factory.insert (std::make_pair ("import", new Cnstancer<ImportCommand> ()));
		m_factory.insert (std::make_pair ("convert", new Cnstancer<ConvertCommand> ()));
		m_factory.insert (std::make_pair ("umount", new Cnstancer<UmountCommand> ()));
		m_factory.insert (std::make_pair ("file", new Cnstancer<FileCommand> ()));
		m_factory.insert (std::make_pair ("sget", new Cnstancer<ShellGetCommand> ()));
		m_factory.insert (std::make_pair ("merge", new Cnstancer<MergeCommand>));
		m_factory.insert (std::make_pair ("list", new Cnstancer<ListCommand> ()));
		m_factory.insert (std::make_pair ("editor", new Cnstancer<EditorCommand> ()));
		m_factory.insert (std::make_pair ("spec-mount", new Cnstancer<SpecMountCommand> ()));
		m_factory.insert (std::make_pair ("smount", new Cnstancer<SpecMountCommand> ()));
		m_factory.insert (std::make_pair ("global-mount", new Cnstancer<GlobalMountCommand> ()));
		m_factory.insert (std::make_pair ("global-umount", new Cnstancer<GlobalUmountCommand> ()));
		m_factory.insert (std::make_pair ("gmount", new Cnstancer<GlobalMountCommand> ()));
		m_factory.insert (std::make_pair ("gumount", new Cnstancer<GlobalUmountCommand> ()));
		m_factory.insert (std::make_pair ("list-commands", new Cnstancer<ListCommandsCommand> ()));
	}

	std::vector<std::string> getPrettyCommands () const
	{
		std::vector<std::string> ret;
		for (auto & elem : m_factory)
		{
			std::string text = getStdColor (ANSI_COLOR::BOLD);
			text += elem.first;
			text += getStdColor (ANSI_COLOR::RESET);
			text += "\t";
			CommandPtr cmd = elem.second->get ();
			text += cmd->getShortHelpText ();
			ret.push_back (text);
		}
		ret.push_back (getStdColor (ANSI_COLOR::BOLD) + "help" + getStdColor (ANSI_COLOR::RESET) + "\t" +
			       "View the man page of a tool");
		ret.push_back (getStdColor (ANSI_COLOR::BOLD) + "list-tools" + getStdColor (ANSI_COLOR::RESET) + "\t" +
			       "List all external tools");
		return ret;
	}

	/**Returns a list of available commands */
	std::vector<std::string> getCommands () const
	{
		std::vector<std::string> ret;
		for (auto & elem : m_factory)
		{
			ret.push_back (elem.first);
		}
		ret.push_back ("help");
		ret.push_back ("list-tools");
		return ret;
	}

	CommandPtr get (std::string const & which)
	{
		std::shared_ptr<Instancer> instancer = m_factory[which];
		if (instancer)
		{
			CommandPtr ret (instancer->get ());
			return ret;
		}
		else
		{
			m_factory.erase (which);
			return CommandPtr (new ExternalCommand ());
		}
	}
};

#endif
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

// This is a wrapper program that we use for things we launch via glexec,
// in order to get around glexec's inability to pass environment variables.
// The basic procedure is:
//   1) Condor sets up a UNIX domain socket pair
//   2) Condor invokes this wrapper via glexec, passing one of the sockets
//      to the wrapper as it's standard input stream.
//   3) A stream of environment variables is sent over the socket pair and
//      merged into the environment that will be used for the job.
//   4) The job's "real" standard input FD is sent over the socket pair. The
//      wrapper's socket end is dup'ed and FD 0 is then set to use the
//      received FD.
//   5) The wrapper's socket end is set close-on-exec, and the wrapper then
//      exec's the job.

#include "condor_common.h"
#include "MyString.h"
#include "env.h"
#include "condor_blkng_full_disk_io.h"
#include "fdpass.h"

static void fatal_error();
static char* read_env();
static void get_std_fd(int, char*);

static MyString err;
static int sock_fd;

int
main(int argc, char* argv[])
{
	// dup FD 0 since we will later replace FD 0 with the job's stdin
	//
	sock_fd = dup(0);
	if (sock_fd == -1) {
		err.sprintf("dup error on FD 0: %s", strerror(errno));
		sock_fd = 0;
		fatal_error();
	}

	// deal with our arguments
	//
	if (argc < 5) {
		err.sprintf("usage: %s <in> <out> <err> <cmd> [<arg> ...]",
		            argv[0]);
		fatal_error();
	}
	char* job_stdin = argv[1];
	char* job_stdout = argv[2];
	char* job_stderr = argv[3];
	char** job_argv = &argv[4];

	// set up an Env object that we'll use for the job. we'll initialize
	// it with the environment that Condor sends us then merge on top of
	// that the environment that glexec prepared for us
	//
	// Why?  I don't understand why we are overriding job environment
	// set by condor with the environment set by glexec.  For now, we
	// must make two exceptions: X509_USER_PROXY and PATH.  We want the job to
	// use the proxy that is managed by Condor, not a copy of the
	// proxy created by glexec or the proxy used by condor itself.
	// The overriding of PATH by glexec has also been probematic.

	Env env;
	char* env_buf = read_env();
	MyString merge_err;
	if (!env.MergeFromV2Raw(env_buf, &merge_err)) {
		err.sprintf("Env::MergeFromV2Raw error: %s", merge_err.Value());
		fatal_error();
	}

	MyString user_proxy;
	bool override_glexec_proxy_env = false;
	if( env.GetEnv("X509_USER_PROXY",user_proxy) &&
		getenv("X509_USER_PROXY") )
	{
		override_glexec_proxy_env = true;
	}

	MyString path;
	bool override_path = false;
	if( env.GetEnv("PATH",path) &&
		getenv("PATH") )
	{
		override_path = true;
	}

	env.MergeFrom(environ);
	delete[] env_buf;

	if( override_glexec_proxy_env ) {
		env.SetEnv("X509_USER_PROXY",user_proxy.Value());
	}

	if( override_path ) {
		env.SetEnv("PATH",path.Value());
	}

	// now prepare the job's standard FDs
	//
	get_std_fd(0, job_stdin);
	get_std_fd(1, job_stdout);
	get_std_fd(2, job_stderr);

		// Now we do a little dance to replace the socketpair that we
		// have been using to communicate with the starter with a new
		// one.  Why?  Because, as of glexec 0.8, when glexec is
		// configured with linger=on, some persistent process
		// (glexec?, procd?) is keeping a handle to the wrapper's end
		// of the socket open, so the starter hangs waiting for the
		// socket to close when the job is executed.

	int new_sock_fd = fdpass_recv(sock_fd);
	if (new_sock_fd == -1) {
		err = "fdpass_recv error on new_sock_fd";
		fatal_error();
	}
	if (dup2(new_sock_fd,sock_fd) == -1 ) {
		err = "dup2 error on new_sock_fd";
		fatal_error();
	}
	close(new_sock_fd);

	// set our UNIX domain socket end close-on-exec; if the Starter
	// sees it close without seeing an error message first, it assumes
	// that the job has begun execution
	//
	if (fcntl(sock_fd, F_SETFD, FD_CLOEXEC) == -1) {
		err.sprintf("fcntl error setting close-on-exec: %s",
		            strerror(errno));
		fatal_error();
	}

	// now we can exec the job. for arguments, we shift this wrapper's
	// arguments by one. similarly, the job's executable path is taken
	// as our argv[1]
	//
	char** envp = env.getStringArray();
	execve(job_argv[0], &job_argv[0], envp);
	err.sprintf("execve error: %s", strerror(errno));
	fatal_error();
}

static void
fatal_error()
{
	write(sock_fd, err.Value(), err.Length() + 1);
	exit(1);
}

static char*
read_env()
{
	int bytes;
	int env_len;
	bytes = full_read(0, &env_len, sizeof(env_len));
	if (bytes != sizeof(env_len)) {
		if (bytes == -1) {
			err.sprintf("read error getting env size: %s",
			            strerror(errno));
		}
		else {
			err.sprintf("short read of env size: %d of %d bytes",
			            bytes,
			            sizeof(env_len));
		}
		fatal_error();
	}
	if (env_len <= 0) {
		err.sprintf("invalid env size %d read from stdin", env_len);
		fatal_error();
	}
	char* env_buf = new char[env_len];
	if (env_buf == NULL) {
		err.sprintf("failure to allocate %d bytes", env_len);
		fatal_error();
	}
	bytes = full_read(0, env_buf, env_len);
	if (bytes != env_len) {
		if (bytes == -1) {
			err.sprintf("read error getting env: %s",
			            strerror(errno));
		}
		else {
			err.sprintf("short read of env: %d of %d bytes",
			            bytes,
			            env_len);
		}
		fatal_error();
	}
	return env_buf;
}

static void
get_std_fd(int std_fd, char* name)
{
	int new_fd = std_fd;
	if (strcmp(name, "-") == 0) {
		if (std_fd == 0) {
			// stdin is handled specially, since its "default"
			// (if we were passed "-" on the command line) is
			// to get passed the FD to use from the Starter
			//
			new_fd = fdpass_recv(sock_fd);
			if (new_fd == -1) {
				err = "fdpass_recv error";
				fatal_error();
			}
		}
	}
	else {
		int flags;
		if (std_fd == 0) {
			flags = O_RDONLY;
		}
		else {
			flags = O_WRONLY | O_CREAT | O_TRUNC;
		}
		new_fd = safe_open_wrapper(name, flags, 0600);
		if (new_fd == -1) {
			err.sprintf("safe_open_wrapper error on %s: %s",
			            name,
			            strerror(errno));
			fatal_error();
		}
	}
	if (new_fd != std_fd) {
		if (dup2(new_fd, std_fd) == -1) {
			err.sprintf("dup2 error (%d to %d): %s",
			            new_fd,
			            std_fd,
			            strerror(errno));
			fatal_error();
		}
		close(new_fd);
	}
}
<commit_msg>Fixed a bug in condor_glexec_job_wrapper. #2840<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

// This is a wrapper program that we use for things we launch via glexec,
// in order to get around glexec's inability to pass environment variables.
// The basic procedure is:
//   1) Condor sets up a UNIX domain socket pair
//   2) Condor invokes this wrapper via glexec, passing one of the sockets
//      to the wrapper as it's standard input stream.
//   3) A stream of environment variables is sent over the socket pair and
//      merged into the environment that will be used for the job.
//   4) The job's "real" standard input FD is sent over the socket pair. The
//      wrapper's socket end is dup'ed and FD 0 is then set to use the
//      received FD.
//   5) The wrapper's socket end is set close-on-exec, and the wrapper then
//      exec's the job.

#include "condor_common.h"
#include "MyString.h"
#include "env.h"
#include "condor_blkng_full_disk_io.h"
#include "fdpass.h"

static void fatal_error();
static char* read_env();
static void get_std_fd(int, char*);

static MyString err;
static int sock_fd;

int
main(int argc, char* argv[])
{
	// dup FD 0 since we will later replace FD 0 with the job's stdin
	// Make sure we dup it to something >= 3 so it doesn't get
	// clobbered when we set up stdin, stdout, and stderr.
	do {
		sock_fd = dup(0);
		if (sock_fd == -1) {
			err.sprintf("dup error on FD 0: %s", strerror(errno));
			sock_fd = 0;
			fatal_error();
		}
	} while( sock_fd < 3 );

	// deal with our arguments
	//
	if (argc < 5) {
		err.sprintf("usage: %s <in> <out> <err> <cmd> [<arg> ...]",
		            argv[0]);
		fatal_error();
	}
	char* job_stdin = argv[1];
	char* job_stdout = argv[2];
	char* job_stderr = argv[3];
	char** job_argv = &argv[4];

	// set up an Env object that we'll use for the job. we'll initialize
	// it with the environment that Condor sends us then merge on top of
	// that the environment that glexec prepared for us
	//
	// Why?  I don't understand why we are overriding job environment
	// set by condor with the environment set by glexec.  For now, we
	// must make two exceptions: X509_USER_PROXY and PATH.  We want the job to
	// use the proxy that is managed by Condor, not a copy of the
	// proxy created by glexec or the proxy used by condor itself.
	// The overriding of PATH by glexec has also been probematic.

	Env env;
	char* env_buf = read_env();
	MyString merge_err;
	if (!env.MergeFromV2Raw(env_buf, &merge_err)) {
		err.sprintf("Env::MergeFromV2Raw error: %s", merge_err.Value());
		fatal_error();
	}

	MyString user_proxy;
	bool override_glexec_proxy_env = false;
	if( env.GetEnv("X509_USER_PROXY",user_proxy) &&
		getenv("X509_USER_PROXY") )
	{
		override_glexec_proxy_env = true;
	}

	MyString path;
	bool override_path = false;
	if( env.GetEnv("PATH",path) &&
		getenv("PATH") )
	{
		override_path = true;
	}

	env.MergeFrom(environ);
	delete[] env_buf;

	if( override_glexec_proxy_env ) {
		env.SetEnv("X509_USER_PROXY",user_proxy.Value());
	}

	if( override_path ) {
		env.SetEnv("PATH",path.Value());
	}

	// now prepare the job's standard FDs
	//
	get_std_fd(0, job_stdin);
	get_std_fd(1, job_stdout);
	get_std_fd(2, job_stderr);

		// Now we do a little dance to replace the socketpair that we
		// have been using to communicate with the starter with a new
		// one.  Why?  Because, as of glexec 0.8, when glexec is
		// configured with linger=on, some persistent process
		// (glexec?, procd?) is keeping a handle to the wrapper's end
		// of the socket open, so the starter hangs waiting for the
		// socket to close when the job is executed.

	int new_sock_fd = fdpass_recv(sock_fd);
	if (new_sock_fd == -1) {
		err = "fdpass_recv error on new_sock_fd";
		fatal_error();
	}
	if (dup2(new_sock_fd,sock_fd) == -1 ) {
		err = "dup2 error on new_sock_fd";
		fatal_error();
	}
	close(new_sock_fd);

	// set our UNIX domain socket end close-on-exec; if the Starter
	// sees it close without seeing an error message first, it assumes
	// that the job has begun execution
	//
	if (fcntl(sock_fd, F_SETFD, FD_CLOEXEC) == -1) {
		err.sprintf("fcntl error setting close-on-exec: %s",
		            strerror(errno));
		fatal_error();
	}

	// now we can exec the job. for arguments, we shift this wrapper's
	// arguments by one. similarly, the job's executable path is taken
	// as our argv[1]
	//
	char** envp = env.getStringArray();
	execve(job_argv[0], &job_argv[0], envp);
	err.sprintf("execve error: %s", strerror(errno));
	fatal_error();
}

static void
fatal_error()
{
	write(sock_fd, err.Value(), err.Length() + 1);
	exit(1);
}

static char*
read_env()
{
	int bytes;
	int env_len;
	bytes = full_read(0, &env_len, sizeof(env_len));
	if (bytes != sizeof(env_len)) {
		if (bytes == -1) {
			err.sprintf("read error getting env size: %s",
			            strerror(errno));
		}
		else {
			err.sprintf("short read of env size: %d of %d bytes",
			            bytes,
			            sizeof(env_len));
		}
		fatal_error();
	}
	if (env_len <= 0) {
		err.sprintf("invalid env size %d read from stdin", env_len);
		fatal_error();
	}
	char* env_buf = new char[env_len];
	if (env_buf == NULL) {
		err.sprintf("failure to allocate %d bytes", env_len);
		fatal_error();
	}
	bytes = full_read(0, env_buf, env_len);
	if (bytes != env_len) {
		if (bytes == -1) {
			err.sprintf("read error getting env: %s",
			            strerror(errno));
		}
		else {
			err.sprintf("short read of env: %d of %d bytes",
			            bytes,
			            env_len);
		}
		fatal_error();
	}
	return env_buf;
}

static void
get_std_fd(int std_fd, char* name)
{
	int new_fd = std_fd;
	if (strcmp(name, "-") == 0) {
		if (std_fd == 0) {
			// stdin is handled specially, since its "default"
			// (if we were passed "-" on the command line) is
			// to get passed the FD to use from the Starter
			//
			new_fd = fdpass_recv(sock_fd);
			if (new_fd == -1) {
				err = "fdpass_recv error";
				fatal_error();
			}
		}
	}
	else {
		int flags;
		if (std_fd == 0) {
			flags = O_RDONLY;
		}
		else {
			flags = O_WRONLY | O_CREAT | O_TRUNC;
		}
		new_fd = safe_open_wrapper(name, flags, 0600);
		if (new_fd == -1) {
			err.sprintf("safe_open_wrapper error on %s: %s",
			            name,
			            strerror(errno));
			fatal_error();
		}
	}
	if (new_fd != std_fd) {
		if (dup2(new_fd, std_fd) == -1) {
			err.sprintf("dup2 error (%d to %d): %s",
			            new_fd,
			            std_fd,
			            strerror(errno));
			fatal_error();
		}
		close(new_fd);
	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include "SimpleLinkedList.h"

using namespace std;

SimpleLinkedList::SimpleLinkedList() :
	first{ nullptr },
	last{ nullptr },
	size{ 0u } { }

SimpleLinkedList::SimpleLinkedList(int i) : SimpleLinkedList() {
	last = first = new Element(i);
	++size;
}

SimpleLinkedList::SimpleLinkedList(const SimpleLinkedList & in) : SimpleLinkedList() {
	if (in.first != nullptr) {
		first = new Element(in.first->i);
		Element * tmpLocal = first;
		Element * tmpCopy = in.first;
		while (tmpCopy->next != nullptr) {
			tmpCopy = tmpCopy->next;
			tmpLocal->next = new Element(tmpCopy->i);
			tmpLocal = tmpLocal->next;
			last = tmpLocal;
			++size;
		}
	}
}

SimpleLinkedList::SimpleLinkedList(SimpleLinkedList && in) {
	first = in.first;
	last = in.last;
	size = in.size;

	in.first = nullptr;
	in.last = nullptr;
	in.size = 0;
}

SimpleLinkedList::~SimpleLinkedList() {
	Element * tmp = first;
	while (tmp != 0) {
		first = first->next;
		delete tmp;
		tmp = first;
	}
}

void SimpleLinkedList::add(int i) {
	addLast(i);
}

void SimpleLinkedList::addLast(int i) {
	if (!first) {
		last = first = new Element(i);
	} else {
		last->next = new Element(i);
		last = last->next;
		++size;
	}
}

unsigned int SimpleLinkedList::getSize() {
	return size;
}

Element * SimpleLinkedList::getFirst() {
	return this->first;
}

void SimpleLinkedList::printAll() {
	Element * tmp = this->first;
	cout << "{";
	while (tmp != nullptr) {
		cout << tmp->i;
		if (tmp->next != nullptr) {
			cout << ",";
		}
		tmp = tmp->next;
	};
	cout << "}" << endl;
}

SimpleLinkedList & SimpleLinkedList::operator=(const SimpleLinkedList & in) {
	if (this != &in) {
		SimpleLinkedList(in).swap(*this);
	}
	return *this;
}

SimpleLinkedList & SimpleLinkedList::operator=(SimpleLinkedList && in) {
	using std::move;
	first = move(in.first);
	last = move(in.last);
	size = move(in.move);
	return *this;
}

void SimpleLinkedList::swap(SimpleLinkedList & in) {
	using  std::swap;
	swap(this->first, in.first);
	swap(this->last, in.last);
	swap(this->size, in.size);
}

Element::Element(int i) {
	this->i = i;
	this->next = nullptr;
}<commit_msg>fixed a stupid bug.<commit_after>#include <iostream>
#include "SimpleLinkedList.h"

using namespace std;

SimpleLinkedList::SimpleLinkedList() :
	first{ nullptr },
	last{ nullptr },
	size{ 0u } { }

SimpleLinkedList::SimpleLinkedList(int i) : SimpleLinkedList() {
	last = first = new Element(i);
	++size;
}

SimpleLinkedList::SimpleLinkedList(const SimpleLinkedList & in) : SimpleLinkedList() {
	if (in.first != nullptr) {
		first = new Element(in.first->i);
		Element * tmpLocal = first;
		Element * tmpCopy = in.first;
		while (tmpCopy->next != nullptr) {
			tmpCopy = tmpCopy->next;
			tmpLocal->next = new Element(tmpCopy->i);
			tmpLocal = tmpLocal->next;
			last = tmpLocal;
			++size;
		}
	}
}

SimpleLinkedList::SimpleLinkedList(SimpleLinkedList && in) {
	first = in.first;
	last = in.last;
	size = in.size;

	in.first = nullptr;
	in.last = nullptr;
	in.size = 0;
}

SimpleLinkedList::~SimpleLinkedList() {
	Element * tmp = first;
	while (tmp != 0) {
		first = first->next;
		delete tmp;
		tmp = first;
	}
}

void SimpleLinkedList::add(int i) {
	addLast(i);
}

void SimpleLinkedList::addLast(int i) {
	if (!first) {
		last = first = new Element(i);
	} else {
		last->next = new Element(i);
		last = last->next;
		++size;
	}
}

unsigned int SimpleLinkedList::getSize() {
	return size;
}

Element * SimpleLinkedList::getFirst() {
	return this->first;
}

void SimpleLinkedList::printAll() {
	Element * tmp = this->first;
	cout << "{";
	while (tmp != nullptr) {
		cout << tmp->i;
		if (tmp->next != nullptr) {
			cout << ",";
		}
		tmp = tmp->next;
	};
	cout << "}" << endl;
}

SimpleLinkedList & SimpleLinkedList::operator=(const SimpleLinkedList & in) {
	if (this != &in) {
		SimpleLinkedList(in).swap(*this);
	}
	return *this;
}

SimpleLinkedList & SimpleLinkedList::operator=(SimpleLinkedList && in) {
	using std::move;
	first = move(in.first);
	last = move(in.last);
	size = move(in.size);
	return *this;
}

void SimpleLinkedList::swap(SimpleLinkedList & in) {
	using  std::swap;
	swap(this->first, in.first);
	swap(this->last, in.last);
	swap(this->size, in.size);
}

Element::Element(int i) {
	this->i = i;
	this->next = nullptr;
}<|endoftext|>