<commit_before>/*
    addcontactwizard.cpp - Kopete's Add Contact Wizard

    Copyright (c) 2002 by Nick Betcher           <nbetcher@kde.org>
    Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/
//	CONDITIONS FOR PROGRESSING:
//	Welcome page
//		true
//	|
//	V
//	Select Address Book Entry
//		( Addressee is selected AND is not already associated with a contact )
//			OR Do not use address book is checked
//	|
//	V
//	Select Display Name and Group
//		true
//	|
//	V
//	Select Account
//		( Only 1 account ) OR ( An account is selected )
//	|
//	V
//	(Each AddContactPage)
//		( Own conditions)
//	|
//	V
//	Finish
//		true

#include <qcheckbox.h>
#include <klocale.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <kpushbutton.h>
#include <kdebug.h>
#include <klistview.h>
// used for its AddresseeItem class
#include <kabc/addresseedialog.h>
#include <kabc/addressbook.h>
#include <kabc/stdaddressbook.h>

#include <addcontactpage.h>
#include "addcontactwizard.h"
#include "kopetecontactlist.h"
#include "kopetemetacontact.h"
#include "kopeteaccountmanager.h"
#include "kopeteaccount.h"

AddContactWizard::AddContactWizard( QWidget *parent, const char *name )
: AddContactWizard_Base( parent, name )
{
	// Populate the groups list
	KopeteGroupList groups=KopeteContactList::contactList()->groups();
	for( KopeteGroup *it = groups.first(); it; it = groups.next() )
	{
		QString groupname = it->displayName();
		if ( !groupname.isEmpty() )
			new QCheckListItem( groupList, groupname, QCheckListItem::CheckBox);
	}

	protocolListView->clear();
	m_accountItems.clear();

	// Populate the accounts list
	QCheckListItem* accountLVI=0L;
	QPtrList<KopeteAccount>  accounts = KopeteAccountManager::manager()->accounts();
	for(KopeteAccount *i=accounts.first() ; i; i=accounts.next() )
	{
		accountLVI= new QCheckListItem( protocolListView, i->accountId(), QCheckListItem::CheckBox);
		accountLVI->setText(1,i->protocol()->displayName() + QString::fromLatin1(" ") );
		accountLVI->setPixmap( 1, SmallIcon( i->protocol()->pluginIcon() ) );
		m_accountItems.insert(accountLVI,i);
	}

	// Populate the addressee list
	// This could be slow - is there a better way of doing it (progressive loading?)
	loadAddressees();

	if ( accounts.count() == 1 )
	{
		accountLVI->setOn( true );
		setAppropriate( selectService, false );
	}

	setNextEnabled( selectAddressee, false );
	setNextEnabled(selectService, (accounts.count() == 1));
	setFinishEnabled(finis, true);

	// FIXME: steal/add a create addressee widget
	addAddresseeButton->setEnabled( false );
	// Addressee validation connections
	connect( addAddresseeButton, SIGNAL( clicked() ), SLOT( slotAddAddresseeClicked() ) );
	connect( chkNoAddressee, SIGNAL( toggled( bool ) ),
			SLOT( slotCheckAddresseeChoice( bool ) ) );
	connect( addresseeListView, SIGNAL( clicked(QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );
	connect( addresseeListView, SIGNAL( selectionChanged( QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );
	connect( addresseeListView, SIGNAL( spacePressed( QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );

	// Group manipulation connection
	connect( addGroupButton, SIGNAL(clicked()) , SLOT(slotAddGroupClicked()) );

	// Account choice validation connections
	connect( protocolListView, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
	connect( protocolListView, SIGNAL(selectionChanged(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
	connect( protocolListView, SIGNAL(spacePressed(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
}

AddContactWizard::~AddContactWizard()
{
}

void AddContactWizard::loadAddressees()
{
	addresseeListView->clear();
	KABC::AddressBook* ab = KABC::StdAddressBook::self();
	KABC::AddressBook::Iterator it;
	for( it = ab->begin(); it != ab->end(); ++it )
		KABC::AddresseeItem *item = new KABC::AddresseeItem( addresseeListView, (*it) );
}

void AddContactWizard::slotAddAddresseeClicked()
{
	// Pop up add addressee dialog
}

void AddContactWizard::slotCheckAddresseeChoice( bool on )
{
	// Disable addressee selection widgets
	addresseeListView->setEnabled( !on );
	addAddresseeButton->setEnabled( !on );
	if ( on )
		setNextEnabled( selectAddressee, true );
	else
	{
		if ( addresseeListView->selectedItem() )
			setNextEnabled( selectAddressee, true );
		else
			setNextEnabled( selectAddressee, false );
	}
}

void AddContactWizard::slotAddresseeListClicked( QListViewItem *addressee )
{
	// check a valid addressee is selected
	setNextEnabled( selectAddressee, addressee ? addressee->isSelected() : false );
}

void AddContactWizard::slotAddGroupClicked()
{
	bool ok;
	QString groupName = KLineEditDlg::getText(
		i18n( "New Group" ),
		i18n( "Please enter the name for the new group:" ),
		QString::null, &ok );

	if ( !groupName.isNull() && ok)
		new QCheckListItem( groupList, groupName, QCheckListItem::CheckBox);
}

void AddContactWizard::slotProtocolListClicked( QListViewItem *)
{
	// Just makes sure a protocol is selected before allowing the user to continue
	bool oneIsChecked = false;

	for (QListViewItemIterator it(protocolListView); it.current(); ++it)
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(it.current());
		if (check && check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}

	setNextEnabled(selectService, oneIsChecked);
}

void AddContactWizard::accept()
{
	KopeteMetaContact *m = new KopeteMetaContact();

	// set the display name if required
	if ( !mDisplayName->text().isEmpty() )
	{
		m->setTrackChildNameChanges( false );
		m->setDisplayName( mDisplayName->text() );
	}

	// set the KABC uid in the metacontact
	KABC::AddresseeItem* i = 0L;
	i = static_cast<KABC::AddresseeItem *>( addresseeListView->selectedItem() );
	if ( addresseeListView->isEnabled() && i )
		m->setMetaContactId( i->addressee().uid() );

	// set the metacontact's groups
	bool topLevel = true;
	for (QListViewItemIterator it(groupList); it.current(); ++it)
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(it.current());
		if (check && check->isOn())
		{
			m->addToGroup(KopeteContactList::contactList()->getGroup(check->text()));
			topLevel = false;
		}
	}
	m->setTopLevel(topLevel);

	bool ok=false;

	// get each protocol's contact
	QMap <KopeteAccount*,AddContactPage*>::Iterator it;
	for ( it = protocolPages.begin(); it != protocolPages.end(); ++it )
	{
		ok |= it.data()->apply(it.key(),m);
	}

	// add it to the contact list
	if(ok)
		KopeteContactList::contactList()->addMetaContact(m);
	else
		delete m;
	delete this;
}

void AddContactWizard::next()
{
	// If the we're on the select account page
	// follow it with the add contact pages for
	// the chosen protocols
	if (currentPage() == selectService ||
		(currentPage() == intro && !appropriate( selectService )))
	{
		QMap <KopeteAccount*,AddContactPage*>::Iterator it;
		for ( it = protocolPages.begin(); it != protocolPages.end(); ++it )
		{
			delete it.data();
		}
		protocolPages.clear();

		// We don't keep track of this pointer because it gets deleted when the wizard does (which is what we want)
		for (QListViewItemIterator it(protocolListView); it.current(); ++it)
		{
			QCheckListItem *item = dynamic_cast<QCheckListItem *>(it.current());
			if (item && item->isOn())
			{
				// this shouldn't happen either, but I hate crashes
				if (!m_accountItems[item]) continue;

				AddContactPage *addPage = m_accountItems[item]->protocol()->createAddContactWidget(this, m_accountItems[item] );
				if (!addPage) continue;

				QString title = i18n( "The account name is prepended here",
									  "%1 contact information" )
									 .arg( item->text(0) );
				addPage->show();
				insertPage( addPage, title, indexOf( selectGroup) );
				protocolPages.insert( m_accountItems[item] , addPage );
			}
		}
		QWizard::next();
		return;
	}

	// If we're not on any account specific pages,
	// we must be on an add account page, so make sure it validates
	if (currentPage() != intro &&
		currentPage() != selectAddressee &&
		currentPage() != selectService &&
		currentPage() != selectGroup &&
		currentPage() != finis)
	{
		AddContactPage *ePage = dynamic_cast<AddContactPage *>(currentPage());
		if (!ePage || !ePage->validateData())
			return;
	}

	QWizard::next();
}

void AddContactWizard::showPage( QWidget *page )
{
	if ( page == selectGroup )
	{
		if ( addresseeListView->isEnabled() )
		{
			if ( KABC::AddresseeItem* i = static_cast<KABC::AddresseeItem *>( addresseeListView->selectedItem() ) )
				mDisplayName->setText( i->addressee().realName() );
			else
				mDisplayName->setText( QString::null );
		}
	}
	QWizard::showPage( page );
}

#include "addcontactwizard.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>Make the protocol pages appear in the right place again.<commit_after>/*
    addcontactwizard.cpp - Kopete's Add Contact Wizard

    Copyright (c) 2002 by Nick Betcher           <nbetcher@kde.org>
    Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/
//	CONDITIONS FOR PROGRESSING:
//	Welcome page
//		true
//	|
//	V
//	Select Address Book Entry
//		( Addressee is selected AND is not already associated with a contact )
//			OR Do not use address book is checked
//	|
//	V
//	Select Display Name and Group
//		true
//	|
//	V
//	Select Account
//		( Only 1 account ) OR ( An account is selected )
//	|
//	V
//	(Each AddContactPage)
//		( Own conditions)
//	|
//	V
//	Finish
//		true

#include <qcheckbox.h>
#include <klocale.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <kpushbutton.h>
#include <kdebug.h>
#include <klistview.h>
// used for its AddresseeItem class
#include <kabc/addresseedialog.h>
#include <kabc/addressbook.h>
#include <kabc/stdaddressbook.h>

#include <addcontactpage.h>
#include "addcontactwizard.h"
#include "kopetecontactlist.h"
#include "kopetemetacontact.h"
#include "kopeteaccountmanager.h"
#include "kopeteaccount.h"

AddContactWizard::AddContactWizard( QWidget *parent, const char *name )
: AddContactWizard_Base( parent, name )
{
	// Populate the groups list
	KopeteGroupList groups=KopeteContactList::contactList()->groups();
	for( KopeteGroup *it = groups.first(); it; it = groups.next() )
	{
		QString groupname = it->displayName();
		if ( !groupname.isEmpty() )
			new QCheckListItem( groupList, groupname, QCheckListItem::CheckBox);
	}

	protocolListView->clear();
	m_accountItems.clear();

	// Populate the accounts list
	QCheckListItem* accountLVI=0L;
	QPtrList<KopeteAccount>  accounts = KopeteAccountManager::manager()->accounts();
	for(KopeteAccount *i=accounts.first() ; i; i=accounts.next() )
	{
		accountLVI= new QCheckListItem( protocolListView, i->accountId(), QCheckListItem::CheckBox);
		accountLVI->setText(1,i->protocol()->displayName() + QString::fromLatin1(" ") );
		accountLVI->setPixmap( 1, SmallIcon( i->protocol()->pluginIcon() ) );
		m_accountItems.insert(accountLVI,i);
	}

	// Populate the addressee list
	// This could be slow - is there a better way of doing it (progressive loading?)
	loadAddressees();

	if ( accounts.count() == 1 )
	{
		accountLVI->setOn( true );
		setAppropriate( selectService, false );
	}

	setNextEnabled( selectAddressee, false );
	setNextEnabled(selectService, (accounts.count() == 1));
	setFinishEnabled(finis, true);

	// FIXME: steal/add a create addressee widget
	addAddresseeButton->setEnabled( false );
	// Addressee validation connections
	connect( addAddresseeButton, SIGNAL( clicked() ), SLOT( slotAddAddresseeClicked() ) );
	connect( chkNoAddressee, SIGNAL( toggled( bool ) ),
			SLOT( slotCheckAddresseeChoice( bool ) ) );
	connect( addresseeListView, SIGNAL( clicked(QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );
	connect( addresseeListView, SIGNAL( selectionChanged( QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );
	connect( addresseeListView, SIGNAL( spacePressed( QListViewItem * ) ),
			SLOT( slotAddresseeListClicked( QListViewItem * ) ) );

	// Group manipulation connection
	connect( addGroupButton, SIGNAL(clicked()) , SLOT(slotAddGroupClicked()) );

	// Account choice validation connections
	connect( protocolListView, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
	connect( protocolListView, SIGNAL(selectionChanged(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
	connect( protocolListView, SIGNAL(spacePressed(QListViewItem *)), this, SLOT(slotProtocolListClicked(QListViewItem *)));
}

AddContactWizard::~AddContactWizard()
{
}

void AddContactWizard::loadAddressees()
{
	addresseeListView->clear();
	KABC::AddressBook* ab = KABC::StdAddressBook::self();
	KABC::AddressBook::Iterator it;
	for( it = ab->begin(); it != ab->end(); ++it )
		KABC::AddresseeItem *item = new KABC::AddresseeItem( addresseeListView, (*it) );
}

void AddContactWizard::slotAddAddresseeClicked()
{
	// Pop up add addressee dialog
}

void AddContactWizard::slotCheckAddresseeChoice( bool on )
{
	// Disable addressee selection widgets
	addresseeListView->setEnabled( !on );
	addAddresseeButton->setEnabled( !on );
	if ( on )
		setNextEnabled( selectAddressee, true );
	else
	{
		if ( addresseeListView->selectedItem() )
			setNextEnabled( selectAddressee, true );
		else
			setNextEnabled( selectAddressee, false );
	}
}

void AddContactWizard::slotAddresseeListClicked( QListViewItem *addressee )
{
	// check a valid addressee is selected
	setNextEnabled( selectAddressee, addressee ? addressee->isSelected() : false );
}

void AddContactWizard::slotAddGroupClicked()
{
	bool ok;
	QString groupName = KLineEditDlg::getText(
		i18n( "New Group" ),
		i18n( "Please enter the name for the new group:" ),
		QString::null, &ok );

	if ( !groupName.isNull() && ok)
		new QCheckListItem( groupList, groupName, QCheckListItem::CheckBox);
}

void AddContactWizard::slotProtocolListClicked( QListViewItem *)
{
	// Just makes sure a protocol is selected before allowing the user to continue
	bool oneIsChecked = false;

	for (QListViewItemIterator it(protocolListView); it.current(); ++it)
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(it.current());
		if (check && check->isOn())
		{
			oneIsChecked = true;
			break;
		}
	}

	setNextEnabled(selectService, oneIsChecked);
}

void AddContactWizard::accept()
{
	KopeteMetaContact *m = new KopeteMetaContact();

	// set the display name if required
	if ( !mDisplayName->text().isEmpty() )
	{
		m->setTrackChildNameChanges( false );
		m->setDisplayName( mDisplayName->text() );
	}

	// set the KABC uid in the metacontact
	KABC::AddresseeItem* i = 0L;
	i = static_cast<KABC::AddresseeItem *>( addresseeListView->selectedItem() );
	if ( addresseeListView->isEnabled() && i )
		m->setMetaContactId( i->addressee().uid() );

	// set the metacontact's groups
	bool topLevel = true;
	for (QListViewItemIterator it(groupList); it.current(); ++it)
	{
		QCheckListItem *check = dynamic_cast<QCheckListItem *>(it.current());
		if (check && check->isOn())
		{
			m->addToGroup(KopeteContactList::contactList()->getGroup(check->text()));
			topLevel = false;
		}
	}
	m->setTopLevel(topLevel);

	bool ok=false;

	// get each protocol's contact
	QMap <KopeteAccount*,AddContactPage*>::Iterator it;
	for ( it = protocolPages.begin(); it != protocolPages.end(); ++it )
	{
		ok |= it.data()->apply(it.key(),m);
	}

	// add it to the contact list
	if(ok)
		KopeteContactList::contactList()->addMetaContact(m);
	else
		delete m;
	delete this;
}

void AddContactWizard::next()
{
	// If the we're on the select account page
	// follow it with the add contact pages for
	// the chosen protocols
	if (currentPage() == selectService ||
		(currentPage() == intro && !appropriate( selectService )))
	{
		QMap <KopeteAccount*,AddContactPage*>::Iterator it;
		for ( it = protocolPages.begin(); it != protocolPages.end(); ++it )
		{
			delete it.data();
		}
		protocolPages.clear();

		// We don't keep track of this pointer because it gets deleted when the wizard does (which is what we want)
		for (QListViewItemIterator it(protocolListView); it.current(); ++it)
		{
			QCheckListItem *item = dynamic_cast<QCheckListItem *>(it.current());
			if (item && item->isOn())
			{
				// this shouldn't happen either, but I hate crashes
				if (!m_accountItems[item]) continue;

				AddContactPage *addPage = m_accountItems[item]->protocol()->createAddContactWidget(this, m_accountItems[item] );
				if (!addPage) continue;

				QString title = i18n( "The account name is prepended here",
									  "%1 contact information" )
									 .arg( item->text(0) );
				addPage->show();
				insertPage( addPage, title, indexOf( finis ) );
				protocolPages.insert( m_accountItems[item] , addPage );
			}
		}
		QWizard::next();
		return;
	}

	// If we're not on any account specific pages,
	// we must be on an add account page, so make sure it validates
	if (currentPage() != intro &&
		currentPage() != selectAddressee &&
		currentPage() != selectService &&
		currentPage() != selectGroup &&
		currentPage() != finis)
	{
		AddContactPage *ePage = dynamic_cast<AddContactPage *>(currentPage());
		if (!ePage || !ePage->validateData())
			return;
	}

	QWizard::next();
}

void AddContactWizard::showPage( QWidget *page )
{
	if ( page == selectGroup )
	{
		if ( addresseeListView->isEnabled() )
		{
			if ( KABC::AddresseeItem* i = static_cast<KABC::AddresseeItem *>( addresseeListView->selectedItem() ) )
				mDisplayName->setText( i->addressee().realName() );
			else
				mDisplayName->setText( QString::null );
		}
	}
	QWizard::showPage( page );
}

#include "addcontactwizard.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>#include <MainApplication/Utils/Keyboard.hpp>

#include <Core/CoreMacros.hpp>
#include <Core/Log/Log.hpp>

#if defined( OS_WINDOWS )
#include <Windows.h>
#elif defined( OS_LINUX )
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/keysym.h>
#include <xcb/xcb.h>
#endif

namespace Ra
{
    namespace Gui
    {
#if defined( OS_WINDOWS )

        bool isKeyPressed( Key key )
        {

        }

#elif defined( OS_LINUX )

        bool isKeyPressed( Key key )
        {
            KeySym keysym = 0;
            switch (key)
            {
                case Key_LShift:     keysym = XK_Shift_L;      break;
                case Key_RShift:     keysym = XK_Shift_R;      break;
                case Key_LControl:   keysym = XK_Control_L;    break;
                case Key_RControl:   keysym = XK_Control_R;    break;
                case Key_LAlt:       keysym = XK_Alt_L;        break;
                case Key_RAlt:       keysym = XK_Alt_R;        break;
                case Key_LSystem:    keysym = XK_Super_L;      break;
                case Key_RSystem:    keysym = XK_Super_R;      break;
                case Key_Menu:       keysym = XK_Menu;         break;
                case Key_Escape:     keysym = XK_Escape;       break;
                case Key_SemiColon:  keysym = XK_semicolon;    break;
                case Key_Slash:      keysym = XK_slash;        break;
                case Key_Equal:      keysym = XK_equal;        break;
                case Key_Dash:       keysym = XK_minus;        break;
                case Key_LBracket:   keysym = XK_bracketleft;  break;
                case Key_RBracket:   keysym = XK_bracketright; break;
                case Key_Comma:      keysym = XK_comma;        break;
                case Key_Period:     keysym = XK_period;       break;
                case Key_Quote:      keysym = XK_apostrophe;   break;
                case Key_BackSlash:  keysym = XK_backslash;    break;
                case Key_Tilde:      keysym = XK_grave;        break;
                case Key_Space:      keysym = XK_space;        break;
                case Key_Return:     keysym = XK_Return;       break;
                case Key_BackSpace:  keysym = XK_BackSpace;    break;
                case Key_Tab:        keysym = XK_Tab;          break;
                case Key_PageUp:     keysym = XK_Prior;        break;
                case Key_PageDown:   keysym = XK_Next;         break;
                case Key_End:        keysym = XK_End;          break;
                case Key_Home:       keysym = XK_Home;         break;
                case Key_Insert:     keysym = XK_Insert;       break;
                case Key_Delete:     keysym = XK_Delete;       break;
                case Key_Add:        keysym = XK_KP_Add;       break;
                case Key_Subtract:   keysym = XK_KP_Subtract;  break;
                case Key_Multiply:   keysym = XK_KP_Multiply;  break;
                case Key_Divide:     keysym = XK_KP_Divide;    break;
                case Key_Pause:      keysym = XK_Pause;        break;
                case Key_F1:         keysym = XK_F1;           break;
                case Key_F2:         keysym = XK_F2;           break;
                case Key_F3:         keysym = XK_F3;           break;
                case Key_F4:         keysym = XK_F4;           break;
                case Key_F5:         keysym = XK_F5;           break;
                case Key_F6:         keysym = XK_F6;           break;
                case Key_F7:         keysym = XK_F7;           break;
                case Key_F8:         keysym = XK_F8;           break;
                case Key_F9:         keysym = XK_F9;           break;
                case Key_F10:        keysym = XK_F10;          break;
                case Key_F11:        keysym = XK_F11;          break;
                case Key_F12:        keysym = XK_F12;          break;
                case Key_F13:        keysym = XK_F13;          break;
                case Key_F14:        keysym = XK_F14;          break;
                case Key_F15:        keysym = XK_F15;          break;
                case Key_Left:       keysym = XK_Left;         break;
                case Key_Right:      keysym = XK_Right;        break;
                case Key_Up:         keysym = XK_Up;           break;
                case Key_Down:       keysym = XK_Down;         break;
                case Key_Numpad0:    keysym = XK_KP_Insert;    break;
                case Key_Numpad1:    keysym = XK_KP_End;       break;
                case Key_Numpad2:    keysym = XK_KP_Down;      break;
                case Key_Numpad3:    keysym = XK_KP_Page_Down; break;
                case Key_Numpad4:    keysym = XK_KP_Left;      break;
                case Key_Numpad5:    keysym = XK_KP_Begin;     break;
                case Key_Numpad6:    keysym = XK_KP_Right;     break;
                case Key_Numpad7:    keysym = XK_KP_Home;      break;
                case Key_Numpad8:    keysym = XK_KP_Up;        break;
                case Key_Numpad9:    keysym = XK_KP_Page_Up;   break;
                case Key_A:          keysym = XK_a;            break;
                case Key_B:          keysym = XK_b;            break;
                case Key_C:          keysym = XK_c;            break;
                case Key_D:          keysym = XK_d;            break;
                case Key_E:          keysym = XK_e;            break;
                case Key_F:          keysym = XK_f;            break;
                case Key_G:          keysym = XK_g;            break;
                case Key_H:          keysym = XK_h;            break;
                case Key_I:          keysym = XK_i;            break;
                case Key_J:          keysym = XK_j;            break;
                case Key_K:          keysym = XK_k;            break;
                case Key_L:          keysym = XK_l;            break;
                case Key_M:          keysym = XK_m;            break;
                case Key_N:          keysym = XK_n;            break;
                case Key_O:          keysym = XK_o;            break;
                case Key_P:          keysym = XK_p;            break;
                case Key_Q:          keysym = XK_q;            break;
                case Key_R:          keysym = XK_r;            break;
                case Key_S:          keysym = XK_s;            break;
                case Key_T:          keysym = XK_t;            break;
                case Key_U:          keysym = XK_u;            break;
                case Key_V:          keysym = XK_v;            break;
                case Key_W:          keysym = XK_w;            break;
                case Key_X:          keysym = XK_x;            break;
                case Key_Y:          keysym = XK_y;            break;
                case Key_Z:          keysym = XK_z;            break;
                case Key_Num0:       keysym = XK_0;            break;
                case Key_Num1:       keysym = XK_1;            break;
                case Key_Num2:       keysym = XK_2;            break;
                case Key_Num3:       keysym = XK_3;            break;
                case Key_Num4:       keysym = XK_4;            break;
                case Key_Num5:       keysym = XK_5;            break;
                case Key_Num6:       keysym = XK_6;            break;
                case Key_Num7:       keysym = XK_7;            break;
                case Key_Num8:       keysym = XK_8;            break;
                case Key_Num9:       keysym = XK_9;            break;
                default:             keysym = 0;               break;
            }

            Display* dis = XOpenDisplay( nullptr );
            xcb_keycode_t keycode = XKeysymToKeycode( dis, keysym );
            XCloseDisplay( dis );

            xcb_connection_t* connection = xcb_connect( nullptr, nullptr );
            xcb_generic_error_t* error = nullptr;

            xcb_query_keymap_reply_t* keymap = xcb_query_keymap_reply(
                connection, xcb_query_keymap( connection ), &error );

            xcb_disconnect( connection );

            if ( error )
            {
                LOG( logERROR ) << "Could not query keymap in isKeyPressed()";
                return false;
            }

            // NOTE(Charly): No real idea what is going on there, but it seems to work :D
            return ( keymap->keys[keycode / 8] & ( 1 << ( keycode % 8 ) ) ) != 0;
        }
#else
        bool isKeyPressed( Key key )
        {
            LOG( logERROR ) << "isKeyPressed is not implemented for your OS."
                return false;
        }
#endif
    }
}
<commit_msg>isKeyPressed for windows<commit_after>#include <MainApplication/Utils/Keyboard.hpp>

#include <Core/CoreMacros.hpp>
#include <Core/Log/Log.hpp>

#if defined( OS_WINDOWS )
#include <Windows.h>
#elif defined( OS_LINUX )
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/keysym.h>
#include <xcb/xcb.h>
#endif

namespace Ra
{
    namespace Gui
    {
#if defined( OS_WINDOWS )

        bool isKeyPressed( Key key )
        {
            int vkey = 0;
            switch (key)
            {
                case Key_A:          vkey = 'A';           break;
                case Key_B:          vkey = 'B';           break;
                case Key_C:          vkey = 'C';           break;
                case Key_D:          vkey = 'D';           break;
                case Key_E:          vkey = 'E';           break;
                case Key_F:          vkey = 'F';           break;
                case Key_G:          vkey = 'G';           break;
                case Key_H:          vkey = 'H';           break;
                case Key_I:          vkey = 'I';           break;
                case Key_J:          vkey = 'J';           break;
                case Key_K:          vkey = 'K';           break;
                case Key_L:          vkey = 'L';           break;
                case Key_M:          vkey = 'M';           break;
                case Key_N:          vkey = 'N';           break;
                case Key_O:          vkey = 'O';           break;
                case Key_P:          vkey = 'P';           break;
                case Key_Q:          vkey = 'Q';           break;
                case Key_R:          vkey = 'R';           break;
                case Key_S:          vkey = 'S';           break;
                case Key_T:          vkey = 'T';           break;
                case Key_U:          vkey = 'U';           break;
                case Key_V:          vkey = 'V';           break;
                case Key_W:          vkey = 'W';           break;
                case Key_X:          vkey = 'X';           break;
                case Key_Y:          vkey = 'Y';           break;
                case Key_Z:          vkey = 'Z';           break;
                case Key_Num0:       vkey = '0';           break;
                case Key_Num1:       vkey = '1';           break;
                case Key_Num2:       vkey = '2';           break;
                case Key_Num3:       vkey = '3';           break;
                case Key_Num4:       vkey = '4';           break;
                case Key_Num5:       vkey = '5';           break;
                case Key_Num6:       vkey = '6';           break;
                case Key_Num7:       vkey = '7';           break;
                case Key_Num8:       vkey = '8';           break;
                case Key_Num9:       vkey = '9';           break;
                case Key_Escape:     vkey = VK_ESCAPE;     break;
                case Key_LControl:   vkey = VK_LCONTROL;   break;
                case Key_LShift:     vkey = VK_LSHIFT;     break;
                case Key_LAlt:       vkey = VK_LMENU;      break;
                case Key_LSystem:    vkey = VK_LWIN;       break;
                case Key_RControl:   vkey = VK_RCONTROL;   break;
                case Key_RShift:     vkey = VK_RSHIFT;     break;
                case Key_RAlt:       vkey = VK_RMENU;      break;
                case Key_RSystem:    vkey = VK_RWIN;       break;
                case Key_Menu:       vkey = VK_APPS;       break;
                case Key_LBracket:   vkey = VK_OEM_4;      break;
                case Key_RBracket:   vkey = VK_OEM_6;      break;
                case Key_SemiColon:  vkey = VK_OEM_1;      break;
                case Key_Comma:      vkey = VK_OEM_COMMA;  break;
                case Key_Period:     vkey = VK_OEM_PERIOD; break;
                case Key_Quote:      vkey = VK_OEM_7;      break;
                case Key_Slash:      vkey = VK_OEM_2;      break;
                case Key_BackSlash:  vkey = VK_OEM_5;      break;
                case Key_Tilde:      vkey = VK_OEM_3;      break;
                case Key_Equal:      vkey = VK_OEM_PLUS;   break;
                case Key_Dash:       vkey = VK_OEM_MINUS;  break;
                case Key_Space:      vkey = VK_SPACE;      break;
                case Key_Return:     vkey = VK_RETURN;     break;
                case Key_BackSpace:  vkey = VK_BACK;       break;
                case Key_Tab:        vkey = VK_TAB;        break;
                case Key_PageUp:     vkey = VK_PRIOR;      break;
                case Key_PageDown:   vkey = VK_NEXT;       break;
                case Key_End:        vkey = VK_END;        break;
                case Key_Home:       vkey = VK_HOME;       break;
                case Key_Insert:     vkey = VK_INSERT;     break;
                case Key_Delete:     vkey = VK_DELETE;     break;
                case Key_Add:        vkey = VK_ADD;        break;
                case Key_Subtract:   vkey = VK_SUBTRACT;   break;
                case Key_Multiply:   vkey = VK_MULTIPLY;   break;
                case Key_Divide:     vkey = VK_DIVIDE;     break;
                case Key_Left:       vkey = VK_LEFT;       break;
                case Key_Right:      vkey = VK_RIGHT;      break;
                case Key_Up:         vkey = VK_UP;         break;
                case Key_Down:       vkey = VK_DOWN;       break;
                case Key_Numpad0:    vkey = VK_NUMPAD0;    break;
                case Key_Numpad1:    vkey = VK_NUMPAD1;    break;
                case Key_Numpad2:    vkey = VK_NUMPAD2;    break;
                case Key_Numpad3:    vkey = VK_NUMPAD3;    break;
                case Key_Numpad4:    vkey = VK_NUMPAD4;    break;
                case Key_Numpad5:    vkey = VK_NUMPAD5;    break;
                case Key_Numpad6:    vkey = VK_NUMPAD6;    break;
                case Key_Numpad7:    vkey = VK_NUMPAD7;    break;
                case Key_Numpad8:    vkey = VK_NUMPAD8;    break;
                case Key_Numpad9:    vkey = VK_NUMPAD9;    break;
                case Key_F1:         vkey = VK_F1;         break;
                case Key_F2:         vkey = VK_F2;         break;
                case Key_F3:         vkey = VK_F3;         break;
                case Key_F4:         vkey = VK_F4;         break;
                case Key_F5:         vkey = VK_F5;         break;
                case Key_F6:         vkey = VK_F6;         break;
                case Key_F7:         vkey = VK_F7;         break;
                case Key_F8:         vkey = VK_F8;         break;
                case Key_F9:         vkey = VK_F9;         break;
                case Key_F10:        vkey = VK_F10;        break;
                case Key_F11:        vkey = VK_F11;        break;
                case Key_F12:        vkey = VK_F12;        break;
                case Key_F13:        vkey = VK_F13;        break;
                case Key_F14:        vkey = VK_F14;        break;
                case Key_F15:        vkey = VK_F15;        break;
                case Key_Pause:      vkey = VK_PAUSE;      break;
                default:             vkey = 0;             break;
            }

            return ( GetAsyncKeyState( vkey ) & 0x8000 ) != 0;
        }

#elif defined( OS_LINUX )

        bool isKeyPressed( Key key )
        {
            KeySym keysym = 0;
            switch (key)
            {
                case Key_LShift:     keysym = XK_Shift_L;      break;
                case Key_RShift:     keysym = XK_Shift_R;      break;
                case Key_LControl:   keysym = XK_Control_L;    break;
                case Key_RControl:   keysym = XK_Control_R;    break;
                case Key_LAlt:       keysym = XK_Alt_L;        break;
                case Key_RAlt:       keysym = XK_Alt_R;        break;
                case Key_LSystem:    keysym = XK_Super_L;      break;
                case Key_RSystem:    keysym = XK_Super_R;      break;
                case Key_Menu:       keysym = XK_Menu;         break;
                case Key_Escape:     keysym = XK_Escape;       break;
                case Key_SemiColon:  keysym = XK_semicolon;    break;
                case Key_Slash:      keysym = XK_slash;        break;
                case Key_Equal:      keysym = XK_equal;        break;
                case Key_Dash:       keysym = XK_minus;        break;
                case Key_LBracket:   keysym = XK_bracketleft;  break;
                case Key_RBracket:   keysym = XK_bracketright; break;
                case Key_Comma:      keysym = XK_comma;        break;
                case Key_Period:     keysym = XK_period;       break;
                case Key_Quote:      keysym = XK_apostrophe;   break;
                case Key_BackSlash:  keysym = XK_backslash;    break;
                case Key_Tilde:      keysym = XK_grave;        break;
                case Key_Space:      keysym = XK_space;        break;
                case Key_Return:     keysym = XK_Return;       break;
                case Key_BackSpace:  keysym = XK_BackSpace;    break;
                case Key_Tab:        keysym = XK_Tab;          break;
                case Key_PageUp:     keysym = XK_Prior;        break;
                case Key_PageDown:   keysym = XK_Next;         break;
                case Key_End:        keysym = XK_End;          break;
                case Key_Home:       keysym = XK_Home;         break;
                case Key_Insert:     keysym = XK_Insert;       break;
                case Key_Delete:     keysym = XK_Delete;       break;
                case Key_Add:        keysym = XK_KP_Add;       break;
                case Key_Subtract:   keysym = XK_KP_Subtract;  break;
                case Key_Multiply:   keysym = XK_KP_Multiply;  break;
                case Key_Divide:     keysym = XK_KP_Divide;    break;
                case Key_Pause:      keysym = XK_Pause;        break;
                case Key_F1:         keysym = XK_F1;           break;
                case Key_F2:         keysym = XK_F2;           break;
                case Key_F3:         keysym = XK_F3;           break;
                case Key_F4:         keysym = XK_F4;           break;
                case Key_F5:         keysym = XK_F5;           break;
                case Key_F6:         keysym = XK_F6;           break;
                case Key_F7:         keysym = XK_F7;           break;
                case Key_F8:         keysym = XK_F8;           break;
                case Key_F9:         keysym = XK_F9;           break;
                case Key_F10:        keysym = XK_F10;          break;
                case Key_F11:        keysym = XK_F11;          break;
                case Key_F12:        keysym = XK_F12;          break;
                case Key_F13:        keysym = XK_F13;          break;
                case Key_F14:        keysym = XK_F14;          break;
                case Key_F15:        keysym = XK_F15;          break;
                case Key_Left:       keysym = XK_Left;         break;
                case Key_Right:      keysym = XK_Right;        break;
                case Key_Up:         keysym = XK_Up;           break;
                case Key_Down:       keysym = XK_Down;         break;
                case Key_Numpad0:    keysym = XK_KP_Insert;    break;
                case Key_Numpad1:    keysym = XK_KP_End;       break;
                case Key_Numpad2:    keysym = XK_KP_Down;      break;
                case Key_Numpad3:    keysym = XK_KP_Page_Down; break;
                case Key_Numpad4:    keysym = XK_KP_Left;      break;
                case Key_Numpad5:    keysym = XK_KP_Begin;     break;
                case Key_Numpad6:    keysym = XK_KP_Right;     break;
                case Key_Numpad7:    keysym = XK_KP_Home;      break;
                case Key_Numpad8:    keysym = XK_KP_Up;        break;
                case Key_Numpad9:    keysym = XK_KP_Page_Up;   break;
                case Key_A:          keysym = XK_a;            break;
                case Key_B:          keysym = XK_b;            break;
                case Key_C:          keysym = XK_c;            break;
                case Key_D:          keysym = XK_d;            break;
                case Key_E:          keysym = XK_e;            break;
                case Key_F:          keysym = XK_f;            break;
                case Key_G:          keysym = XK_g;            break;
                case Key_H:          keysym = XK_h;            break;
                case Key_I:          keysym = XK_i;            break;
                case Key_J:          keysym = XK_j;            break;
                case Key_K:          keysym = XK_k;            break;
                case Key_L:          keysym = XK_l;            break;
                case Key_M:          keysym = XK_m;            break;
                case Key_N:          keysym = XK_n;            break;
                case Key_O:          keysym = XK_o;            break;
                case Key_P:          keysym = XK_p;            break;
                case Key_Q:          keysym = XK_q;            break;
                case Key_R:          keysym = XK_r;            break;
                case Key_S:          keysym = XK_s;            break;
                case Key_T:          keysym = XK_t;            break;
                case Key_U:          keysym = XK_u;            break;
                case Key_V:          keysym = XK_v;            break;
                case Key_W:          keysym = XK_w;            break;
                case Key_X:          keysym = XK_x;            break;
                case Key_Y:          keysym = XK_y;            break;
                case Key_Z:          keysym = XK_z;            break;
                case Key_Num0:       keysym = XK_0;            break;
                case Key_Num1:       keysym = XK_1;            break;
                case Key_Num2:       keysym = XK_2;            break;
                case Key_Num3:       keysym = XK_3;            break;
                case Key_Num4:       keysym = XK_4;            break;
                case Key_Num5:       keysym = XK_5;            break;
                case Key_Num6:       keysym = XK_6;            break;
                case Key_Num7:       keysym = XK_7;            break;
                case Key_Num8:       keysym = XK_8;            break;
                case Key_Num9:       keysym = XK_9;            break;
                default:             keysym = 0;               break;
            }

            Display* dis = XOpenDisplay( nullptr );
            xcb_keycode_t keycode = XKeysymToKeycode( dis, keysym );
            XCloseDisplay( dis );

            xcb_connection_t* connection = xcb_connect( nullptr, nullptr );
            xcb_generic_error_t* error = nullptr;

            xcb_query_keymap_reply_t* keymap = xcb_query_keymap_reply(
                connection, xcb_query_keymap( connection ), &error );

            xcb_disconnect( connection );

            if ( error )
            {
                LOG( logERROR ) << "Could not query keymap in isKeyPressed()";
                return false;
            }

            // NOTE(Charly): No real idea what is going on there, but it seems to work :D
            return ( keymap->keys[keycode / 8] & ( 1 << ( keycode % 8 ) ) ) != 0;
        }
#else
        bool isKeyPressed( Key key )
        {
            LOG( logERROR ) << "isKeyPressed is not implemented for your OS."
                return false;
        }
#endif
    }
}
<|endoftext|>


<commit_before>//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the InstructionSelect class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#define DEBUG_TYPE "instruction-select"

using namespace llvm;

char InstructionSelect::ID = 0;
INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
                      "Select target instructions out of generic instructions",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE,
                    "Select target instructions out of generic instructions",
                    false, false)

InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) {
  initializeInstructionSelectPass(*PassRegistry::getPassRegistry());
}

void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<TargetPassConfig>();
  MachineFunctionPass::getAnalysisUsage(AU);
}

static void reportSelectionError(const MachineFunction &MF,
                                 const MachineInstr *MI, const Twine &Message) {
  std::string ErrStorage;
  raw_string_ostream Err(ErrStorage);
  Err << Message << ":\nIn function: " << MF.getName() << '\n';
  if (MI)
    Err << *MI << '\n';
  report_fatal_error(Err.str());
}

bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
  // If the ISel pipeline failed, do not bother running that pass.
  if (MF.getProperties().hasProperty(
          MachineFunctionProperties::Property::FailedISel))
    return false;

  DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n');

  const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
  const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
  assert(ISel && "Cannot work without InstructionSelector");

  // FIXME: freezeReservedRegs is now done in IRTranslator, but there are many
  // other MF/MFI fields we need to initialize.

  const MachineRegisterInfo &MRI = MF.getRegInfo();

#ifndef NDEBUG
  // Check that our input is fully legal: we require the function to have the
  // Legalized property, so it should be.
  // FIXME: This should be in the MachineVerifier, but it can't use the
  // LegalizerInfo as it's currently in the separate GlobalISel library.
  // The RegBankSelected property is already checked in the verifier. Note
  // that it has the same layering problem, but we only use inline methods so
  // end up not needing to link against the GlobalISel library.
  if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo())
    for (const MachineBasicBlock &MBB : MF)
      for (const MachineInstr &MI : MBB)
        if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI))
          reportSelectionError(MF, &MI, "Instruction is not legal");

#endif
  // FIXME: We could introduce new blocks and will need to fix the outer loop.
  // Until then, keep track of the number of blocks to assert that we don't.
  const size_t NumBlocks = MF.size();

  bool Failed = false;
  for (MachineBasicBlock *MBB : post_order(&MF)) {
    if (MBB->empty())
      continue;

    // Select instructions in reverse block order. We permit erasing so have
    // to resort to manually iterating and recognizing the begin (rend) case.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
         !ReachedBegin;) {
#ifndef NDEBUG
      // Keep track of the insertion range for debug printing.
      const auto AfterIt = std::next(MII);
#endif
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;

      DEBUG(dbgs() << "Selecting: \n  " << MI);

      if (!ISel->select(MI)) {
        if (TPC.isGlobalISelAbortEnabled())
          // FIXME: It would be nice to dump all inserted instructions.  It's
          // not obvious how, esp. considering select() can insert after MI.
          reportSelectionError(MF, &MI, "Cannot select");
        Failed = true;
        break;
      }

      // Dump the range of instructions that MI expanded into.
      DEBUG({
        auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII);
        dbgs() << "Into:\n";
        for (auto &InsertedMI : make_range(InsertedBegin, AfterIt))
          dbgs() << "  " << InsertedMI;
        dbgs() << '\n';
      });
    }
  }

  // Now that selection is complete, there are no more generic vregs.  Verify
  // that the size of the now-constrained vreg is unchanged and that it has a
  // register class.
  for (auto &VRegToType : MRI.getVRegToType()) {
    unsigned VReg = VRegToType.first;
    auto *RC = MRI.getRegClassOrNull(VReg);
    MachineInstr *MI = nullptr;
    if (!MRI.def_empty(VReg))
      MI = &*MRI.def_instr_begin(VReg);
    else if (!MRI.use_empty(VReg))
      MI = &*MRI.use_instr_begin(VReg);

    if (MI && !RC) {
      if (TPC.isGlobalISelAbortEnabled())
        reportSelectionError(MF, MI, "VReg has no regclass after selection");
      Failed = true;
      break;
    } else if (!RC)
      continue;

    if (VRegToType.second.isValid() &&
        VRegToType.second.getSizeInBits() > (RC->getSize() * 8)) {
      if (TPC.isGlobalISelAbortEnabled())
        reportSelectionError(
            MF, MI, "VReg has explicit size different from class size");
      Failed = true;
      break;
    }
  }

  MRI.getVRegToType().clear();

  if (!TPC.isGlobalISelAbortEnabled() && (Failed || MF.size() != NumBlocks)) {
    MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
    return false;
  }
  assert(MF.size() == NumBlocks && "Inserting blocks is not supported yet");

  // FIXME: Should we accurately track changes?
  return true;
}
<commit_msg>[GlobalISel] Simplify Select type cleanup using a ScopeExit. NFC.<commit_after>//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the InstructionSelect class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#define DEBUG_TYPE "instruction-select"

using namespace llvm;

char InstructionSelect::ID = 0;
INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
                      "Select target instructions out of generic instructions",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE,
                    "Select target instructions out of generic instructions",
                    false, false)

InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) {
  initializeInstructionSelectPass(*PassRegistry::getPassRegistry());
}

void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<TargetPassConfig>();
  MachineFunctionPass::getAnalysisUsage(AU);
}

static void reportSelectionError(const MachineFunction &MF,
                                 const MachineInstr *MI, const Twine &Message) {
  std::string ErrStorage;
  raw_string_ostream Err(ErrStorage);
  Err << Message << ":\nIn function: " << MF.getName() << '\n';
  if (MI)
    Err << *MI << '\n';
  report_fatal_error(Err.str());
}

bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
  const MachineRegisterInfo &MRI = MF.getRegInfo();

  // No matter what happens, whether we successfully select the function or not,
  // nothing is going to use the vreg types after us.  Make sure they disappear.
  auto ClearVRegTypesOnReturn =
      make_scope_exit([&]() { MRI.getVRegToType().clear(); });

  // If the ISel pipeline failed, do not bother running that pass.
  if (MF.getProperties().hasProperty(
          MachineFunctionProperties::Property::FailedISel))
    return false;

  DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n');

  const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
  const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
  assert(ISel && "Cannot work without InstructionSelector");

  // FIXME: freezeReservedRegs is now done in IRTranslator, but there are many
  // other MF/MFI fields we need to initialize.

#ifndef NDEBUG
  // Check that our input is fully legal: we require the function to have the
  // Legalized property, so it should be.
  // FIXME: This should be in the MachineVerifier, but it can't use the
  // LegalizerInfo as it's currently in the separate GlobalISel library.
  // The RegBankSelected property is already checked in the verifier. Note
  // that it has the same layering problem, but we only use inline methods so
  // end up not needing to link against the GlobalISel library.
  if (const LegalizerInfo *MLI = MF.getSubtarget().getLegalizerInfo())
    for (const MachineBasicBlock &MBB : MF)
      for (const MachineInstr &MI : MBB)
        if (isPreISelGenericOpcode(MI.getOpcode()) && !MLI->isLegal(MI, MRI))
          reportSelectionError(MF, &MI, "Instruction is not legal");

#endif
  // FIXME: We could introduce new blocks and will need to fix the outer loop.
  // Until then, keep track of the number of blocks to assert that we don't.
  const size_t NumBlocks = MF.size();

  for (MachineBasicBlock *MBB : post_order(&MF)) {
    if (MBB->empty())
      continue;

    // Select instructions in reverse block order. We permit erasing so have
    // to resort to manually iterating and recognizing the begin (rend) case.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
         !ReachedBegin;) {
#ifndef NDEBUG
      // Keep track of the insertion range for debug printing.
      const auto AfterIt = std::next(MII);
#endif
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;

      DEBUG(dbgs() << "Selecting: \n  " << MI);

      if (!ISel->select(MI)) {
        if (TPC.isGlobalISelAbortEnabled())
          // FIXME: It would be nice to dump all inserted instructions.  It's
          // not obvious how, esp. considering select() can insert after MI.
          reportSelectionError(MF, &MI, "Cannot select");
        MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
        return false;
      }

      // Dump the range of instructions that MI expanded into.
      DEBUG({
        auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII);
        dbgs() << "Into:\n";
        for (auto &InsertedMI : make_range(InsertedBegin, AfterIt))
          dbgs() << "  " << InsertedMI;
        dbgs() << '\n';
      });
    }
  }

  // Now that selection is complete, there are no more generic vregs.  Verify
  // that the size of the now-constrained vreg is unchanged and that it has a
  // register class.
  for (auto &VRegToType : MRI.getVRegToType()) {
    unsigned VReg = VRegToType.first;
    auto *RC = MRI.getRegClassOrNull(VReg);
    MachineInstr *MI = nullptr;
    if (!MRI.def_empty(VReg))
      MI = &*MRI.def_instr_begin(VReg);
    else if (!MRI.use_empty(VReg))
      MI = &*MRI.use_instr_begin(VReg);

    if (MI && !RC) {
      if (TPC.isGlobalISelAbortEnabled())
        reportSelectionError(MF, MI, "VReg has no regclass after selection");
      MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
      return false;
    } else if (!RC)
      continue;

    if (VRegToType.second.isValid() &&
        VRegToType.second.getSizeInBits() > (RC->getSize() * 8)) {
      if (TPC.isGlobalISelAbortEnabled())
        reportSelectionError(
            MF, MI, "VReg has explicit size different from class size");
      MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
      return false;
    }
  }

  if (MF.size() != NumBlocks) {
    if (TPC.isGlobalISelAbortEnabled())
      reportSelectionError(MF, /*MI=*/nullptr,
                           "Inserting blocks is not supported yet");
    MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
    return false;
  }

  // FIXME: Should we accurately track changes?
  return true;
}
<|endoftext|>


