<commit_before>/*************************************************************************
 *
 *  $RCSfile: accessibilityclient.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 15:05:09 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX
#define TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX

#ifndef TOOLKIT_HELPER_ACCESSIBLE_FACTORY_HXX
#include <toolkit/helper/accessiblefactory.hxx>
#endif

//........................................................................
namespace toolkit
{
//........................................................................

    //====================================================================
    //= AccessibilityClient
    //====================================================================
    /** a client for the accessibility implementations which have been
        outsourced from the main toolkit library

        All instances of this class share a reference to a common IAccessibleFactory
        instance, which is used for creating all kind of Accessibility related
        components.

        When the AccessibilityClient goes aways, this factory goes aways, to, and the respective
        library is unloaded.

        This class is not thread-safe.
    */
    class AccessibilityClient
    {
    private:
        bool    m_bInitialized;

    public:
        AccessibilityClient();
        ~AccessibilityClient();

        IAccessibleFactory& getFactory();

    private:
        void ensureInitialized();
    };

//........................................................................
}   // namespace toolkit
//........................................................................

#endif // TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX

<commit_msg>INTEGRATION: CWS finalsisslremoval (1.2.10); FILE MERGED 2007/07/15 07:53:10 pjanik 1.2.10.1: #i79627#: Remove SISSL.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: accessibilityclient.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2007-07-18 10:05:58 $
 *
 *  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
 *
 ************************************************************************/

#ifndef TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX
#define TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX

#ifndef TOOLKIT_HELPER_ACCESSIBLE_FACTORY_HXX
#include <toolkit/helper/accessiblefactory.hxx>
#endif

//........................................................................
namespace toolkit
{
//........................................................................

    //====================================================================
    //= AccessibilityClient
    //====================================================================
    /** a client for the accessibility implementations which have been
        outsourced from the main toolkit library

        All instances of this class share a reference to a common IAccessibleFactory
        instance, which is used for creating all kind of Accessibility related
        components.

        When the AccessibilityClient goes aways, this factory goes aways, to, and the respective
        library is unloaded.

        This class is not thread-safe.
    */
    class AccessibilityClient
    {
    private:
        bool    m_bInitialized;

    public:
        AccessibilityClient();
        ~AccessibilityClient();

        IAccessibleFactory& getFactory();

    private:
        void ensureInitialized();
    };

//........................................................................
}   // namespace toolkit
//........................................................................

#endif // TOOLKIT_HELPER_ACCESSIBILITY_CLIENT_HXX

<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	コマンド入力クラス
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>