<commit_before>//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the InstructionSelect class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/config.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"

#define DEBUG_TYPE "instruction-select"

using namespace llvm;

#ifdef LLVM_GISEL_COV_PREFIX
static cl::opt<std::string>
    CoveragePrefix("gisel-coverage-prefix", cl::init(LLVM_GISEL_COV_PREFIX),
                   cl::desc("Record GlobalISel rule coverage files of this "
                            "prefix if instrumentation was generated"));
#else
static const std::string CoveragePrefix = "";
#endif

char InstructionSelect::ID = 0;
INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
                      "Select target instructions out of generic instructions",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE,
                    "Select target instructions out of generic instructions",
                    false, false)

InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) {
  initializeInstructionSelectPass(*PassRegistry::getPassRegistry());
}

void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<TargetPassConfig>();
  getSelectionDAGFallbackAnalysisUsage(AU);
  MachineFunctionPass::getAnalysisUsage(AU);
}

bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
  // If the ISel pipeline failed, do not bother running that pass.
  if (MF.getProperties().hasProperty(
          MachineFunctionProperties::Property::FailedISel))
    return false;

  LLVM_DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n');

  const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
  const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
  CodeGenCoverage CoverageInfo;
  assert(ISel && "Cannot work without InstructionSelector");

  // An optimization remark emitter. Used to report failures.
  MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);

  // FIXME: There are many other MF/MFI fields we need to initialize.

  MachineRegisterInfo &MRI = MF.getRegInfo();
#ifndef NDEBUG
  // Check that our input is fully legal: we require the function to have the
  // Legalized property, so it should be.
  // FIXME: This should be in the MachineVerifier, as the RegBankSelected
  // property check already is.
  if (!DisableGISelLegalityCheck)
    if (const MachineInstr *MI = machineFunctionIsIllegal(MF)) {
      reportGISelFailure(MF, TPC, MORE, "gisel-select",
                         "instruction is not legal", *MI);
      return false;
    }
#endif
  // FIXME: We could introduce new blocks and will need to fix the outer loop.
  // Until then, keep track of the number of blocks to assert that we don't.
  const size_t NumBlocks = MF.size();

  for (MachineBasicBlock *MBB : post_order(&MF)) {
    if (MBB->empty())
      continue;

    // Select instructions in reverse block order. We permit erasing so have
    // to resort to manually iterating and recognizing the begin (rend) case.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
         !ReachedBegin;) {
#ifndef NDEBUG
      // Keep track of the insertion range for debug printing.
      const auto AfterIt = std::next(MII);
#endif
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;

      LLVM_DEBUG(dbgs() << "Selecting: \n  " << MI);

      // We could have folded this instruction away already, making it dead.
      // If so, erase it.
      if (isTriviallyDead(MI, MRI)) {
        LLVM_DEBUG(dbgs() << "Is dead; erasing.\n");
        MI.eraseFromParentAndMarkDBGValuesForRemoval();
        continue;
      }

      if (!ISel->select(MI, CoverageInfo)) {
        // FIXME: It would be nice to dump all inserted instructions.  It's
        // not obvious how, esp. considering select() can insert after MI.
        reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI);
        return false;
      }

      // Dump the range of instructions that MI expanded into.
      LLVM_DEBUG({
        auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII);
        dbgs() << "Into:\n";
        for (auto &InsertedMI : make_range(InsertedBegin, AfterIt))
          dbgs() << "  " << InsertedMI;
        dbgs() << '\n';
      });
    }
  }

  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();

  for (MachineBasicBlock &MBB : MF) {
    if (MBB.empty())
      continue;

    // Try to find redundant copies b/w vregs of the same register class.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB.end()), Begin = MBB.begin(); !ReachedBegin;) {
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;
      if (MI.getOpcode() != TargetOpcode::COPY)
        continue;
      unsigned SrcReg = MI.getOperand(1).getReg();
      unsigned DstReg = MI.getOperand(0).getReg();
      if (TargetRegisterInfo::isVirtualRegister(SrcReg) &&
          TargetRegisterInfo::isVirtualRegister(DstReg)) {
        auto SrcRC = MRI.getRegClass(SrcReg);
        auto DstRC = MRI.getRegClass(DstReg);
        if (SrcRC == DstRC) {
          MRI.replaceRegWith(DstReg, SrcReg);
          MI.eraseFromParentAndMarkDBGValuesForRemoval();
        }
      }
    }
  }

  // Now that selection is complete, there are no more generic vregs.  Verify
  // that the size of the now-constrained vreg is unchanged and that it has a
  // register class.
  for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
    unsigned VReg = TargetRegisterInfo::index2VirtReg(I);

    MachineInstr *MI = nullptr;
    if (!MRI.def_empty(VReg))
      MI = &*MRI.def_instr_begin(VReg);
    else if (!MRI.use_empty(VReg))
      MI = &*MRI.use_instr_begin(VReg);
    if (!MI)
      continue;

    const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
    if (!RC) {
      reportGISelFailure(MF, TPC, MORE, "gisel-select",
                         "VReg has no regclass after selection", *MI);
      return false;
    }

    const LLT Ty = MRI.getType(VReg);
    if (Ty.isValid() && Ty.getSizeInBits() > TRI.getRegSizeInBits(*RC)) {
      reportGISelFailure(
          MF, TPC, MORE, "gisel-select",
          "VReg's low-level type and register class have different sizes", *MI);
      return false;
    }
  }

  if (MF.size() != NumBlocks) {
    MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure",
                                      MF.getFunction().getSubprogram(),
                                      /*MBB=*/nullptr);
    R << "inserting blocks is not supported yet";
    reportGISelFailure(MF, TPC, MORE, R);
    return false;
  }

  auto &TLI = *MF.getSubtarget().getTargetLowering();
  TLI.finalizeLowering(MF);

  LLVM_DEBUG({
    dbgs() << "Rules covered by selecting function: " << MF.getName() << ":";
    for (auto RuleID : CoverageInfo.covered())
      dbgs() << " id" << RuleID;
    dbgs() << "\n\n";
  });
  CoverageInfo.emit(CoveragePrefix,
                    MF.getSubtarget()
                        .getTargetLowering()
                        ->getTargetMachine()
                        .getTarget()
                        .getBackendName());

  // If we successfully selected the function nothing is going to use the vreg
  // types after us (otherwise MIRPrinter would need them). Make sure the types
  // disappear.
  MRI.clearVirtRegTypes();

  // FIXME: Should we accurately track changes?
  return true;
}
<commit_msg>[GlobalISel] Make isel verification checks of vregs run under NDEBUG only.<commit_after>//===- llvm/CodeGen/GlobalISel/InstructionSelect.cpp - InstructionSelect ---==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the InstructionSelect class.
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
#include "llvm/CodeGen/GlobalISel/Utils.h"
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/config.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetRegistry.h"