extern "C" {
	void sci_putch(char ch);
	void sci_puts(const char *str);
	char sci_getch(void);
	uint16_t sci_length(void);
};

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  command class
		@param[in]	buffsize	バッファサイズ（最小でも９）
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <int16_t buffsize>
	class command {
		char	buff_[buffsize];
		int16_t	bpos_;
		int16_t	pos_;
		int16_t	len_;
		int16_t tab_top_;

		const char*	prompt_;

		bool	tab_;

		// VT-100 ESC シーケンス
		static void clear_line_() {
			sci_putch(0x1b);
			sci_putch('[');
			sci_putch('0');
			sci_putch('J');
		}

		static void save_cursor_() {
			sci_putch(0x1b);
			sci_putch('7');
		}

		static void load_cursor_() {
			sci_putch(0x1b);
			sci_putch('8');
		}

		static void crlf_() {
			sci_putch('\r');	///< CR
			sci_putch('\n');	///< LF
		}
	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		command() : bpos_(-1), pos_(0), len_(0), tab_top_(-1),
			prompt_(nullptr), tab_(false) { buff_[0] = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  プロムプト文字列を設定
			@param[in]	text	文字列
        */
        //-----------------------------------------------------------------//
		void set_prompt(const char* text) { prompt_ = text; }

        //-----------------------------------------------------------------//
        /*!
            @brief  サービス @n
					定期的に呼び出す
			@return 「Enter」キーが押されたら「true」
        */
        //-----------------------------------------------------------------//
		bool service() {
			if(bpos_ < 0 && pos_ == 0) {
				if(prompt_) sci_puts(prompt_);
			}
			bpos_ = pos_;
			tab_ = false;
			while(sci_length()) {
				if(pos_ >= (buffsize - 1)) {	///< バッファが溢れた・・
					sci_putch('\\');		///< バックスラッシュ
					buff_[buffsize - 1] = 0;
					pos_ = 0;
					bpos_ = -1;
					crlf_();
					return false;
				} else if(pos_ >= (buffsize - 8)) {	///< バッファが溢れそうな警告
					sci_putch('G' - 0x40);	///< Ctrl-G
				}

				char ch = sci_getch();
				switch(ch) {
				case '\r':	// Enter キー
					buff_[pos_] = 0;
					len_ = pos_;
					clear_line_();
					crlf_();
					pos_ = 0;
					bpos_ = -1;
					tab_top_ = -1;
					return true;

				case 0x08:	// バックスペース
					if(pos_) {
						--pos_;
						sci_putch(0x08);
						if(buff_[pos_] < 0x20) {
							sci_putch(0x08);
						}
					} else {
						pos_ = 0;
						bpos_ = -1;
						crlf_();
					}
					break;

				case '\t':  // TAB キー
					if(tab_top_ < 0) {
						tab_top_ = pos_;
						save_cursor_();
					}
					tab_ = true;
					break;

				default:
					if(ch < 0x20) {	///< 他の ctrl コード
						buff_[pos_] = ch;
						++pos_;
						sci_putch('^');
						sci_putch(ch + 0x40);
					} else {
						buff_[pos_] = ch;
						++pos_;
						sci_putch(ch);
					}
					buff_[pos_] = 0;
					break;
				}
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  コマンド行を取得
			@return コマンド行
        */
        //-----------------------------------------------------------------//
		const char* get_command() const { return buff_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  ワード数を取得
			@return ワード数を返す
        */
        //-----------------------------------------------------------------//
		uint8_t get_words() const {
			const char* p = buff_;
			char bc = ' ';
			uint8_t n = 0;
			while(1) {
				char ch = *p++;
				if(ch == 0) break;
				if(bc == ' ' && ch != ' ') {
					++n;
				}
				bc = ch;
			}
			return n;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  ワードを取得
			@param[in]	argc	ワード位置
			@param[in]	limit	ワード文字列リミット数
			@param[out]	word	ワード文字列格納ポインター
			@return 取得できたら「true」を返す
        */
        //-----------------------------------------------------------------//
		bool get_word(uint8_t argc, uint8_t limit, char* word) const {
			const char* p = buff_;
			char bc = ' ';
			const char* wd = p;
			while(1) {
				char ch = *p;
				if(bc == ' ' && ch != ' ') {
					wd = p;
				}
				if(bc != ' ' && (ch == ' ' || ch == 0)) {
					if(argc == 0) {
						uint8_t i;
						for(i = 0; i < (p - wd); ++i) {
							--limit;
							if(limit == 0) break;
							word[i] = wd[i];
						}
						word[i] = 0;
						return true;
					}
					--argc;
				}
				if(ch == 0) break;
				bc = ch;
				++p;
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  ワードを比較
			@param[in]	argc	ワード位置
			@param[in]	key		比較文字列
			@return
        */
        //-----------------------------------------------------------------//
		bool cmp_word(uint8_t argc, const char* key) const {
			const char* p = buff_;
			char bc = ' ';
			const char* top;
			while(1) {
				char ch = *p;
				if(bc == ' ' && ch != ' ') {
					top = p;
				}
				if(bc != ' ' && (ch == ' ' || ch == 0)) {
					if(argc == 0) {
						return std::strncmp(key, top, p - top) == 0;
					}
					--argc;
				}
				if(ch == 0) break;
				bc = ch;
				++p;
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB キーが押されたか
			@return 押されたら「true」
        */
        //-----------------------------------------------------------------//
		bool probe_tab() const { return tab_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB 注入位置のリセット
        */
        //-----------------------------------------------------------------//
		void reset_tab() { tab_top_ = -1; }

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB キーの候補を注入
			@param[in]	key	注入文字列
        */
        //-----------------------------------------------------------------//
		void injection_tab(const char* key) {
			if(tab_top_ < 0) return;
			std::strcpy(&buff_[tab_top_], key);

			load_cursor_();
			sci_puts(key);
		}
	};
}
<commit_msg>fix compare length<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	コマンド入力クラス
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>

extern "C" {
	void sci_putch(char ch);
	void sci_puts(const char *str);
	char sci_getch(void);
	uint16_t sci_length(void);
};

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  command class
		@param[in]	buffsize	バッファサイズ（最小でも９）
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <int16_t buffsize>
	class command {
		char	buff_[buffsize];
		int16_t	bpos_;
		int16_t	pos_;
		int16_t	len_;
		int16_t tab_top_;

		const char*	prompt_;

		bool	tab_;

		// VT-100 ESC シーケンス
		static void clear_line_() {
			sci_putch(0x1b);
			sci_putch('[');
			sci_putch('0');
			sci_putch('J');
		}

		static void save_cursor_() {
			sci_putch(0x1b);
			sci_putch('7');
		}

		static void load_cursor_() {
			sci_putch(0x1b);
			sci_putch('8');
		}

		static void crlf_() {
			sci_putch('\r');	///< CR
			sci_putch('\n');	///< LF
		}
	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		command() : bpos_(-1), pos_(0), len_(0), tab_top_(-1),
			prompt_(nullptr), tab_(false) { buff_[0] = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  プロムプト文字列を設定
			@param[in]	text	文字列
        */
        //-----------------------------------------------------------------//
		void set_prompt(const char* text) { prompt_ = text; }

        //-----------------------------------------------------------------//
        /*!
            @brief  サービス @n
					定期的に呼び出す
			@return 「Enter」キーが押されたら「true」
        */
        //-----------------------------------------------------------------//
		bool service() {
			if(bpos_ < 0 && pos_ == 0) {
				if(prompt_) sci_puts(prompt_);
			}
			bpos_ = pos_;
			tab_ = false;
			while(sci_length()) {
				if(pos_ >= (buffsize - 1)) {	///< バッファが溢れた・・
					sci_putch('\\');		///< バックスラッシュ
					buff_[buffsize - 1] = 0;
					pos_ = 0;
					bpos_ = -1;
					crlf_();
					return false;
				} else if(pos_ >= (buffsize - 8)) {	///< バッファが溢れそうな警告
					sci_putch('G' - 0x40);	///< Ctrl-G
				}

				char ch = sci_getch();
				switch(ch) {
				case '\r':	// Enter キー
					buff_[pos_] = 0;
					len_ = pos_;
					clear_line_();
					crlf_();
					pos_ = 0;
					bpos_ = -1;
					tab_top_ = -1;
					return true;

				case 0x08:	// バックスペース
					if(pos_) {
						--pos_;
						sci_putch(0x08);
						if(buff_[pos_] < 0x20) {
							sci_putch(0x08);
						}
					} else {
						pos_ = 0;
						bpos_ = -1;
						crlf_();
					}
					break;

				case '\t':  // TAB キー
					if(tab_top_ < 0) {
						tab_top_ = pos_;
						save_cursor_();
					}
					tab_ = true;
					break;

				default:
					if(ch < 0x20) {	///< 他の ctrl コード
						buff_[pos_] = ch;
						++pos_;
						sci_putch('^');
						sci_putch(ch + 0x40);
					} else {
						buff_[pos_] = ch;
						++pos_;
						sci_putch(ch);
					}
					buff_[pos_] = 0;
					break;
				}
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  コマンド行を取得
			@return コマンド行
        */
        //-----------------------------------------------------------------//
		const char* get_command() const { return buff_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  ワード数を取得
			@return ワード数を返す
        */
        //-----------------------------------------------------------------//
		uint8_t get_words() const {
			const char* p = buff_;
			char bc = ' ';
			uint8_t n = 0;
			while(1) {
				char ch = *p++;
				if(ch == 0) break;
				if(bc == ' ' && ch != ' ') {
					++n;
				}
				bc = ch;
			}
			return n;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  ワードを取得
			@param[in]	argc	ワード位置
			@param[in]	limit	ワード文字列リミット数
			@param[out]	word	ワード文字列格納ポインター
			@return 取得できたら「true」を返す
        */
        //-----------------------------------------------------------------//
		bool get_word(uint8_t argc, uint8_t limit, char* word) const {
			const char* p = buff_;
			char bc = ' ';
			const char* wd = p;
			while(1) {
				char ch = *p;
				if(bc == ' ' && ch != ' ') {
					wd = p;
				}
				if(bc != ' ' && (ch == ' ' || ch == 0)) {
					if(argc == 0) {
						uint8_t i;
						for(i = 0; i < (p - wd); ++i) {
							--limit;
							if(limit == 0) break;
							word[i] = wd[i];
						}
						word[i] = 0;
						return true;
					}
					--argc;
				}
				if(ch == 0) break;
				bc = ch;
				++p;
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  ワードを比較
			@param[in]	argc	ワード位置
			@param[in]	key		比較文字列
			@return
        */
        //-----------------------------------------------------------------//
		bool cmp_word(uint8_t argc, const char* key) const {
			const char* p = buff_;
			char bc = ' ';
			const char* top;
			while(1) {
				char ch = *p;
				if(bc == ' ' && ch != ' ') {
					top = p;
				}
				if(bc != ' ' && (ch == ' ' || ch == 0)) {
					if(argc == 0) {
						return std::strncmp(key, top, std::strlen(key)) == 0;
					}
					--argc;
				}
				if(ch == 0) break;
				bc = ch;
				++p;
			}
			return false;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB キーが押されたか
			@return 押されたら「true」
        */
        //-----------------------------------------------------------------//
		bool probe_tab() const { return tab_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB 注入位置のリセット
        */
        //-----------------------------------------------------------------//
		void reset_tab() { tab_top_ = -1; }

        //-----------------------------------------------------------------//
        /*!
            @brief  TAB キーの候補を注入
			@param[in]	key	注入文字列
        */
        //-----------------------------------------------------------------//
		void injection_tab(const char* key) {
			if(tab_top_ < 0) return;
			std::strcpy(&buff_[tab_top_], key);

			load_cursor_();
			sci_puts(key);
		}
	};
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2009-05-06
// Updated : 2010-04-30
// Licence : This source is under MIT License
// File    : glm/gtc/type_ptr.hpp
///////////////////////////////////////////////////////////////////////////////////////////////////
// Dependency:
// - GLM core
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef glm_gtc_type_ptr
#define glm_gtc_type_ptr

// Dependency:
#include "../glm.hpp"

#if(defined(GLM_MESSAGES) && !defined(glm_ext))
#	pragma message("GLM: GLM_GTC_type_ptr extension included")
#endif

namespace glm
{
	namespace test{
		void main_gtc_type_ptr();
	}//namespace test

	namespace gtc{
	//! GLM_GTC_type_ptr extension: Get access to vectors & matrices value type address.
	namespace type_ptr{

		/// \addtogroup gtc_type_ptr
		///@{

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec2<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec2<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec3<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec3<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec4<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec4<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x3<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat4x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x3<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat4x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr(detail::tmat4x3<T> & mat)
		{
			return &(mat[0].x);
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec2<T> make_vec2(T const * const ptr)
		{
			detail::tvec2<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tvec2<T>));
			return Result;
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec3<T> make_vec3(T const * const ptr)
		{
			detail::tvec3<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tvec3<T>));
			return Result;
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec4<T> make_vec4(T const * const ptr)
		{
			detail::tvec4<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tvec4<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat2<T> make_mat2(T const * const ptr)
		{
			detail::tmat2<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tmat2<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat3<T> make_mat3(T const * const ptr)
		{
			detail::tmat3<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tmat3<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat4<T> make_mat4(T const * const ptr)
		{
			detail::tmat4<T> Result;
			memcpy(&Result[0], ptr, sizeof(detail::tmat4<T>));
			return Result;
		}

		///@}

	}//namespace type_ptr
	}//namespace gtc
}//namespace glm

#include "type_ptr.inl"

namespace glm{using namespace gtc::type_ptr;}

#endif//glm_gtx_type_ptr

<commit_msg>Completed implementation of building a GLM type from a pointer<commit_after>///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2009-05-06
// Updated : 2010-04-30
// Licence : This source is under MIT License
// File    : glm/gtc/type_ptr.hpp
///////////////////////////////////////////////////////////////////////////////////////////////////
// Dependency:
// - GLM core
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef glm_gtc_type_ptr
#define glm_gtc_type_ptr

// Dependency:
#include "../glm.hpp"

#if(defined(GLM_MESSAGES) && !defined(glm_ext))
#	pragma message("GLM: GLM_GTC_type_ptr extension included")
#endif

namespace glm
{
	namespace test{
		void main_gtc_type_ptr();
	}//namespace test

	namespace gtc{
	//! GLM_GTC_type_ptr extension: Get access to vectors & matrices value type address.
	namespace type_ptr{

		/// \addtogroup gtc_type_ptr
		///@{

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec2<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec2<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec3<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec3<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tvec4<T> const & vec
		)
		{
			return &(vec.x);
		}

		//! Get the address of the vector content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tvec4<T> & vec
		)
		{
			return &(vec.x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x3<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat4x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x3<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat2x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat2x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x2<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat4x2<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat3x4<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr
		(
			detail::tmat3x4<T> & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the const address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T const * value_ptr
		(
			detail::tmat4x3<T> const & mat
		)
		{
			return &(mat[0].x);
		}

		//! Get the address of the matrix content.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline T * value_ptr(detail::tmat4x3<T> & mat)
		{
			return &(mat[0].x);
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec2<T> make_vec2(T const * const ptr)
		{
			detail::tvec2<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tvec2<T>));
			return Result;
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec3<T> make_vec3(T const * const ptr)
		{
			detail::tvec3<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tvec3<T>));
			return Result;
		}

		//! Build a vector from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tvec4<T> make_vec4(T const * const ptr)
		{
			detail::tvec4<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tvec4<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat2x2<T> make_mat2x2(T const * const ptr)
		{
			detail::tmat2x2<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat2x2<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat2x3<T> make_mat2x3(T const * const ptr)
		{
			detail::tmat2x3<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat2x3<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat2x4<T> make_mat2x4(T const * const ptr)
		{
			detail::tmat2x4<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat2x4<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat3x2<T> make_mat3x2(T const * const ptr)
		{
			detail::tmat3x2<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat3x2<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat3x3<T> make_mat3x3(T const * const ptr)
		{
			detail::tmat3x3<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat3x3<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat3x4<T> make_mat3x4(T const * const ptr)
		{
			detail::tmat3x4<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat3x4<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat4x2<T> make_mat4x2(T const * const ptr)
		{
			detail::tmat4x2<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat4x2<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat4x3<T> make_mat4x3(T const * const ptr)
		{
			detail::tmat4x3<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat4x3<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat4x4<T> make_mat4x4(T const * const ptr)
		{
			detail::tmat4x4<T> Result;
			memcpy(value_ptr(Result), ptr, sizeof(detail::tmat4x4<T>));
			return Result;
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat2x2<T> make_mat2(T const * const ptr)
		{
			return make_mat2x2(Result);
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat3<T> make_mat3(T const * const ptr)
		{
			return make_mat3x3(Result);
		}

		//! Build a matrix from a pointer.
		//! From GLM_GTC_type_ptr extension.
		template<typename T>
		inline detail::tmat4<T> make_mat4(T const * const ptr)
		{
			return make_mat4x4(Result);
		}

		///@}

	}//namespace type_ptr
	}//namespace gtc
}//namespace glm

#include "type_ptr.inl"

namespace glm{using namespace gtc::type_ptr;}

#endif//glm_gtx_type_ptr

<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "browser/ui/file_dialog.h"

#include <atlbase.h>
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>

#include "base/file_util.h"
#include "base/i18n/case_conversion.h"
#include "base/string_util.h"
#include "base/strings/string_split.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "browser/native_window.h"
#include "third_party/wtl/include/atlapp.h"
#include "third_party/wtl/include/atldlgs.h"

namespace file_dialog {

namespace {

// Distinguish directories from regular files.
bool IsDirectory(const base::FilePath& path) {
  base::PlatformFileInfo file_info;
  return file_util::GetFileInfo(path, &file_info) ?
      file_info.is_directory : path.EndsWithSeparator();
}

// Get the file type description from the registry. This will be "Text Document"
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
// have an entry for the file type, we return false, true if the description was
// found. 'file_ext' must be in form ".txt".
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
                                                std::wstring* reg_description) {
  DCHECK(reg_description);
  base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
  std::wstring reg_app;
  if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
    base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
    if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
      return true;
  }
  return false;
}

// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
// extensions (internally separated by semicolons), |ext_desc| as the text
// descriptions of the |file_ext| types (optional), and (optionally) the default
// 'All Files' view. The purpose of the filter is to show only files of a
// particular type in a Windows Save/Open dialog box. The resulting filter is
// returned. The filters created here are:
//   1. only files that have 'file_ext' as their extension
//   2. all files (only added if 'include_all_files' is true)
// Example:
//   file_ext: { "*.txt", "*.htm;*.html" }
//   ext_desc: { "Text Document" }
//   returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
//             "All Files\0*.*\0\0" (in one big string)
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
void FormatFilterForExtensions(
    std::vector<std::wstring>* file_ext,
    std::vector<std::wstring>* ext_desc,
    bool include_all_files,
    std::vector<COMDLG_FILTERSPEC>* file_types) {
  DCHECK(file_ext->size() >= ext_desc->size());

  if (file_ext->empty())
    include_all_files = true;

  for (size_t i = 0; i < file_ext->size(); ++i) {
    std::wstring ext = (*file_ext)[i];
    std::wstring desc;
    if (i < ext_desc->size())
      desc = (*ext_desc)[i];

    if (ext.empty()) {
      // Force something reasonable to appear in the dialog box if there is no
      // extension provided.
      include_all_files = true;
      continue;
    }

    if (desc.empty()) {
      DCHECK(ext.find(L'.') != std::wstring::npos);
      std::wstring first_extension = ext.substr(ext.find(L'.'));
      size_t first_separator_index = first_extension.find(L';');
      if (first_separator_index != std::wstring::npos)
        first_extension = first_extension.substr(0, first_separator_index);

      // Find the extension name without the preceeding '.' character.
      std::wstring ext_name = first_extension;
      size_t ext_index = ext_name.find_first_not_of(L'.');
      if (ext_index != std::wstring::npos)
        ext_name = ext_name.substr(ext_index);

      if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
        // The extension doesn't exist in the registry. Create a description
        // based on the unknown extension type (i.e. if the extension is .qqq,
        // the we create a description "QQQ File (.qqq)").
        include_all_files = true;
        // TODO(zcbenz): should be localized.
        desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
      }
      desc += L" (*." + ext_name + L")";

      // Store the description.
      ext_desc->push_back(desc);
    }

    COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
    file_types->push_back(spec);
  }

  if (include_all_files) {
    // TODO(zcbenz): Should be localized.
    ext_desc->push_back(L"All Files (*.*)");
    file_ext->push_back(L"*.*");

    COMDLG_FILTERSPEC spec = {
      (*ext_desc)[ext_desc->size() - 1].c_str(),
      (*file_ext)[file_ext->size() - 1].c_str(),
    };
    file_types->push_back(spec);
  }
}

// Generic class to delegate common open/save dialog's behaviours, users need to
// call interface methods via GetPtr().
template <typename T>
class FileDialog {
 public:
  FileDialog(const base::FilePath& default_path,
             const std::string title,
             int options,
             const std::vector<std::wstring>& file_ext,
             const std::vector<std::wstring>& desc_ext)
      : file_ext_(file_ext),
        desc_ext_(desc_ext) {
    std::vector<COMDLG_FILTERSPEC> filters;
    FormatFilterForExtensions(&file_ext_, &desc_ext_, true, &filters);

    std::wstring file_part;
    if (!IsDirectory(default_path))
      file_part = default_path.BaseName().value();

    dialog_.reset(new T(
        file_part.c_str(),
        options,
        NULL,
        filters.data(),
        filters.size()));

    if (!title.empty())
      GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());

    SetDefaultFolder(default_path);
  }

  bool Show(atom::NativeWindow* window) {
    return dialog_->DoModal(window->GetNativeWindow()) == IDOK;
  }

  T* GetDialog() { return dialog_.get(); }

  IFileDialog* GetPtr() const { return dialog_->GetPtr(); }

  const std::vector<std::wstring> file_ext() const { return file_ext_; }

 private:
  // Set up the initial directory for the dialog.
  void SetDefaultFolder(const base::FilePath file_path) {
    std::wstring directory = IsDirectory(file_path) ?
        file_path.value() :
        file_path.DirName().value();

    ATL::CComPtr<IShellItem> folder_item;
    HRESULT hr = SHCreateItemFromParsingName(directory.c_str(),
                                             NULL,
                                             IID_PPV_ARGS(&folder_item));
    if (SUCCEEDED(hr))
      GetPtr()->SetDefaultFolder(folder_item);
  }

  scoped_ptr<T> dialog_;

  std::vector<std::wstring> file_ext_;
  std::vector<std::wstring> desc_ext_;
  std::vector<COMDLG_FILTERSPEC> filters_;

  DISALLOW_COPY_AND_ASSIGN(FileDialog);
};

}  // namespace

bool ShowOpenDialog(const std::string& title,
                    const base::FilePath& default_path,
                    int properties,
                    std::vector<base::FilePath>* paths) {
  return false;
}

bool ShowSaveDialog(atom::NativeWindow* window,
                    const std::string& title,
                    const base::FilePath& default_path,
                    base::FilePath* path) {
  // TODO(zcbenz): Accept custom filters from caller.
  std::vector<std::wstring> file_ext;
  std::wstring extension = default_path.Extension();
  if (!extension.empty())
    file_ext.push_back(extension.insert(0, L"*"));

  FileDialog<CShellFileSaveDialog> save_dialog(
      default_path,
      title,
      FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
      file_ext,
      std::vector<std::wstring>());
  if (!save_dialog.Show(window))
    return false;

  wchar_t file_name[MAX_PATH];
  HRESULT hr = save_dialog.GetDialog()->GetFilePath(file_name, MAX_PATH);
  if (FAILED(hr))
    return false;

  // Append extension according to selected filter.
  UINT filter_index = 1;
  save_dialog.GetPtr()->GetFileTypeIndex(&filter_index);
  std::wstring selected_filter = save_dialog.file_ext()[filter_index - 1];
  if (selected_filter != L"*.*") {
    std::wstring result = file_name;
    if (!EndsWith(result, selected_filter.substr(1), false)) {
      if (result[result.length() - 1] != L'.')
        result.push_back(L'.');
      result.append(selected_filter.substr(2));
      *path = base::FilePath(result);
      return true;
    }
  }

  *path = base::FilePath(file_name);
  return true;
}

}  // namespace file_dialog
<commit_msg>win: Implement ShowOpenDialog.<commit_after>// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "browser/ui/file_dialog.h"

#include <atlbase.h>
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>

#include "base/file_util.h"
#include "base/i18n/case_conversion.h"
#include "base/string_util.h"
#include "base/strings/string_split.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "browser/native_window.h"
#include "third_party/wtl/include/atlapp.h"
#include "third_party/wtl/include/atldlgs.h"

namespace file_dialog {

namespace {

// Distinguish directories from regular files.
bool IsDirectory(const base::FilePath& path) {
  base::PlatformFileInfo file_info;
  return file_util::GetFileInfo(path, &file_info) ?
      file_info.is_directory : path.EndsWithSeparator();
}

// Get the file type description from the registry. This will be "Text Document"
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
// have an entry for the file type, we return false, true if the description was
// found. 'file_ext' must be in form ".txt".
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
                                                std::wstring* reg_description) {
  DCHECK(reg_description);
  base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
  std::wstring reg_app;
  if (reg_ext.ReadValue(NULL, &reg_app) == ERROR_SUCCESS && !reg_app.empty()) {
    base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
    if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
      return true;
  }
  return false;
}

// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
// extensions (internally separated by semicolons), |ext_desc| as the text
// descriptions of the |file_ext| types (optional), and (optionally) the default
// 'All Files' view. The purpose of the filter is to show only files of a
// particular type in a Windows Save/Open dialog box. The resulting filter is
// returned. The filters created here are:
//   1. only files that have 'file_ext' as their extension
//   2. all files (only added if 'include_all_files' is true)
// Example:
//   file_ext: { "*.txt", "*.htm;*.html" }
//   ext_desc: { "Text Document" }
//   returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
//             "All Files\0*.*\0\0" (in one big string)
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
void FormatFilterForExtensions(
    std::vector<std::wstring>* file_ext,
    std::vector<std::wstring>* ext_desc,
    bool include_all_files,
    std::vector<COMDLG_FILTERSPEC>* file_types) {
  DCHECK(file_ext->size() >= ext_desc->size());

  if (file_ext->empty())
    include_all_files = true;

  for (size_t i = 0; i < file_ext->size(); ++i) {
    std::wstring ext = (*file_ext)[i];
    std::wstring desc;
    if (i < ext_desc->size())
      desc = (*ext_desc)[i];

    if (ext.empty()) {
      // Force something reasonable to appear in the dialog box if there is no
      // extension provided.
      include_all_files = true;
      continue;
    }

    if (desc.empty()) {
      DCHECK(ext.find(L'.') != std::wstring::npos);
      std::wstring first_extension = ext.substr(ext.find(L'.'));
      size_t first_separator_index = first_extension.find(L';');
      if (first_separator_index != std::wstring::npos)
        first_extension = first_extension.substr(0, first_separator_index);

      // Find the extension name without the preceeding '.' character.
      std::wstring ext_name = first_extension;
      size_t ext_index = ext_name.find_first_not_of(L'.');
      if (ext_index != std::wstring::npos)
        ext_name = ext_name.substr(ext_index);

      if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
        // The extension doesn't exist in the registry. Create a description
        // based on the unknown extension type (i.e. if the extension is .qqq,
        // the we create a description "QQQ File (.qqq)").
        include_all_files = true;
        // TODO(zcbenz): should be localized.
        desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
      }
      desc += L" (*." + ext_name + L")";

      // Store the description.
      ext_desc->push_back(desc);
    }

    COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
    file_types->push_back(spec);
  }

  if (include_all_files) {
    // TODO(zcbenz): Should be localized.
    ext_desc->push_back(L"All Files (*.*)");
    file_ext->push_back(L"*.*");

    COMDLG_FILTERSPEC spec = {
      (*ext_desc)[ext_desc->size() - 1].c_str(),
      (*file_ext)[file_ext->size() - 1].c_str(),
    };
    file_types->push_back(spec);
  }
}

// Generic class to delegate common open/save dialog's behaviours, users need to
// call interface methods via GetPtr().
template <typename T>
class FileDialog {
 public:
  FileDialog(const base::FilePath& default_path,
             const std::string title,
             int options,
             const std::vector<std::wstring>& file_ext,
             const std::vector<std::wstring>& desc_ext)
      : file_ext_(file_ext),
        desc_ext_(desc_ext) {
    std::vector<COMDLG_FILTERSPEC> filters;
    FormatFilterForExtensions(&file_ext_, &desc_ext_, true, &filters);

    std::wstring file_part;
    if (!IsDirectory(default_path))
      file_part = default_path.BaseName().value();

    dialog_.reset(new T(
        file_part.c_str(),
        options,
        NULL,
        filters.data(),
        filters.size()));

    if (!title.empty())
      GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());

    SetDefaultFolder(default_path);
  }

  bool Show(HWND window) {
    return dialog_->DoModal(window) == IDOK;
  }

  T* GetDialog() { return dialog_.get(); }

  IFileDialog* GetPtr() const { return dialog_->GetPtr(); }

  const std::vector<std::wstring> file_ext() const { return file_ext_; }

 private:
  // Set up the initial directory for the dialog.
  void SetDefaultFolder(const base::FilePath file_path) {
    std::wstring directory = IsDirectory(file_path) ?
        file_path.value() :
        file_path.DirName().value();

    ATL::CComPtr<IShellItem> folder_item;
    HRESULT hr = SHCreateItemFromParsingName(directory.c_str(),
                                             NULL,
                                             IID_PPV_ARGS(&folder_item));
    if (SUCCEEDED(hr))
      GetPtr()->SetDefaultFolder(folder_item);
  }

  scoped_ptr<T> dialog_;

  std::vector<std::wstring> file_ext_;
  std::vector<std::wstring> desc_ext_;
  std::vector<COMDLG_FILTERSPEC> filters_;

  DISALLOW_COPY_AND_ASSIGN(FileDialog);
};

}  // namespace

bool ShowOpenDialog(const std::string& title,
                    const base::FilePath& default_path,
                    int properties,
                    std::vector<base::FilePath>* paths) {
  int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
  if (properties & FILE_DIALOG_OPEN_DIRECTORY)
    options |= FOS_PICKFOLDERS;
  if (properties & FILE_DIALOG_MULTI_SELECTIONS)
    options |= FOS_ALLOWMULTISELECT;

  FileDialog<CShellFileOpenDialog> open_dialog(
      default_path,
      title,
      options,
      std::vector<std::wstring>(),
      std::vector<std::wstring>());
  if (!open_dialog.Show(::GetActiveWindow()))
    return false;

  ATL::CComPtr<IShellItemArray> items;
  HRESULT hr = static_cast<IFileOpenDialog*>(open_dialog.GetPtr())->GetResults(
      &items);
  if (FAILED(hr))
    return false;

  ATL::CComPtr<IShellItem> item;
  DWORD count = 0;
  hr = items->GetCount(&count);
  if (FAILED(hr))
    return false;

  paths->reserve(count);
  for (DWORD i = 0; i < count; ++i) {
    hr = items->GetItemAt(i, &item);
    if (FAILED(hr))
      return false;

    wchar_t file_name[MAX_PATH];
    hr = CShellFileOpenDialog::GetFileNameFromShellItem(
        item, SIGDN_FILESYSPATH, file_name, MAX_PATH);
    if (FAILED(hr))
      return false;

    paths->push_back(base::FilePath(file_name));
  }

  return true;
}

bool ShowSaveDialog(atom::NativeWindow* window,
                    const std::string& title,
                    const base::FilePath& default_path,
                    base::FilePath* path) {
  // TODO(zcbenz): Accept custom filters from caller.
  std::vector<std::wstring> file_ext;
  std::wstring extension = default_path.Extension();
  if (!extension.empty())
    file_ext.push_back(extension.insert(0, L"*"));

  FileDialog<CShellFileSaveDialog> save_dialog(
      default_path,
      title,
      FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
      file_ext,
      std::vector<std::wstring>());
  if (!save_dialog.Show(window->GetNativeWindow()))
    return false;

  wchar_t file_name[MAX_PATH];
  HRESULT hr = save_dialog.GetDialog()->GetFilePath(file_name, MAX_PATH);
  if (FAILED(hr))
    return false;

  // Append extension according to selected filter.
  UINT filter_index = 1;
  save_dialog.GetPtr()->GetFileTypeIndex(&filter_index);
  std::wstring selected_filter = save_dialog.file_ext()[filter_index - 1];
  if (selected_filter != L"*.*") {
    std::wstring result = file_name;
    if (!EndsWith(result, selected_filter.substr(1), false)) {
      if (result[result.length() - 1] != L'.')
        result.push_back(L'.');
      result.append(selected_filter.substr(2));
      *path = base::FilePath(result);
      return true;
    }
  }

  *path = base::FilePath(file_name);
  return true;
}

}  // namespace file_dialog
<|endoftext|>


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

#include "wte/stream.h"

#if !defined(_WIN32)
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#include <cassert>
#include <limits>

#include <event2/util.h>

#include "wte/buffer.h"
#include "wte/event_base.h"
#include "wte/event_handler.h"
#include "wte/porting.h"
#include "xplat-io.h"

namespace wte {

inline bool isConnectRetryable(int e) {
#if !defined(_WIN32)
    return e == EINPROGRESS;
#else
    return e == WSAEWOULDBLOCK || e == WSAEINPROGRESS || e == WSAEINTR;
#endif
}

inline bool isReadRetryable(int e) {
#if !defined(_WIN32)
    return e == EAGAIN || e == EWOULDBLOCK;
#else
    return e == WSAEWOULDBLOCK || e == WSAEINTR;
#endif
}

class StreamImpl final : public Stream {
public:
    // TODO: temporary fd-based constructor for testing
    StreamImpl(EventBase *base, int fd) : handler_(this, fd),
        base_(base), requests_({nullptr, nullptr}), readCallback_(nullptr),
        connectCallback_(nullptr) { }

    explicit StreamImpl(EventBase *base) : handler_(this, -1),
        base_(base), requests_({nullptr, nullptr}), readCallback_(nullptr),
        connectCallback_(nullptr) { }

    ~StreamImpl();

    void write(const char *buf, size_t size, WriteCallback *cb) override;
    void write(Buffer *buf, WriteCallback *cb) override;
    void startRead(ReadCallback *cb) override;
    void stopRead() override;
    void close() override;
    void connect(std::string const& ip_addr, int16_t port, ConnectCallback *cb)
        override;
private:
    void writeHelper();
    void readHelper();
    void connectHelper();

    class SockHandler final : public EventHandler {
    public:
        SockHandler(StreamImpl *stream, int fd)
            : EventHandler(fd), stream_(stream) { }
        void ready(What what) NOEXCEPT override;
    private:
        StreamImpl *stream_;
    };

    // State about a write request (buffer, callback)
    class WriteRequest {
    public:
        WriteRequest(const char *buffer, size_t size, WriteCallback *cb);
        WriteRequest(Buffer *buf, WriteCallback *cb);
        ~WriteRequest();
        Buffer buffer_;
        WriteCallback *callback_;
        WriteRequest *next_;
    };

    SockHandler handler_;
    EventBase *base_;
    struct Requests {
        WriteRequest *head;
        WriteRequest *tail;

        void append(WriteRequest *req) {
            if (!head) {
                assert(!tail);
                head = req;
                tail = req;
            } else {
                tail->next_ = req;
            }
        }

        WriteRequest* consumeFront() {
            if (!head) {
                return nullptr;
            }
            WriteRequest *tmp = head;
            head = head->next_;
            if (!head) {
                tail = nullptr;
            }
            delete tmp;
            return head;
        }
    } requests_;
    ReadCallback *readCallback_;
    ConnectCallback *connectCallback_;
    Buffer readBuffer_;
};

void StreamImpl::SockHandler::ready(What event) NOEXCEPT {
    if (isWrite(event)) {
        if (stream_->connectCallback_) {
            stream_->connectHelper();
        }
        stream_->writeHelper();
    }

   if (isRead(event)) {
       stream_->readHelper();
   }
}

StreamImpl::WriteRequest::WriteRequest(const char *buffer, size_t size,
        WriteCallback *cb) : callback_(cb), next_(nullptr) {
    buffer_.append(buffer, size);
}

StreamImpl::WriteRequest::WriteRequest(Buffer *buffer, WriteCallback *cb)
        : callback_(cb), next_(nullptr) {
    buffer_.append(buffer);
}

StreamImpl::WriteRequest::~WriteRequest() { }

void StreamImpl::startRead(Stream::ReadCallback *cb) {
    if (readCallback_ == cb) {
        return;
    }
    readCallback_ = cb;
    base_->registerHandler(&handler_, ensureRead(handler_.watched()));
}

void StreamImpl::stopRead() {
    if (!readCallback_) {
        return;
    }

    readCallback_ = nullptr;

    What events = handler_.watched();
    if (!isRead(handler_.watched())) {
        return;
    } else if (isWrite(handler_.watched())) {
        assert(events == What::READ_WRITE);
        base_->registerHandler(&handler_, What::WRITE);
    }
}

void StreamImpl::write(const char *buf, size_t size, WriteCallback *cb) {
    // TODO: try writing immediately, saving a loop iteration if the socket
    // can handle the entire write w/o blocking
    WriteRequest *req = new WriteRequest(buf, size, cb);
    requests_.append(req);
    base_->registerHandler(&handler_, ensureWrite(handler_.watched()));
}

void StreamImpl::write(Buffer *buf, WriteCallback *cb) {
    WriteRequest *req = new WriteRequest(buf, cb);
    requests_.append(req);
    base_->registerHandler(&handler_, ensureWrite(handler_.watched()));
}

void StreamImpl::close() {
    if (readCallback_) {
        readCallback_->eof();
    }
    if (connectCallback_) {
        connectCallback_->error(std::runtime_error("Closed before connect"));
    }
    if (handler_.registered()) {
        handler_.unregister();
    }

    if (handler_.fd() != -1) {
        xclose(handler_.fd());
    }
}

void StreamImpl::connect(std::string const& ip, int16_t port,
        ConnectCallback *cb) {
    assert(handler_.fd() == -1);
    assert(connectCallback_ == nullptr);

    const char *error = nullptr;
    int fd = -1;

    for (;;) {
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (-1 == fd) {
            error = "Failed to allocate socket";
            break;
        }

        int rc = evutil_make_socket_nonblocking(fd);
        if (-1 == rc) {
            error = "Failed to set socket non-blocking";
            break;
        }

        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        rc = inet_pton(AF_INET, ip.c_str(), &saddr.sin_addr);
        if (1 != rc) {
            error = "Failed to convert address";
            break;
        }

        saddr.sin_port = htons(port);
        socklen_t len = sizeof(saddr);
        rc = ::connect(fd, reinterpret_cast<struct sockaddr*>(&saddr), len);
        if (rc == -1) {
            if (isConnectRetryable(evutil_socket_geterror(fd))) {
                // Expected; queue up the callback
                handler_.setFd(fd);
                connectCallback_ = cb;
                base_->registerHandler(&handler_, ensureWrite(
                    handler_.watched()));
                return;
            } else {
                error = "Connect failed";
                break;
            }
        }

        // Connect succeeded immediately
        handler_.setFd(fd);
        cb->complete();

        return;
    }

    if (fd != -1) {
        xclose(fd);
    }

    cb->error(std::runtime_error(error));
}

StreamImpl::~StreamImpl() {
    handler_.unregister();
    WriteRequest *r;
    // Delete all outstanding write requests
    while ((r = requests_.consumeFront()) != nullptr) { }
}

void StreamImpl::readHelper() {
    char buf[4096];

    // TODO: consider not reading indefinitely
    for (;;) {
        int nread = xread(handler_.fd(), buf, sizeof(buf));
        if (nread < 0) {
            if (isReadRetryable(evutil_socket_geterror(handler_.fd()))) {
                break;
            }
            // TODO: better errors
            if (readCallback_) {
                readCallback_->error(std::runtime_error("Read failed"));
            }
            break;
        } else if (nread == 0) {
            if (readCallback_) {
                readCallback_->eof();
            }
            break;
        }

        // TODO: a reserve + get readable iovec + readv will be more efficient
        // than a read + append.
        readBuffer_.append(buf, nread);

        if (readCallback_) {
            readCallback_->available(&readBuffer_);
        }
        if (nread < sizeof(buf)) {
            break;
        }
    }
}

void StreamImpl::connectHelper() {
    assert(connectCallback_);

    const char *error = nullptr;

    for (;;) {
        // Check connection status
        int err = 0;
        socklen_t len = sizeof(error);
#if defined(_WIN32)
        int rc = getsockopt(handler_.fd(), SOL_SOCKET, SO_ERROR,
            (char *) &err, &len);
#else
        int rc = getsockopt(handler_.fd(), SOL_SOCKET, SO_ERROR, &err, &len);
#endif
        if (-1 == rc) {
            error = "Failed to query connection status";
            break;
        }

        if (error != 0) {
            error = "Connection failed";
            break;
        }

        // Good to go
        auto *cb = connectCallback_;
        connectCallback_ = nullptr;
        cb->complete();
        return;
    }

    auto *cb = connectCallback_;
    connectCallback_ = nullptr;
    cb->error(std::runtime_error(error));
}

void StreamImpl::writeHelper() {
    WriteRequest *req = requests_.head;
    std::vector<Extent> extents;
    bool blocked = false;
    bool failed = false;
    while (req) {
        extents.clear();
        // TODO: better limit
        req->buffer_.peek(std::numeric_limits<size_t>::max(), &extents);
        assert(!extents.empty());

        // TODO: writev
        size_t total_written = 0;
        for (auto& extent : extents) {
            int written = xwrite(handler_.fd(), extent.data, extent.size);
            if (written >= 0) {
                total_written += written;
                if (written < extent.size) {
                    blocked = true;
                }
            } else {
                failed = true;
                break;
            }
        }

        req->buffer_.drain(total_written);

        if (blocked || failed) {
            break;
        }

        WriteCallback *cb = req->callback_;
        // Must not touch req after this call
        WriteRequest *next = requests_.consumeFront();
        if (!next) {
            // Uninstall the write handler before invoking the callback
            // for this final request; callbacks that know that they are
            // last invocation may legitimately do destructive things like
            // freeing this stream.
            base_->registerHandler(&handler_, removeWrite(handler_.watched()));
        }

        if (cb) {
            cb->complete(this);
        }

        req = next;
    }

    if (failed && req->callback_) {
        // TODO: better errors
        req->callback_->error(std::runtime_error("Write failed"));
    }
}

void Stream::Deleter::operator()(Stream *stream) {
    delete stream;
}

std::unique_ptr<Stream, Stream::Deleter> wrapFd(EventBase *base, int fd) {
    return std::unique_ptr<Stream, Stream::Deleter>(
         new StreamImpl(base, fd), Stream::Deleter());
}

std::unique_ptr<Stream, Stream::Deleter> Stream::create(EventBase *base) {
    return std::unique_ptr<Stream, Stream::Deleter>(
         new StreamImpl(base), Stream::Deleter());
}

} // wte namespace
<commit_msg>Include errno.h for OS X<commit_after>/*
 * Copyright (©) 2015 Nate Rosenblum
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "wte/stream.h"

#include <errno.h>

#if !defined(_WIN32)
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#else
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#include <cassert>
#include <limits>

#include <event2/util.h>

#include "wte/buffer.h"
#include "wte/event_base.h"
#include "wte/event_handler.h"
#include "wte/porting.h"
#include "xplat-io.h"

namespace wte {

inline bool isConnectRetryable(int e) {
#if !defined(_WIN32)
    return e == EINPROGRESS;
#else
    return e == WSAEWOULDBLOCK || e == WSAEINPROGRESS || e == WSAEINTR;
#endif
}

inline bool isReadRetryable(int e) {
#if !defined(_WIN32)
    return e == EAGAIN || e == EWOULDBLOCK;
#else
    return e == WSAEWOULDBLOCK || e == WSAEINTR;
#endif
}

class StreamImpl final : public Stream {
public:
    // TODO: temporary fd-based constructor for testing
    StreamImpl(EventBase *base, int fd) : handler_(this, fd),
        base_(base), requests_({nullptr, nullptr}), readCallback_(nullptr),
        connectCallback_(nullptr) { }

    explicit StreamImpl(EventBase *base) : handler_(this, -1),
        base_(base), requests_({nullptr, nullptr}), readCallback_(nullptr),
        connectCallback_(nullptr) { }

    ~StreamImpl();

    void write(const char *buf, size_t size, WriteCallback *cb) override;
    void write(Buffer *buf, WriteCallback *cb) override;
    void startRead(ReadCallback *cb) override;
    void stopRead() override;
    void close() override;
    void connect(std::string const& ip_addr, int16_t port, ConnectCallback *cb)
        override;
private:
    void writeHelper();
    void readHelper();
    void connectHelper();

    class SockHandler final : public EventHandler {
    public:
        SockHandler(StreamImpl *stream, int fd)
            : EventHandler(fd), stream_(stream) { }
        void ready(What what) NOEXCEPT override;
    private:
        StreamImpl *stream_;
    };

    // State about a write request (buffer, callback)
    class WriteRequest {
    public:
        WriteRequest(const char *buffer, size_t size, WriteCallback *cb);
        WriteRequest(Buffer *buf, WriteCallback *cb);
        ~WriteRequest();
        Buffer buffer_;
        WriteCallback *callback_;
        WriteRequest *next_;
    };

    SockHandler handler_;
    EventBase *base_;
    struct Requests {
        WriteRequest *head;
        WriteRequest *tail;

        void append(WriteRequest *req) {
            if (!head) {
                assert(!tail);
                head = req;
                tail = req;
            } else {
                tail->next_ = req;
            }
        }

        WriteRequest* consumeFront() {
            if (!head) {
                return nullptr;
            }
            WriteRequest *tmp = head;
            head = head->next_;
            if (!head) {
                tail = nullptr;
            }
            delete tmp;
            return head;
        }
    } requests_;
    ReadCallback *readCallback_;
    ConnectCallback *connectCallback_;
    Buffer readBuffer_;
};

void StreamImpl::SockHandler::ready(What event) NOEXCEPT {
    if (isWrite(event)) {
        if (stream_->connectCallback_) {
            stream_->connectHelper();
        }
        stream_->writeHelper();
    }

   if (isRead(event)) {
       stream_->readHelper();
   }
}

StreamImpl::WriteRequest::WriteRequest(const char *buffer, size_t size,
        WriteCallback *cb) : callback_(cb), next_(nullptr) {
    buffer_.append(buffer, size);
}

StreamImpl::WriteRequest::WriteRequest(Buffer *buffer, WriteCallback *cb)
        : callback_(cb), next_(nullptr) {
    buffer_.append(buffer);
}

StreamImpl::WriteRequest::~WriteRequest() { }

void StreamImpl::startRead(Stream::ReadCallback *cb) {
    if (readCallback_ == cb) {
        return;
    }
    readCallback_ = cb;
    base_->registerHandler(&handler_, ensureRead(handler_.watched()));
}

void StreamImpl::stopRead() {
    if (!readCallback_) {
        return;
    }

    readCallback_ = nullptr;

    What events = handler_.watched();
    if (!isRead(handler_.watched())) {
        return;
    } else if (isWrite(handler_.watched())) {
        assert(events == What::READ_WRITE);
        base_->registerHandler(&handler_, What::WRITE);
    }
}

void StreamImpl::write(const char *buf, size_t size, WriteCallback *cb) {
    // TODO: try writing immediately, saving a loop iteration if the socket
    // can handle the entire write w/o blocking
    WriteRequest *req = new WriteRequest(buf, size, cb);
    requests_.append(req);
    base_->registerHandler(&handler_, ensureWrite(handler_.watched()));
}

void StreamImpl::write(Buffer *buf, WriteCallback *cb) {
    WriteRequest *req = new WriteRequest(buf, cb);
    requests_.append(req);
    base_->registerHandler(&handler_, ensureWrite(handler_.watched()));
}

void StreamImpl::close() {
    if (readCallback_) {
        readCallback_->eof();
    }
    if (connectCallback_) {
        connectCallback_->error(std::runtime_error("Closed before connect"));
    }
    if (handler_.registered()) {
        handler_.unregister();
    }

    if (handler_.fd() != -1) {
        xclose(handler_.fd());
    }
}

void StreamImpl::connect(std::string const& ip, int16_t port,
        ConnectCallback *cb) {
    assert(handler_.fd() == -1);
    assert(connectCallback_ == nullptr);

    const char *error = nullptr;
    int fd = -1;

    for (;;) {
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (-1 == fd) {
            error = "Failed to allocate socket";
            break;
        }

        int rc = evutil_make_socket_nonblocking(fd);
        if (-1 == rc) {
            error = "Failed to set socket non-blocking";
            break;
        }

        struct sockaddr_in saddr;
        saddr.sin_family = AF_INET;
        rc = inet_pton(AF_INET, ip.c_str(), &saddr.sin_addr);
        if (1 != rc) {
            error = "Failed to convert address";
            break;
        }

        saddr.sin_port = htons(port);
        socklen_t len = sizeof(saddr);
        rc = ::connect(fd, reinterpret_cast<struct sockaddr*>(&saddr), len);
        if (rc == -1) {
            if (isConnectRetryable(evutil_socket_geterror(fd))) {
                // Expected; queue up the callback
                handler_.setFd(fd);
                connectCallback_ = cb;
                base_->registerHandler(&handler_, ensureWrite(
                    handler_.watched()));
                return;
            } else {
                error = "Connect failed";
                break;
            }
        }

        // Connect succeeded immediately
        handler_.setFd(fd);
        cb->complete();

        return;
    }

    if (fd != -1) {
        xclose(fd);
    }

    cb->error(std::runtime_error(error));
}

StreamImpl::~StreamImpl() {
    handler_.unregister();
    WriteRequest *r;
    // Delete all outstanding write requests
    while ((r = requests_.consumeFront()) != nullptr) { }
}

void StreamImpl::readHelper() {
    char buf[4096];

    // TODO: consider not reading indefinitely
    for (;;) {
        int nread = xread(handler_.fd(), buf, sizeof(buf));
        if (nread < 0) {
            if (isReadRetryable(evutil_socket_geterror(handler_.fd()))) {
                break;
            }
            // TODO: better errors
            if (readCallback_) {
                readCallback_->error(std::runtime_error("Read failed"));
            }
            break;
        } else if (nread == 0) {
            if (readCallback_) {
                readCallback_->eof();
            }
            break;
        }

        // TODO: a reserve + get readable iovec + readv will be more efficient
        // than a read + append.
        readBuffer_.append(buf, nread);

        if (readCallback_) {
            readCallback_->available(&readBuffer_);
        }
        if (nread < sizeof(buf)) {
            break;
        }
    }
}

void StreamImpl::connectHelper() {
    assert(connectCallback_);

    const char *error = nullptr;

    for (;;) {
        // Check connection status
        int err = 0;
        socklen_t len = sizeof(error);
#if defined(_WIN32)
        int rc = getsockopt(handler_.fd(), SOL_SOCKET, SO_ERROR,
            (char *) &err, &len);
#else
        int rc = getsockopt(handler_.fd(), SOL_SOCKET, SO_ERROR, &err, &len);
#endif
        if (-1 == rc) {
            error = "Failed to query connection status";
            break;
        }

        if (error != 0) {
            error = "Connection failed";
            break;
        }

        // Good to go
        auto *cb = connectCallback_;
        connectCallback_ = nullptr;
        cb->complete();
        return;
    }

    auto *cb = connectCallback_;
    connectCallback_ = nullptr;
    cb->error(std::runtime_error(error));
}

void StreamImpl::writeHelper() {
    WriteRequest *req = requests_.head;
    std::vector<Extent> extents;
    bool blocked = false;
    bool failed = false;
    while (req) {
        extents.clear();
        // TODO: better limit
        req->buffer_.peek(std::numeric_limits<size_t>::max(), &extents);
        assert(!extents.empty());

        // TODO: writev
        size_t total_written = 0;
        for (auto& extent : extents) {
            int written = xwrite(handler_.fd(), extent.data, extent.size);
            if (written >= 0) {
                total_written += written;
                if (written < extent.size) {
                    blocked = true;
                }
            } else {
                failed = true;
                break;
            }
        }

        req->buffer_.drain(total_written);

        if (blocked || failed) {
            break;
        }

        WriteCallback *cb = req->callback_;
        // Must not touch req after this call
        WriteRequest *next = requests_.consumeFront();
        if (!next) {
            // Uninstall the write handler before invoking the callback
            // for this final request; callbacks that know that they are
            // last invocation may legitimately do destructive things like
            // freeing this stream.
            base_->registerHandler(&handler_, removeWrite(handler_.watched()));
        }

        if (cb) {
            cb->complete(this);
        }

        req = next;
    }

    if (failed && req->callback_) {
        // TODO: better errors
        req->callback_->error(std::runtime_error("Write failed"));
    }
}

void Stream::Deleter::operator()(Stream *stream) {
    delete stream;
}

std::unique_ptr<Stream, Stream::Deleter> wrapFd(EventBase *base, int fd) {
    return std::unique_ptr<Stream, Stream::Deleter>(
         new StreamImpl(base, fd), Stream::Deleter());
}

std::unique_ptr<Stream, Stream::Deleter> Stream::create(EventBase *base) {
    return std::unique_ptr<Stream, Stream::Deleter>(
         new StreamImpl(base), Stream::Deleter());
}

} // wte namespace
<|endoftext|>


<commit_before>//===- DeadStoreElimination.cpp - Dead Store Elimination ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a trivial dead store elimination that only considers
// basic-block local redundant stores.
//
// FIXME: This should eventually be extended to be a post-dominator tree
// traversal.  Doing so would be pretty trivial.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "Support/SetVector.h"
#include "Support/Statistic.h"
using namespace llvm;

namespace {
  Statistic<> NumStores("dse", "Number of stores deleted");
  Statistic<> NumOther ("dse", "Number of other instrs removed");

  struct DSE : public FunctionPass {

    virtual bool runOnFunction(Function &F) {
      bool Changed = false;
      for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
        Changed |= runOnBasicBlock(*I);
      return Changed;
    }

    bool runOnBasicBlock(BasicBlock &BB);

    void DeleteDeadInstructionChains(Instruction *I,
                                     SetVector<Instruction*> &DeadInsts);

    // getAnalysisUsage - We require post dominance frontiers (aka Control
    // Dependence Graph)
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<TargetData>();
      AU.addRequired<AliasAnalysis>();
      AU.addPreserved<AliasAnalysis>();
    }
  };
  RegisterOpt<DSE> X("dse", "Dead Store Elimination");
}

Pass *llvm::createDeadStoreEliminationPass() { return new DSE(); }

bool DSE::runOnBasicBlock(BasicBlock &BB) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  AliasSetTracker KillLocs(AA);

  // If this block ends in a return, unwind, and eventually tailcall/barrier,
  // then all allocas are dead at its end.
  if (BB.getTerminator()->getNumSuccessors() == 0) {

  }

  // PotentiallyDeadInsts - Deleting dead stores from the program can make other
  // instructions die if they were only used as operands to stores.  Keep track
  // of the operands to stores so that we can try deleting them at the end of
  // the traversal.
  SetVector<Instruction*> PotentiallyDeadInsts;

  bool MadeChange = false;
  for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ) {
    Instruction *I = --BBI;   // Keep moving iterator backwards

    // If this is a free instruction, it makes the free'd location dead!
    if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      // Free instructions make any stores to the free'd location dead.
      KillLocs.add(FI);
      continue;
    }

    if (!isa<StoreInst>(I) || cast<StoreInst>(I)->isVolatile()) {
      // If this is a non-store instruction, it makes everything referenced no
      // longer killed.  Remove anything aliased from the alias set tracker.
      KillLocs.remove(I);
      continue;
    }

    // If this is a non-volatile store instruction, and if it is already in
    // the stored location is already in the tracker, then this is a dead
    // store.  We can just delete it here, but while we're at it, we also
    // delete any trivially dead expression chains.
    unsigned ValSize = TD.getTypeSize(I->getOperand(0)->getType());
    Value *Ptr = I->getOperand(1);

    if (AliasSet *AS = KillLocs.getAliasSetForPointerIfExists(Ptr, ValSize))
      for (AliasSet::iterator ASI = AS->begin(), E = AS->end(); ASI != E; ++ASI)
        if (AA.alias(ASI.getPointer(), ASI.getSize(), Ptr, ValSize)
               == AliasAnalysis::MustAlias) {
          // If we found a must alias in the killed set, then this store really
          // is dead.  Remember that the various operands of the store now have
          // fewer users.  At the end we will see if we can delete any values
          // that are dead as part of the store becoming dead.
          if (Instruction *Op = dyn_cast<Instruction>(I->getOperand(0)))
            PotentiallyDeadInsts.insert(Op);
          if (Instruction *Op = dyn_cast<Instruction>(Ptr))
            PotentiallyDeadInsts.insert(Op);

          // Delete it now.
          ++BBI;                        // Don't invalidate iterator.
          BB.getInstList().erase(I);    // Nuke the store!
          ++NumStores;
          MadeChange = true;
          goto BigContinue;
        }

    // Otherwise, this is a non-dead store just add it to the set of dead
    // locations.
    KillLocs.add(cast<StoreInst>(I));
  BigContinue:;
  }

  while (!PotentiallyDeadInsts.empty()) {
    Instruction *I = PotentiallyDeadInsts.back();
    PotentiallyDeadInsts.pop_back();
    DeleteDeadInstructionChains(I, PotentiallyDeadInsts);
  }
  return MadeChange;
}

void DSE::DeleteDeadInstructionChains(Instruction *I,
                                      SetVector<Instruction*> &DeadInsts) {
  // Instruction must be dead.
  if (!I->use_empty() || !isInstructionTriviallyDead(I)) return;

  // Let the alias analysis know that we have nuked a value.
  getAnalysis<AliasAnalysis>().deleteValue(I);

  // See if this made any operands dead.  We do it this way in case the
  // instruction uses the same operand twice.  We don't want to delete a
  // value then reference it.
  while (unsigned NumOps = I->getNumOperands()) {
    Instruction *Op = dyn_cast<Instruction>(I->getOperand(NumOps-1));
    I->op_erase(I->op_end()-1);         // Drop from the operand list.

    if (Op) DeadInsts.insert(Op);       // Attempt to nuke it later.
  }

  I->getParent()->getInstList().erase(I);
  ++NumOther;
}
<commit_msg>Implement DeadStoreElim/alloca.llx by observing that allocas are dead at the end of the function (either return or unwind)<commit_after>//===- DeadStoreElimination.cpp - Dead Store Elimination ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a trivial dead store elimination that only considers
// basic-block local redundant stores.
//
// FIXME: This should eventually be extended to be a post-dominator tree
// traversal.  Doing so would be pretty trivial.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "Support/SetVector.h"
#include "Support/Statistic.h"
using namespace llvm;

namespace {
  Statistic<> NumStores("dse", "Number of stores deleted");
  Statistic<> NumOther ("dse", "Number of other instrs removed");

  struct DSE : public FunctionPass {

    virtual bool runOnFunction(Function &F) {
      bool Changed = false;
      for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
        Changed |= runOnBasicBlock(*I);
      return Changed;
    }

    bool runOnBasicBlock(BasicBlock &BB);

    void DeleteDeadInstructionChains(Instruction *I,
                                     SetVector<Instruction*> &DeadInsts);

    // getAnalysisUsage - We require post dominance frontiers (aka Control
    // Dependence Graph)
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<TargetData>();
      AU.addRequired<AliasAnalysis>();
      AU.addPreserved<AliasAnalysis>();
    }
  };
  RegisterOpt<DSE> X("dse", "Dead Store Elimination");
}

Pass *llvm::createDeadStoreEliminationPass() { return new DSE(); }

bool DSE::runOnBasicBlock(BasicBlock &BB) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  AliasSetTracker KillLocs(AA);

  // If this block ends in a return, unwind, and eventually tailcall/barrier,
  // then all allocas are dead at its end.
  if (BB.getTerminator()->getNumSuccessors() == 0) {
    BasicBlock *Entry = BB.getParent()->begin();
    for (BasicBlock::iterator I = Entry->begin(), E = Entry->end(); I != E; ++I)
      if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
        KillLocs.add(AI, ~0);
  }

  // PotentiallyDeadInsts - Deleting dead stores from the program can make other
  // instructions die if they were only used as operands to stores.  Keep track
  // of the operands to stores so that we can try deleting them at the end of
  // the traversal.
  SetVector<Instruction*> PotentiallyDeadInsts;

  bool MadeChange = false;
  for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ) {
    Instruction *I = --BBI;   // Keep moving iterator backwards

    // If this is a free instruction, it makes the free'd location dead!
    if (FreeInst *FI = dyn_cast<FreeInst>(I)) {
      // Free instructions make any stores to the free'd location dead.
      KillLocs.add(FI);
      continue;
    }

    if (!isa<StoreInst>(I) || cast<StoreInst>(I)->isVolatile()) {
      // If this is a non-store instruction, it makes everything referenced no
      // longer killed.  Remove anything aliased from the alias set tracker.
      KillLocs.remove(I);
      continue;
    }

    // If this is a non-volatile store instruction, and if it is already in
    // the stored location is already in the tracker, then this is a dead
    // store.  We can just delete it here, but while we're at it, we also
    // delete any trivially dead expression chains.
    unsigned ValSize = TD.getTypeSize(I->getOperand(0)->getType());
    Value *Ptr = I->getOperand(1);

    if (AliasSet *AS = KillLocs.getAliasSetForPointerIfExists(Ptr, ValSize))
      for (AliasSet::iterator ASI = AS->begin(), E = AS->end(); ASI != E; ++ASI)
        if (AA.alias(ASI.getPointer(), ASI.getSize(), Ptr, ValSize)
               == AliasAnalysis::MustAlias) {
          // If we found a must alias in the killed set, then this store really
          // is dead.  Remember that the various operands of the store now have
          // fewer users.  At the end we will see if we can delete any values
          // that are dead as part of the store becoming dead.
          if (Instruction *Op = dyn_cast<Instruction>(I->getOperand(0)))
            PotentiallyDeadInsts.insert(Op);
          if (Instruction *Op = dyn_cast<Instruction>(Ptr))
            PotentiallyDeadInsts.insert(Op);

          // Delete it now.
          ++BBI;                        // Don't invalidate iterator.
          BB.getInstList().erase(I);    // Nuke the store!
          ++NumStores;
          MadeChange = true;
          goto BigContinue;
        }

    // Otherwise, this is a non-dead store just add it to the set of dead
    // locations.
    KillLocs.add(cast<StoreInst>(I));
  BigContinue:;
  }

  while (!PotentiallyDeadInsts.empty()) {
    Instruction *I = PotentiallyDeadInsts.back();
    PotentiallyDeadInsts.pop_back();
    DeleteDeadInstructionChains(I, PotentiallyDeadInsts);
  }
  return MadeChange;
}

void DSE::DeleteDeadInstructionChains(Instruction *I,
                                      SetVector<Instruction*> &DeadInsts) {
  // Instruction must be dead.
  if (!I->use_empty() || !isInstructionTriviallyDead(I)) return;

  // Let the alias analysis know that we have nuked a value.
  getAnalysis<AliasAnalysis>().deleteValue(I);

  // See if this made any operands dead.  We do it this way in case the
  // instruction uses the same operand twice.  We don't want to delete a
  // value then reference it.
  while (unsigned NumOps = I->getNumOperands()) {
    Instruction *Op = dyn_cast<Instruction>(I->getOperand(NumOps-1));
    I->op_erase(I->op_end()-1);         // Drop from the operand list.

    if (Op) DeadInsts.insert(Op);       // Attempt to nuke it later.
  }

  I->getParent()->getInstList().erase(I);
  ++NumOther;
}
<|endoftext|>