#define DEBUG_TYPE "instruction-select"

using namespace llvm;

#ifdef LLVM_GISEL_COV_PREFIX
static cl::opt<std::string>
    CoveragePrefix("gisel-coverage-prefix", cl::init(LLVM_GISEL_COV_PREFIX),
                   cl::desc("Record GlobalISel rule coverage files of this "
                            "prefix if instrumentation was generated"));
#else
static const std::string CoveragePrefix = "";
#endif

char InstructionSelect::ID = 0;
INITIALIZE_PASS_BEGIN(InstructionSelect, DEBUG_TYPE,
                      "Select target instructions out of generic instructions",
                      false, false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(InstructionSelect, DEBUG_TYPE,
                    "Select target instructions out of generic instructions",
                    false, false)

InstructionSelect::InstructionSelect() : MachineFunctionPass(ID) {
  initializeInstructionSelectPass(*PassRegistry::getPassRegistry());
}

void InstructionSelect::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<TargetPassConfig>();
  getSelectionDAGFallbackAnalysisUsage(AU);
  MachineFunctionPass::getAnalysisUsage(AU);
}

bool InstructionSelect::runOnMachineFunction(MachineFunction &MF) {
  // If the ISel pipeline failed, do not bother running that pass.
  if (MF.getProperties().hasProperty(
          MachineFunctionProperties::Property::FailedISel))
    return false;

  LLVM_DEBUG(dbgs() << "Selecting function: " << MF.getName() << '\n');

  const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
  const InstructionSelector *ISel = MF.getSubtarget().getInstructionSelector();
  CodeGenCoverage CoverageInfo;
  assert(ISel && "Cannot work without InstructionSelector");

  // An optimization remark emitter. Used to report failures.
  MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);

  // FIXME: There are many other MF/MFI fields we need to initialize.

  MachineRegisterInfo &MRI = MF.getRegInfo();
#ifndef NDEBUG
  // Check that our input is fully legal: we require the function to have the
  // Legalized property, so it should be.
  // FIXME: This should be in the MachineVerifier, as the RegBankSelected
  // property check already is.
  if (!DisableGISelLegalityCheck)
    if (const MachineInstr *MI = machineFunctionIsIllegal(MF)) {
      reportGISelFailure(MF, TPC, MORE, "gisel-select",
                         "instruction is not legal", *MI);
      return false;
    }
  // FIXME: We could introduce new blocks and will need to fix the outer loop.
  // Until then, keep track of the number of blocks to assert that we don't.
  const size_t NumBlocks = MF.size();
#endif

  for (MachineBasicBlock *MBB : post_order(&MF)) {
    if (MBB->empty())
      continue;

    // Select instructions in reverse block order. We permit erasing so have
    // to resort to manually iterating and recognizing the begin (rend) case.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
         !ReachedBegin;) {
#ifndef NDEBUG
      // Keep track of the insertion range for debug printing.
      const auto AfterIt = std::next(MII);
#endif
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;

      LLVM_DEBUG(dbgs() << "Selecting: \n  " << MI);

      // We could have folded this instruction away already, making it dead.
      // If so, erase it.
      if (isTriviallyDead(MI, MRI)) {
        LLVM_DEBUG(dbgs() << "Is dead; erasing.\n");
        MI.eraseFromParentAndMarkDBGValuesForRemoval();
        continue;
      }

      if (!ISel->select(MI, CoverageInfo)) {
        // FIXME: It would be nice to dump all inserted instructions.  It's
        // not obvious how, esp. considering select() can insert after MI.
        reportGISelFailure(MF, TPC, MORE, "gisel-select", "cannot select", MI);
        return false;
      }

      // Dump the range of instructions that MI expanded into.
      LLVM_DEBUG({
        auto InsertedBegin = ReachedBegin ? MBB->begin() : std::next(MII);
        dbgs() << "Into:\n";
        for (auto &InsertedMI : make_range(InsertedBegin, AfterIt))
          dbgs() << "  " << InsertedMI;
        dbgs() << '\n';
      });
    }
  }

  for (MachineBasicBlock &MBB : MF) {
    if (MBB.empty())
      continue;

    // Try to find redundant copies b/w vregs of the same register class.
    bool ReachedBegin = false;
    for (auto MII = std::prev(MBB.end()), Begin = MBB.begin(); !ReachedBegin;) {
      // Select this instruction.
      MachineInstr &MI = *MII;

      // And have our iterator point to the next instruction, if there is one.
      if (MII == Begin)
        ReachedBegin = true;
      else
        --MII;
      if (MI.getOpcode() != TargetOpcode::COPY)
        continue;
      unsigned SrcReg = MI.getOperand(1).getReg();
      unsigned DstReg = MI.getOperand(0).getReg();
      if (TargetRegisterInfo::isVirtualRegister(SrcReg) &&
          TargetRegisterInfo::isVirtualRegister(DstReg)) {
        auto SrcRC = MRI.getRegClass(SrcReg);
        auto DstRC = MRI.getRegClass(DstReg);
        if (SrcRC == DstRC) {
          MRI.replaceRegWith(DstReg, SrcReg);
          MI.eraseFromParentAndMarkDBGValuesForRemoval();
        }
      }
    }
  }

#ifndef NDEBUG
  const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
  // Now that selection is complete, there are no more generic vregs.  Verify
  // that the size of the now-constrained vreg is unchanged and that it has a
  // register class.
  for (unsigned I = 0, E = MRI.getNumVirtRegs(); I != E; ++I) {
    unsigned VReg = TargetRegisterInfo::index2VirtReg(I);

    MachineInstr *MI = nullptr;
    if (!MRI.def_empty(VReg))
      MI = &*MRI.def_instr_begin(VReg);
    else if (!MRI.use_empty(VReg))
      MI = &*MRI.use_instr_begin(VReg);
    if (!MI)
      continue;

    const TargetRegisterClass *RC = MRI.getRegClassOrNull(VReg);
    if (!RC) {
      reportGISelFailure(MF, TPC, MORE, "gisel-select",
                         "VReg has no regclass after selection", *MI);
      return false;
    }

    const LLT Ty = MRI.getType(VReg);
    if (Ty.isValid() && Ty.getSizeInBits() > TRI.getRegSizeInBits(*RC)) {
      reportGISelFailure(
          MF, TPC, MORE, "gisel-select",
          "VReg's low-level type and register class have different sizes", *MI);
      return false;
    }
  }

  if (MF.size() != NumBlocks) {
    MachineOptimizationRemarkMissed R("gisel-select", "GISelFailure",
                                      MF.getFunction().getSubprogram(),
                                      /*MBB=*/nullptr);
    R << "inserting blocks is not supported yet";
    reportGISelFailure(MF, TPC, MORE, R);
    return false;
  }
#endif
  auto &TLI = *MF.getSubtarget().getTargetLowering();
  TLI.finalizeLowering(MF);

  LLVM_DEBUG({
    dbgs() << "Rules covered by selecting function: " << MF.getName() << ":";
    for (auto RuleID : CoverageInfo.covered())
      dbgs() << " id" << RuleID;
    dbgs() << "\n\n";
  });
  CoverageInfo.emit(CoveragePrefix,
                    MF.getSubtarget()
                        .getTargetLowering()
                        ->getTargetMachine()
                        .getTarget()
                        .getBackendName());

  // If we successfully selected the function nothing is going to use the vreg
  // types after us (otherwise MIRPrinter would need them). Make sure the types
  // disappear.
  MRI.clearVirtRegTypes();

  // FIXME: Should we accurately track changes?
  return true;
}
<|endoftext|>


<commit_before>/*  MConfig - C++ library for working with configuration files
    Copyright (C) 2011 Dmitry Shatrov

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <libmary/types.h>
#include <cctype>

#include <mycpp/native_file.h>
#include <mycpp/cached_file.h>

#include <pargen/parser.h>

#include <scruffy/preprocessor.h>
#include <scruffy/list_pp_item_stream.h>
#include <scruffy/pp_item_stream_token_stream.h>
#include <scruffy/checkpoint_tracker.h>

#include <mconfig/mconfig_pargen.h>

#include <mconfig/config_parser.h>

using namespace M;

namespace MConfig {

class ConfigParser
{
public:
    MyCpp::List<Section*> sections;

    Scruffy::CheckpointTracker checkpoint_tracker;

    ConfigParser (Config * const config)
    {
	sections.append (config->getRootSection());
    }
};

// Characters banned from words: " { } , ; # =
//
// " is used for string literals, which are provided by pargen with quotes
// included.
//
bool
mconfig_word_token_match_func (MyCpp::ConstMemoryDesc const &token_mem,
			       void * const /* token_user_ptr */,
			       void * const /* user_data */)
{
    logD_ (_func, ConstMemory (token_mem));

    if (token_mem.getLength() == 0)
	return false;

    char const *token = (char const*) token_mem.getMemory();
    if (token [0] == '{' ||
	token [0] == '}' ||
	token [0] == ',' ||
	token [0] == ';' ||
	token [0] == '#' ||
	token [0] == '=')
    {
	return false;
    }

    if (token [0] == '"'
	&& (token_mem.getLength() == 1
	    || token [token_mem.getLength() - 1] != '"'))
    {
	return false;
    }

    return true;
}

static bool
whitespaceBetweenWordsNeeded (ConstMemory const &left,
			      ConstMemory const &right)
{
    if (left .len() == 0 ||
	right.len() == 0)
    {
	return false;
    }

    if (isalnum (left.mem() [left.len() - 1]) &&
	isalnum (right.mem() [0]))
    {
	return true;
    }

    return false;
}

static Ref<String>
wordsToString (MyCpp::List<MConfig_Word*> * const mt_nonnull words)
{
    Size str_len = 0;
    {
	ConstMemory prv_word;
	MyCpp::List<MConfig_Word*>::DataIterator iter (*words);
	while (!iter.done ()) {
	    MConfig_Word * const word_ = iter.next();

	    ConstMemory word = word_->any_token->token;
	    // Stripping quotes from string literals.
	    if (word.len() && word.mem() [0] == '"') {
		assert (word.len() >= 2);
		word = word.region (1, word.len() - 2);
	    }

	    str_len += word.len();

	    if (whitespaceBetweenWordsNeeded (prv_word, word))
		++str_len;

	    prv_word = word;
	}
    }

    logD_ (_func, "str_len: ", str_len);

    Ref<String> str = grab (new String (str_len));

    {
	Size pos = 0;
	ConstMemory prv_word;
	MyCpp::List<MConfig_Word*>::DataIterator iter (*words);
	while (!iter.done ()) {
	    MConfig_Word * const word_ = iter.next();

	    ConstMemory word = word_->any_token->token;
	    logD_ (_func, "word: ", word);
	    // Stripping quotes from string literals.
	    if (word.len() && word.mem() [0] == '"') {
		assert (word.len() >= 2);
		word = word.region (1, word.len() - 2);
	    }

	    if (whitespaceBetweenWordsNeeded (prv_word, word)) {
		str->mem().mem() [pos] = ' ';
		++pos;
	    }

	    memcpy (str->mem().mem() + pos, word.mem(), word.len());
	    pos += word.len();

	    prv_word = word;
	}
    }

    logD_ (_func, "str: ", str);

    return str;
}

static Ref<String>
keyToString (MConfig_Key * const key)
{
    if (!key)
	return grab (new String());

    return wordsToString (&key->words);
}

bool
mconfig_begin_section (MConfig_Section       * const section,
		       Pargen::ParserControl * const /* parser_control */,
		       void                  * const _self)
{
    ConfigParser * const self = static_cast <ConfigParser*> (_self);

    Ref<String> section_name = keyToString (section->name);

    logD_ (_func, "section: ", section_name);

    Section *opts_section = self->sections.getLast()->getSection (section_name->mem());
    if (!opts_section) {
	opts_section = new Section (keyToString (section->name)->mem());
	self->sections.getLast()->addSection (opts_section);
    }

    self->sections.append (opts_section);
    self->checkpoint_tracker.addUnconditionalCancellable (
	    MyCpp::grab (new Scruffy::Cancellable_ListElement<Section*> (
		    self->sections,
		    self->sections.last)));

    return true;
}

bool
mconfig_accept_option (MConfig_Option         * const option,
		       Pargen::ParserControl  * const /* parser_control */,
		       void                   * const _self)
{
    ConfigParser * const self = static_cast <ConfigParser*> (_self);

    if (self->sections.isEmpty()) {
	logE_ (_func, "option not within any section");
	return false;
    }

    Section * const section = self->sections.getLast();

    MConfig_Option_KeyValue *option__key_value = NULL;

    MConfig_Key *key_elem = NULL;
    switch (option->option_type) {
	case MConfig_Option::_KeyValue: {
	    option__key_value = static_cast <MConfig_Option_KeyValue*> (option);
	    key_elem = option__key_value->key;
	} break;
	case MConfig_Option::_Key: {
	    MConfig_Option_Key * const option__key = static_cast <MConfig_Option_Key*> (option);
	    key_elem = option__key->key;
	} break;
	default:
	    unreachable ();
    }

    Ref<String> key = keyToString (key_elem);

    logD_ (_func, "option: ", key);

    Option *opts_option = section->getOption (key->mem());
    if (opts_option) {
	opts_option->removeValues ();
    } else {
	opts_option = new Option (key->mem());
	self->sections.getLast()->addOption (opts_option);
    }

    if (option__key_value) {
	MConfig_Value *value = option__key_value->value;
	for (;;) {
	    switch (value->value_type) {
		case MConfig_Value::_List: {
		    MConfig_Value_List * const value__list = static_cast <MConfig_Value_List*> (value);
		    logD_ (_func, "value: ", wordsToString (&value__list->words));
		    opts_option->addValue (wordsToString (&value__list->words)->mem());
		    value = value__list->value;
		    logD_ (_func, "new value: 0x", fmt_hex, (UintPtr) value);
		} break;
		case MConfig_Value::_Word: {
		    MConfig_Value_Word * const value__word = static_cast <MConfig_Value_Word*> (value);
		    logD_ (_func, "value: ", wordsToString (&value__word->words));
		    opts_option->addValue (wordsToString (&value__word->words)->mem());
		    value = NULL;
		} break;
		default:
		    unreachable ();
	    }

	    if (!value)
		break;
	}
    }

    logD_ (_func, "done");

    return true;
}

Result parseConfig (ConstMemory const &filename,
		    Config * const config)
try {
    MyCpp::Ref<Pargen::Grammar> grammar = create_mconfig_grammar ();

    MyCpp::Ref<MyCpp::File> file = MyCpp::File::createDefault (filename,
							       0 /* open_flags */,
							       MyCpp::AccessMode::ReadOnly);
    file = MyCpp::grab (new MyCpp::CachedFile (file, (1 << 14) /* page_size */, 64 /* max_pages */));

    MyCpp::Ref<Scruffy::CppPreprocessor> const preprocessor = MyCpp::grab (new Scruffy::CppPreprocessor (file));
    preprocessor->performPreprocessing ();

    MyCpp::Ref< MyCpp::List_< MyCpp::Ref<Scruffy::PpItem>, MyCpp::SimplyReferenced > > pp_items =
	    preprocessor->getPpItems ();

    MyCpp::Ref<Scruffy::PpItemStream> pp_stream =
	    MyCpp::grab (static_cast <Scruffy::PpItemStream*> (
		    new Scruffy::ListPpItemStream (pp_items->first, MyLang::FilePosition ())));

    MyCpp::Ref<Scruffy::PpItemStreamTokenStream> token_stream =
	    MyCpp::grab (new Scruffy::PpItemStreamTokenStream (pp_stream));
    token_stream->setNewlineReplacement (";");

    ConfigParser config_parser (config);

    Pargen::ParserElement *mconfig_elem = NULL;
    Pargen::parse (token_stream,
		   &config_parser.checkpoint_tracker,
		   &config_parser,
		   grammar,
		   &mconfig_elem,
		   MyCpp::ConstMemoryDesc::forString ("default"),
		   // TODO Set 'upwards_jumps' to true for non-AST mode.
		   Pargen::createParserConfig (false /* upwards_jumps */),
		   false /* debug_dump */);

    if (mconfig_elem == NULL ||
	token_stream->getNextToken ().getLength () > 0)
    {
	logE_ (_func, "EOF not reached");
	return Result::Failure;
    }

    dump_mconfig_grammar (static_cast <MConfig_Grammar*> (mconfig_elem));
    MyCpp::errf->pflush ();

    return Result::Success;
} catch (...) {
    logE_ (_func, "exception");
    return Result::Failure;
}

}

<commit_msg>Allow lists of sections with the same name.<commit_after>/*  MConfig - C++ library for working with configuration files
    Copyright (C) 2011 Dmitry Shatrov

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <libmary/types.h>
#include <cctype>

#include <mycpp/native_file.h>
#include <mycpp/cached_file.h>

#include <pargen/parser.h>

#include <scruffy/preprocessor.h>
#include <scruffy/list_pp_item_stream.h>
#include <scruffy/pp_item_stream_token_stream.h>
#include <scruffy/checkpoint_tracker.h>

#include <mconfig/mconfig_pargen.h>

#include <mconfig/config_parser.h>

using namespace M;

namespace MConfig {

class ConfigParser
{
public:
    MyCpp::List<Section*> sections;

    Scruffy::CheckpointTracker checkpoint_tracker;

    ConfigParser (Config * const config)
    {
	sections.append (config->getRootSection());
    }
};

// Characters banned from words: " { } , ; # =
//
// " is used for string literals, which are provided by pargen with quotes
// included.
//
bool
mconfig_word_token_match_func (MyCpp::ConstMemoryDesc const &token_mem,
			       void * const /* token_user_ptr */,
			       void * const /* user_data */)
{
    logD_ (_func, ConstMemory (token_mem));

    if (token_mem.getLength() == 0)
	return false;

    char const *token = (char const*) token_mem.getMemory();
    if (token [0] == '{' ||
	token [0] == '}' ||
	token [0] == ',' ||
	token [0] == ';' ||
	token [0] == '#' ||
	token [0] == '=')
    {
	return false;
    }

    if (token [0] == '"'
	&& (token_mem.getLength() == 1
	    || token [token_mem.getLength() - 1] != '"'))
    {
	return false;
    }

    return true;
}

static bool
whitespaceBetweenWordsNeeded (ConstMemory const &left,
			      ConstMemory const &right)
{
    if (left .len() == 0 ||
	right.len() == 0)
    {
	return false;
    }

    if (isalnum (left.mem() [left.len() - 1]) &&
	isalnum (right.mem() [0]))
    {
	return true;
    }

    return false;
}

static Ref<String>
wordsToString (MyCpp::List<MConfig_Word*> * const mt_nonnull words)
{
    Size str_len = 0;
    {
	ConstMemory prv_word;
	MyCpp::List<MConfig_Word*>::DataIterator iter (*words);
	while (!iter.done ()) {
	    MConfig_Word * const word_ = iter.next();

	    ConstMemory word = word_->any_token->token;
	    // Stripping quotes from string literals.
	    if (word.len() && word.mem() [0] == '"') {
		assert (word.len() >= 2);
		word = word.region (1, word.len() - 2);
	    }

	    str_len += word.len();

	    if (whitespaceBetweenWordsNeeded (prv_word, word))
		++str_len;

	    prv_word = word;
	}
    }

    logD_ (_func, "str_len: ", str_len);

    Ref<String> str = grab (new String (str_len));

    {
	Size pos = 0;
	ConstMemory prv_word;
	MyCpp::List<MConfig_Word*>::DataIterator iter (*words);
	while (!iter.done ()) {
	    MConfig_Word * const word_ = iter.next();

	    ConstMemory word = word_->any_token->token;
	    logD_ (_func, "word: ", word);
	    // Stripping quotes from string literals.
	    if (word.len() && word.mem() [0] == '"') {
		assert (word.len() >= 2);
		word = word.region (1, word.len() - 2);
	    }

	    if (whitespaceBetweenWordsNeeded (prv_word, word)) {
		str->mem().mem() [pos] = ' ';
		++pos;
	    }

	    memcpy (str->mem().mem() + pos, word.mem(), word.len());
	    pos += word.len();

	    prv_word = word;
	}
    }

    logD_ (_func, "str: ", str);

    return str;
}

static Ref<String>
keyToString (MConfig_Key * const key)
{
    if (!key)
	return grab (new String());

    return wordsToString (&key->words);
}

bool
mconfig_begin_section (MConfig_Section       * const section,
		       Pargen::ParserControl * const /* parser_control */,
		       void                  * const _self)
{
    ConfigParser * const self = static_cast <ConfigParser*> (_self);

    Ref<String> section_name = keyToString (section->name);

    logD_ (_func, "section: ", section_name);

// Section value replacement was disabled to allow lists of sections
// with the same name (for Moment's mod_file).
//  Section *opts_section = self->sections.getLast()->getSection (section_name->mem());
    Section *opts_section = NULL;
    if (!opts_section) {
	opts_section = new Section (keyToString (section->name)->mem());
	self->sections.getLast()->addSection (opts_section);
    }

    self->sections.append (opts_section);
    self->checkpoint_tracker.addUnconditionalCancellable (
	    MyCpp::grab (new Scruffy::Cancellable_ListElement<Section*> (
		    self->sections,
		    self->sections.last)));

    return true;
}

bool
mconfig_accept_option (MConfig_Option         * const option,
		       Pargen::ParserControl  * const /* parser_control */,
		       void                   * const _self)
{
    ConfigParser * const self = static_cast <ConfigParser*> (_self);

    if (self->sections.isEmpty()) {
	logE_ (_func, "option not within any section");
	return false;
    }

    Section * const section = self->sections.getLast();

    MConfig_Option_KeyValue *option__key_value = NULL;

    MConfig_Key *key_elem = NULL;
    switch (option->option_type) {
	case MConfig_Option::_KeyValue: {
	    option__key_value = static_cast <MConfig_Option_KeyValue*> (option);
	    key_elem = option__key_value->key;
	} break;
	case MConfig_Option::_Key: {
	    MConfig_Option_Key * const option__key = static_cast <MConfig_Option_Key*> (option);
	    key_elem = option__key->key;
	} break;
	default:
	    unreachable ();
    }

    Ref<String> key = keyToString (key_elem);

    logD_ (_func, "option: ", key);

    Option *opts_option = section->getOption (key->mem());
    if (opts_option) {
	opts_option->removeValues ();
    } else {
	opts_option = new Option (key->mem());
	self->sections.getLast()->addOption (opts_option);
    }

    if (option__key_value) {
	MConfig_Value *value = option__key_value->value;
	for (;;) {
	    switch (value->value_type) {
		case MConfig_Value::_List: {
		    MConfig_Value_List * const value__list = static_cast <MConfig_Value_List*> (value);
		    logD_ (_func, "value: ", wordsToString (&value__list->words));
		    opts_option->addValue (wordsToString (&value__list->words)->mem());
		    value = value__list->value;
		    logD_ (_func, "new value: 0x", fmt_hex, (UintPtr) value);
		} break;
		case MConfig_Value::_Word: {
		    MConfig_Value_Word * const value__word = static_cast <MConfig_Value_Word*> (value);
		    logD_ (_func, "value: ", wordsToString (&value__word->words));
		    opts_option->addValue (wordsToString (&value__word->words)->mem());
		    value = NULL;
		} break;
		default:
		    unreachable ();
	    }

	    if (!value)
		break;
	}
    }

    logD_ (_func, "done");

    return true;
}

Result parseConfig (ConstMemory const &filename,
		    Config * const config)
try {
    MyCpp::Ref<Pargen::Grammar> grammar = create_mconfig_grammar ();

    MyCpp::Ref<MyCpp::File> file = MyCpp::File::createDefault (filename,
							       0 /* open_flags */,
							       MyCpp::AccessMode::ReadOnly);
    file = MyCpp::grab (new MyCpp::CachedFile (file, (1 << 14) /* page_size */, 64 /* max_pages */));

    MyCpp::Ref<Scruffy::CppPreprocessor> const preprocessor = MyCpp::grab (new Scruffy::CppPreprocessor (file));
    preprocessor->performPreprocessing ();

    MyCpp::Ref< MyCpp::List_< MyCpp::Ref<Scruffy::PpItem>, MyCpp::SimplyReferenced > > pp_items =
	    preprocessor->getPpItems ();

    MyCpp::Ref<Scruffy::PpItemStream> pp_stream =
	    MyCpp::grab (static_cast <Scruffy::PpItemStream*> (
		    new Scruffy::ListPpItemStream (pp_items->first, MyLang::FilePosition ())));

    MyCpp::Ref<Scruffy::PpItemStreamTokenStream> token_stream =
	    MyCpp::grab (new Scruffy::PpItemStreamTokenStream (pp_stream));
    token_stream->setNewlineReplacement (";");

    ConfigParser config_parser (config);

    Pargen::ParserElement *mconfig_elem = NULL;
    Pargen::parse (token_stream,
		   &config_parser.checkpoint_tracker,
		   &config_parser,
		   grammar,
		   &mconfig_elem,
		   MyCpp::ConstMemoryDesc::forString ("default"),
		   // TODO Set 'upwards_jumps' to true for non-AST mode.
		   Pargen::createParserConfig (false /* upwards_jumps */),
		   false /* debug_dump */);

    if (mconfig_elem == NULL ||
	token_stream->getNextToken ().getLength () > 0)
    {
	logE_ (_func, "EOF not reached");
	return Result::Failure;
    }

    dump_mconfig_grammar (static_cast <MConfig_Grammar*> (mconfig_elem));
    MyCpp::errf->pflush ();

    return Result::Success;
} catch (...) {
    logE_ (_func, "exception");
    return Result::Failure;
}

}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: shutdown_quickstart.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:34:27 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "quickstarter.hxx"
#include <setup_native/qswin32.h>

static BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam )
{
    MSIHANDLE   hMSI = static_cast< MSIHANDLE >( lParam );
    CHAR    szClassName[sizeof(QUICKSTART_CLASSNAMEA) + 1];

    int nCharsCopied = GetClassName( hWnd, szClassName, sizeof( szClassName ) );

    if ( nCharsCopied && !stricmp( QUICKSTART_CLASSNAMEA, szClassName ) )
    {
        DWORD   dwProcessId;

        if ( GetWindowThreadProcessId( hWnd, &dwProcessId ) )
        {
            std::string sImagePath = GetProcessImagePath( dwProcessId );
            std::string sOfficeImageDir = GetOfficeInstallationPath( hMSI ) + "program\\";

            if ( !strnicmp( sImagePath.c_str(), sOfficeImageDir.c_str(), sOfficeImageDir.length() ) )
            {
                UINT    uMsgShutdownQuickstart = RegisterWindowMessageA( SHUTDOWN_QUICKSTART_MESSAGEA );

                if ( uMsgShutdownQuickstart )
                    SendMessageA( hWnd, uMsgShutdownQuickstart, 0, 0 );

                return FALSE;
            }

        }
    }

    return TRUE;
}

extern "C" UINT __stdcall ShutDownQuickstarter( MSIHANDLE hMSI )
{
    EnumWindows( EnumWindowsProc, hMSI );

    return ERROR_SUCCESS;
}

<commit_msg>INTEGRATION: CWS qssyncterm (1.4.180); FILE MERGED 2007/08/02 14:08:25 hro 1.4.180.1: #149979# Wait at most 30 seconds to give Quickstarter enough time to terminate before setup continues<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: shutdown_quickstart.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: ihi $ $Date: 2007-08-17 13:35:41 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "quickstarter.hxx"
#include <setup_native/qswin32.h>

static BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam )
{
    MSIHANDLE   hMSI = static_cast< MSIHANDLE >( lParam );
    CHAR    szClassName[sizeof(QUICKSTART_CLASSNAMEA) + 1];

    int nCharsCopied = GetClassName( hWnd, szClassName, sizeof( szClassName ) );

    if ( nCharsCopied && !stricmp( QUICKSTART_CLASSNAMEA, szClassName ) )
    {
        DWORD   dwProcessId;

        if ( GetWindowThreadProcessId( hWnd, &dwProcessId ) )
        {
            std::string sImagePath = GetProcessImagePath( dwProcessId );
            std::string sOfficeImageDir = GetOfficeInstallationPath( hMSI ) + "program\\";

            if ( !strnicmp( sImagePath.c_str(), sOfficeImageDir.c_str(), sOfficeImageDir.length() ) )
            {
                UINT    uMsgShutdownQuickstart = RegisterWindowMessageA( SHUTDOWN_QUICKSTART_MESSAGEA );

                if ( uMsgShutdownQuickstart )
                    SendMessageA( hWnd, uMsgShutdownQuickstart, 0, 0 );

                HANDLE  hProcess = OpenProcess( SYNCHRONIZE, FALSE, dwProcessId );

                if ( hProcess )
                {
                    WaitForSingleObject( hProcess, 30000 ); // Wait at most 30 seconds for process to terminate
                    CloseHandle( hProcess );
                }

                return FALSE;
            }

        }
    }

    return TRUE;
}

extern "C" UINT __stdcall ShutDownQuickstarter( MSIHANDLE hMSI )
{
    EnumWindows( EnumWindowsProc, hMSI );

    return ERROR_SUCCESS;
}

<|endoftext|>