<commit_before>/*
 * pAlgorithm.cpp
 *
 * Author: Petel__
 * Copyright (c) 2014-2016 HKUST SmartCar Team
 * Refer to LICENSE for details
 */

#include <pSmartCar.h>
#include <libbase/k60/watchdog.h>
#include <pResource.h>

using namespace std;
using namespace libsc;
using namespace libbase::k60;

void pSmartCar::addAllRoutineToLoop(void)
{
	m_loop.addFunctionToLoop(update, 5);
	m_loop.addFunctionToLoop(directionControl, 10);
	m_loop.addFunctionToLoop(speedControl, 100);
	m_loop.addFunctionToLoop(angleControl, 5);
	m_loop.addFunctionToLoop(print, 20);
//	m_loop.addFunctionToLoop(safetyCheck, 200);
}

void pSmartCar::addVariablesToGrapher(void)
{
	m_grapher.setOnChangedListener(pResource::grapherOnChangedListener);
}

//========================================================================================
//=========================				Routine				==============================
//========================================================================================
void pSmartCar::update(void)
{
	pResource::m_instance->updateSensors();
	pResource::m_instance->updateState();
	pResource::m_instance->updateMotors();
	pResource::m_instance->m_magSen[0].updatePair();
}

void pSmartCar::angleControl(void)
{
	pResource::m_instance->updatePid(pResource::m_instance->m_state[StatePos::cur].angle + pResource::m_instance->getSmoothAngleOutput() - ABS(pResource::m_instance->m_state[StatePos::cur].dYaw) * pResource::configTable.kSpinConstant, Type::Angle);

	if (pResource::m_instance->m_motorEnabled && !isInRange2(pResource::m_instance->m_angle.getAngle(), pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
	{
		pResource::m_instance->setMotorsEnabled(false);
		pBuzzer::terminated();
		pResource::m_instance->m_isReadyToRun = true;
	}

	pResource::m_instance->updateSpeed();
}

void pSmartCar::directionControl(void)
{
	float tempResult = -pResource::m_instance->m_magSen[0].updatePair();
	pResource::m_instance->updateSmoothDirectionOutput(pResource::m_instance->m_fuzzyLogic.updatePdController(tempResult));
}

void pSmartCar::speedControl(void)
{
//	pResource::m_instance->smoothedIdealSpeed(2.0f);
	pResource::m_instance->updatePid(pResource::m_instance->m_state[StatePos::cur].dX, Type::Speed);
	pResource::m_instance->updateSmoothAngleOutput(pResource::m_instance->m_pidOutputVal[Type::Speed]);
}

void pSmartCar::print(void)
{
//	pResource::m_instance->onDraw();
	pResource::m_instance->m_grapher.sendWatchData();
}

//========================================================================================
//========================= | | | | | | | | | | | | | | | | ==============================
//========================= v v v v v v v v v v v v v v v v ==============================

void pSmartCar::smoothedIdealSpeed(const float &accelLimit)
{
	m_curSpeed = inRange(0, m_state[cur].dX + inRange(-m_curSpeed, (m_idealSpeed - m_state[cur].dX) * pResource::configTable.kAccelSpeed, accelLimit), m_idealSpeed);
}

void pSmartCar::updateSensors(void)
{
	m_angle.update();
	m_motors[0].update();
	m_motors[1].update();
}

void pSmartCar::updateState(void)
{
	if (m_state[StatePos::prev].timeStamp)
	{
		m_state[StatePos::prev] = m_state[StatePos::cur];
		m_state[StatePos::cur].angle = pResource::m_instance->m_angle.getAngle();
		m_state[StatePos::cur].dAngle = -pResource::m_instance->m_angle.getOmega(1);

		float tempDx = m_encoderLpf.filter((m_motors[0].getEncoderCount() + m_motors[1].getEncoderCount()) * 0.0523137f) / (System::Time() - m_state[StatePos::prev].timeStamp);
		if (++m_ignoreSpeedCounter >= 20 || tempDx < m_state[StatePos::cur].dX * 1.5f)
		{
			m_state[StatePos::cur].dX = tempDx;
			m_ignoreSpeedCounter = 0;
		}

		m_state[StatePos::cur].dYaw = m_angle.getYawOmega();
	}

	m_state[StatePos::prev].timeStamp = System::Time();
}

void pSmartCar::updateSmoothAngleOutput(const float newAngle)
{
	m_smoothIncrement[IncrementType::SpeedIncrement] = (newAngle - m_idealAngleOffset) * 0.05f;
}

float pSmartCar::getSmoothAngleOutput(void)
{
	if (isInRange2(m_state[StatePos::cur].angle + m_smoothIncrement[IncrementType::SpeedIncrement] + m_idealAngleOffset, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
		return (m_idealAngleOffset += m_smoothIncrement[IncrementType::SpeedIncrement]);
	else if (isInRange2(m_state[StatePos::cur].angle, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
		return (m_idealAngleOffset = inRange2(m_state[StatePos::cur].angle + m_smoothIncrement[IncrementType::SpeedIncrement] + m_idealAngleOffset, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange) - pResource::configTable.kIdealAngle);
	else
		return m_idealAngleOffset;
}

void pSmartCar::updateSmoothDirectionOutput(const float newDirection)
{
	m_smoothIncrement[IncrementType::DirectionIncrement] = (newDirection - m_directionOffset) * 0.5f;
}

float pSmartCar::getSmoothDirectionOutput(void)
{
	return (m_directionOffset += m_smoothIncrement[IncrementType::DirectionIncrement]);
}

void pSmartCar::updateMotors(void)
{
	m_motors[0].update();
	m_motors[1].update();
}

void pSmartCar::updateSpeed(void)
{
	float tempDirectionOutput = (m_directionEnabled)? getSmoothDirectionOutput() : 0.0f;
	m_motors[0].setMappedPower(inRange(-9000, m_pidOutputVal[Type::Angle] + tempDirectionOutput, 9000));
	m_motors[1].setMappedPower(inRange(-9000, m_pidOutputVal[Type::Angle] - tempDirectionOutput, 9000));
}

void pSmartCar::onDraw(void)
{
//	m_lcd.setRow(0);
//	m_lcd << m_motors[0].getEncoderCount() << '\t' << m_motors[1].getEncoderCount() << '\t' << endl
//			<< m_motors[0].getPower() << '\t' << m_motors[1].getPower() << '\t' << endl
//			<< m_state[StatePos::cur].dX << '\t' << m_state[StatePos::cur].angle << '\t' << endl
//			<< m_state[StatePos::cur].dYaw << '\t' << m_state[StatePos::cur].dAngle << '\t' << endl;
//			<< m_angle.getAccel(0) << '\t' << m_angle.getAccel(1) << '\t' << m_angle.getAccel(2) << '\t' << endl
//			<< m_angle.getOmega(0) << '\t' << m_angle.getOmega(1) << '\t' << m_angle.getOmega(2) << '\t' << endl
}
<commit_msg>Update speed every 20ms<commit_after>/*
 * pAlgorithm.cpp
 *
 * Author: Petel__
 * Copyright (c) 2014-2016 HKUST SmartCar Team
 * Refer to LICENSE for details
 */

#include <pSmartCar.h>
#include <libbase/k60/watchdog.h>
#include <pResource.h>

using namespace std;
using namespace libsc;
using namespace libbase::k60;

void pSmartCar::addAllRoutineToLoop(void)
{
	m_loop.addFunctionToLoop(update, 5);
	m_loop.addFunctionToLoop(directionControl, 10);
	m_loop.addFunctionToLoop(speedControl, 20);
	m_loop.addFunctionToLoop(angleControl, 5);
	m_loop.addFunctionToLoop(print, 20);
//	m_loop.addFunctionToLoop(safetyCheck, 200);
}

void pSmartCar::addVariablesToGrapher(void)
{
	m_grapher.setOnChangedListener(pResource::grapherOnChangedListener);
}

//========================================================================================
//=========================				Routine				==============================
//========================================================================================
void pSmartCar::update(void)
{
	pResource::m_instance->updateSensors();
	pResource::m_instance->updateState();
	pResource::m_instance->updateMotors();
	pResource::m_instance->m_magSen[0].updatePair();
}

void pSmartCar::angleControl(void)
{
	pResource::m_instance->updatePid(pResource::m_instance->m_state[StatePos::cur].angle + pResource::m_instance->getSmoothAngleOutput() - ABS(pResource::m_instance->m_state[StatePos::cur].dYaw) * pResource::configTable.kSpinConstant, Type::Angle);

	if (pResource::m_instance->m_motorEnabled && !isInRange2(pResource::m_instance->m_angle.getAngle(), pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
	{
		pResource::m_instance->setMotorsEnabled(false);
		pBuzzer::terminated();
		pResource::m_instance->m_isReadyToRun = true;
	}

	pResource::m_instance->updateSpeed();
}

void pSmartCar::directionControl(void)
{
	float tempResult = -pResource::m_instance->m_magSen[0].updatePair();
	pResource::m_instance->updateSmoothDirectionOutput(pResource::m_instance->m_fuzzyLogic.updatePdController(tempResult));
}

void pSmartCar::speedControl(void)
{
//	pResource::m_instance->smoothedIdealSpeed(2.0f);
	pResource::m_instance->updatePid(pResource::m_instance->m_state[StatePos::cur].dX, Type::Speed);
	pResource::m_instance->updateSmoothAngleOutput(pResource::m_instance->m_pidOutputVal[Type::Speed]);
}

void pSmartCar::print(void)
{
//	pResource::m_instance->onDraw();
	pResource::m_instance->m_grapher.sendWatchData();
}

//========================================================================================
//========================= | | | | | | | | | | | | | | | | ==============================
//========================= v v v v v v v v v v v v v v v v ==============================

void pSmartCar::smoothedIdealSpeed(const float &accelLimit)
{
	m_curSpeed = inRange(0, m_state[cur].dX + inRange(-m_curSpeed, (m_idealSpeed - m_state[cur].dX) * pResource::configTable.kAccelSpeed, accelLimit), m_idealSpeed);
}

void pSmartCar::updateSensors(void)
{
	m_angle.update();
	m_motors[0].update();
	m_motors[1].update();
}

void pSmartCar::updateState(void)
{
	if (m_state[StatePos::prev].timeStamp)
	{
		m_state[StatePos::prev] = m_state[StatePos::cur];
		m_state[StatePos::cur].angle = pResource::m_instance->m_angle.getAngle();
		m_state[StatePos::cur].dAngle = -pResource::m_instance->m_angle.getOmega(1);

		float tempDx = m_encoderLpf.filter((m_motors[0].getEncoderCount() + m_motors[1].getEncoderCount()) * 0.0523137f) / (System::Time() - m_state[StatePos::prev].timeStamp);
		if (++m_ignoreSpeedCounter >= 20 || tempDx < m_state[StatePos::cur].dX * 1.5f)
		{
			m_state[StatePos::cur].dX = tempDx;
			m_ignoreSpeedCounter = 0;
		}

		m_state[StatePos::cur].dYaw = m_angle.getYawOmega();
	}

	m_state[StatePos::prev].timeStamp = System::Time();
}

void pSmartCar::updateSmoothAngleOutput(const float newAngle)
{
	m_smoothIncrement[IncrementType::SpeedIncrement] = (newAngle - m_idealAngleOffset) * 0.25f;
}

float pSmartCar::getSmoothAngleOutput(void)
{
	if (isInRange2(m_state[StatePos::cur].angle + m_smoothIncrement[IncrementType::SpeedIncrement] + m_idealAngleOffset, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
		return (m_idealAngleOffset += m_smoothIncrement[IncrementType::SpeedIncrement]);
	else if (isInRange2(m_state[StatePos::cur].angle, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange))
		return (m_idealAngleOffset = inRange2(m_state[StatePos::cur].angle + m_smoothIncrement[IncrementType::SpeedIncrement] + m_idealAngleOffset, pResource::configTable.kIdealAngle, pResource::configTable.kAngleRange) - pResource::configTable.kIdealAngle);
	else
		return m_idealAngleOffset;
}

void pSmartCar::updateSmoothDirectionOutput(const float newDirection)
{
	m_smoothIncrement[IncrementType::DirectionIncrement] = (newDirection - m_directionOffset) * 0.5f;
}

float pSmartCar::getSmoothDirectionOutput(void)
{
	return (m_directionOffset += m_smoothIncrement[IncrementType::DirectionIncrement]);
}

void pSmartCar::updateMotors(void)
{
	m_motors[0].update();
	m_motors[1].update();
}

void pSmartCar::updateSpeed(void)
{
	float tempDirectionOutput = (m_directionEnabled)? getSmoothDirectionOutput() : 0.0f;
	m_motors[0].setMappedPower(inRange(-9000, m_pidOutputVal[Type::Angle] + tempDirectionOutput, 9000));
	m_motors[1].setMappedPower(inRange(-9000, m_pidOutputVal[Type::Angle] - tempDirectionOutput, 9000));
}

void pSmartCar::onDraw(void)
{
//	m_lcd.setRow(0);
//	m_lcd << m_motors[0].getEncoderCount() << '\t' << m_motors[1].getEncoderCount() << '\t' << endl
//			<< m_motors[0].getPower() << '\t' << m_motors[1].getPower() << '\t' << endl
//			<< m_state[StatePos::cur].dX << '\t' << m_state[StatePos::cur].angle << '\t' << endl
//			<< m_state[StatePos::cur].dYaw << '\t' << m_state[StatePos::cur].dAngle << '\t' << endl;
//			<< m_angle.getAccel(0) << '\t' << m_angle.getAccel(1) << '\t' << m_angle.getAccel(2) << '\t' << endl
//			<< m_angle.getOmega(0) << '\t' << m_angle.getOmega(1) << '\t' << m_angle.getOmega(2) << '\t' << endl
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009-2017, Albertas Vyšniauskas
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the software author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Script.h"
#include <sstream>
extern "C"{
#include <lualib.h>
#include <lauxlib.h>
}
#include <iostream>
using namespace std;
namespace lua
{
Script::Script()
{
	m_state = luaL_newstate();
	m_state_owned = true;
	luaL_openlibs(m_state);
}
Script::Script(lua_State *state)
{
	m_state = state;
	m_state_owned = false;
}
Script::~Script()
{
	if (m_state_owned)
		lua_close(m_state);
	m_state = nullptr;
}
Script::operator lua_State*()
{
	return m_state;
}
void Script::setPaths(const std::vector<std::string> &include_paths)
{
	string paths = ";./?.lua;";
	for (vector<string>::const_iterator i = include_paths.begin(); i != include_paths.end(); i++){
		paths += *i;
		paths += "/?.lua;";
	}
	lua_getglobal(m_state, "package");
	lua_pushstring(m_state, "path");
	lua_pushstring(m_state, paths.c_str());
	lua_settable(m_state, -3);
	lua_pop(m_state, 1);
}
bool Script::load(const char *script_name)
{
	int status;
	lua_getglobal(m_state, "require");
	lua_pushstring(m_state, script_name);
	status = lua_pcall(m_state, 1, 1, 0);
	if (status) {
		stringstream ss;
		ss << lua_tostring(m_state, -1);
		m_last_error = ss.str();
		return false;
	}
	return true;
}
bool Script::loadCode(const char *script_code)
{
	int status;
	status = luaL_loadstring(m_state, script_code);
	if (status){
		m_last_error = lua_tostring(m_state, -1);
		return false;
	}
	return true;
}
bool Script::run(int arguments_on_stack, int results)
{
	lua_State *L = m_state;
	int status;
	if (lua_type(L, -1) != LUA_TNIL){
		if ((status = lua_pcall(L, arguments_on_stack, results, 0))){
			stringstream ss;
			ss << "call failed: " << lua_tostring(L, -1);
			m_last_error = ss.str();
			return false;
		}else{
			return true;
		}
	}else{
		m_last_error = "requested function was not found";
		return false;
	}
}
static int registerLuaPackage(lua_State *L)
{
	auto &script = *reinterpret_cast<Script*>(lua_touserdata(L, -5));
	auto &extension = *reinterpret_cast<function<int(Script &)>*>(lua_touserdata(L, -4));
	return extension(script);
}
bool Script::registerExtension(const char *name, std::function<int(Script &)> extension)
{
	lua_State *L = m_state;
	string full_name;
	if (name == nullptr)
		full_name = "gpick";
	else
		full_name = string("gpick/") + name;
	lua_pushlightuserdata(L, this);
	lua_pushlightuserdata(L, &extension);
	luaL_requiref(m_state, full_name.c_str(), registerLuaPackage, 0);
	lua_pop(L, 3);
	return true;
}
std::string Script::getString(int index)
{
	return lua_tostring(m_state, index);
}
void Script::createType(const char *name, const luaL_Reg *members)
{
	lua_State *L = m_state;
	luaL_newmetatable(L, name);
	lua_pushvalue(L, -1);
	lua_setfield(L, -2, "__index");
	luaL_setfuncs(L, members, 0);
	lua_pop(L, 1);
}
const std::string &Script::getLastError()
{
	return m_last_error;
}
}
<commit_msg>Fix extension registration crash on Lua 5.2.<commit_after>/*
 * Copyright (c) 2009-2017, Albertas Vyšniauskas
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of the software author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Script.h"
#include <sstream>
extern "C"{
#include <lualib.h>
#include <lauxlib.h>
}
#include <iostream>
using namespace std;
namespace lua
{
Script::Script()
{
	m_state = luaL_newstate();
	m_state_owned = true;
	luaL_openlibs(m_state);
}
Script::Script(lua_State *state)
{
	m_state = state;
	m_state_owned = false;
}
Script::~Script()
{
	if (m_state_owned)
		lua_close(m_state);
	m_state = nullptr;
}
Script::operator lua_State*()
{
	return m_state;
}
void Script::setPaths(const std::vector<std::string> &include_paths)
{
	string paths = ";./?.lua;";
	for (vector<string>::const_iterator i = include_paths.begin(); i != include_paths.end(); i++){
		paths += *i;
		paths += "/?.lua;";
	}
	lua_getglobal(m_state, "package");
	lua_pushstring(m_state, "path");
	lua_pushstring(m_state, paths.c_str());
	lua_settable(m_state, -3);
	lua_pop(m_state, 1);
}
bool Script::load(const char *script_name)
{
	int status;
	lua_getglobal(m_state, "require");
	lua_pushstring(m_state, script_name);
	status = lua_pcall(m_state, 1, 1, 0);
	if (status) {
		stringstream ss;
		ss << lua_tostring(m_state, -1);
		m_last_error = ss.str();
		return false;
	}
	return true;
}
bool Script::loadCode(const char *script_code)
{
	int status;
	status = luaL_loadstring(m_state, script_code);
	if (status){
		m_last_error = lua_tostring(m_state, -1);
		return false;
	}
	return true;
}
bool Script::run(int arguments_on_stack, int results)
{
	lua_State *L = m_state;
	int status;
	if (lua_type(L, -1) != LUA_TNIL){
		if ((status = lua_pcall(L, arguments_on_stack, results, 0))){
			stringstream ss;
			ss << "call failed: " << lua_tostring(L, -1);
			m_last_error = ss.str();
			return false;
		}else{
			return true;
		}
	}else{
		m_last_error = "requested function was not found";
		return false;
	}
}
static int registerLuaPackage(lua_State *L)
{
	lua_getglobal(L, "__script");
	auto &script = *reinterpret_cast<Script*>(lua_touserdata(L, -1));
	lua_getglobal(L, "__extension");
	auto &extension = *reinterpret_cast<function<int(Script &)>*>(lua_touserdata(L, -1));
	lua_pop(L, 2);
	return extension(script);
}
bool Script::registerExtension(const char *name, std::function<int(Script &)> extension)
{
	lua_State *L = m_state;
	string full_name;
	if (name == nullptr)
		full_name = "gpick";
	else
		full_name = string("gpick/") + name;
	lua_pushlightuserdata(L, this);
	lua_setglobal(L, "__script");
	lua_pushlightuserdata(L, &extension);
	lua_setglobal(L, "__extension");
	luaL_requiref(m_state, full_name.c_str(), registerLuaPackage, 0);
	lua_pushnil(L);
	lua_setglobal(L, "__script");
	lua_pushnil(L);
	lua_setglobal(L, "__extension");
	lua_pop(L, 1);
	return true;
}
std::string Script::getString(int index)
{
	return lua_tostring(m_state, index);
}
void Script::createType(const char *name, const luaL_Reg *members)
{
	lua_State *L = m_state;
	luaL_newmetatable(L, name);
	lua_pushvalue(L, -1);
	lua_setfield(L, -2, "__index");
	luaL_setfuncs(L, members, 0);
	lua_pop(L, 1);
}
const std::string &Script::getLastError()
{
	return m_last_error;
}
}
<|endoftext|>


<commit_before>#pragma once

#include "VSExpHack.hpp"

//		make it count for arguments:
#define _ARGCNT(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...)	N
#define WRD_ARGCNT(...)	WRD_VS_EXP_HACK(_ARGCNT(__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define _ARGCNT2(_X1, _Y1, X2, _Y2, _X3, _Y3, _X4, _Y4, _X5, _Y5, _X6, _Y6, _X7, _Y7, _X8, _Y8, _X9, _Y9, _X10, _Y10, _X11, _Y11, _X12, _Y12, _X13, _Y13, _X14, _Y14, _X15, _Y15, _X16, _Y16, N, ...)	N
#define WRD_ARGCNT2(...)	WRD_VS_EXP_HACK(_ARGCNT2(__VA_ARGS__, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0))
<commit_msg>+ [indep] improve Overload macro. it can accepts zeo argument.<commit_after>#pragma once

//		make it count for arguments:
#define _ARGCNT(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...)	N
#define WRD_ARGCNT(...)	_ARGCNT(, ## __VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _ARGCNT2(_X1, _Y1, X2, _Y2, _X3, _Y3, _X4, _Y4, _X5, _Y5, _X6, _Y6, _X7, _Y7, _X8, _Y8, _X9, _Y9, _X10, _Y10, _X11, _Y11, _X12, _Y12, _X13, _Y13, _X14, _Y14, _X15, _Y15, _X16, _Y16, N, ...)	N
#define WRD_ARGCNT2(...)	_ARGCNT2(__VA_ARGS__, 16, 16, 15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0)
<|endoftext|>


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

/*
 * Antonin Bas (antonin@barefootnetworks.com)
 *
 */

#include <gmock/gmock.h>

#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <tuple>
#include <vector>

#include "PI/frontends/cpp/tables.h"
#include "PI/frontends/proto/device_mgr.h"
#include "PI/int/pi_int.h"

#include "src/access_arbitration.h"
#include "src/common.h"
#include "src/watch_port_enforcer.h"

#include "test_proto_fe_base.h"

namespace pi {
namespace proto {
namespace testing {

using pi::fe::proto::AccessArbitration;
using pi::fe::proto::WatchPortEnforcer;

using ::testing::_;
using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;

class WatchPortEnforcerTest : public ProtoFrontendBaseTest {
 public:
  WatchPortEnforcerTest()
      : watch_port_enforcer(device_tgt, &access_arbitration) {
    act_prof_id = pi_p4info_act_prof_id_from_name(p4info, "ActProfWS");
  }

  static void SetUpTestCase() {
    DeviceMgr::init(256);
    std::ifstream istream(input_path);
    google::protobuf::io::IstreamInputStream istream_(&istream);
    google::protobuf::TextFormat::Parse(&istream_, &p4info_proto);
    pi::p4info::p4info_proto_reader(p4info_proto, &p4info);
  }

  static void TearDownTestCase() {
    DeviceMgr::destroy();
  }

  void SetUp() override {
    for (size_t i = 0; i < numPorts; i++) {
      auto port = static_cast<pi_port_t>(i);
      EXPECT_EQ(mock->port_status_set(port, PI_PORT_STATUS_UP),
                PI_STATUS_SUCCESS);
    }
    ASSERT_OK(watch_port_enforcer.p4_change(p4info));
  };

  mutable std::condition_variable cv;
  mutable std::mutex mutex;

  static constexpr size_t numPorts = 16;
  static constexpr const char *input_path =
           TESTDATADIR "/" "unittest.p4info.txt";
  static constexpr std::chrono::milliseconds timeout{200};
  static pi_p4info_t *p4info;
  static p4configv1::P4Info p4info_proto;

  AccessArbitration access_arbitration;
  WatchPortEnforcer watch_port_enforcer;
  pi_p4_id_t act_prof_id;
  pi_indirect_handle_t grp_h{10};
  pi_indirect_handle_t mbr_h{20};
  pi_port_t watch_1{1};
  pi_port_t watch_2{2};
};

/* static */ constexpr std::chrono::milliseconds WatchPortEnforcerTest::timeout;
/* static */ pi_p4info_t *WatchPortEnforcerTest::p4info = nullptr;
/* static */ p4configv1::P4Info WatchPortEnforcerTest::p4info_proto;

TEST_F(WatchPortEnforcerTest, DontUpdateHw) {
  EXPECT_CALL(*mock, action_prof_group_activate_member(act_prof_id, _, _))
      .Times(0);
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(act_prof_id, _, _))
      .Times(0);

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_DOWN);
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  // down -> up
  EXPECT_OK(watch_port_enforcer.modify_member(
      act_prof_id, grp_h, mbr_h, watch_1, watch_2));

  // up -> down
  EXPECT_OK(watch_port_enforcer.modify_member(
      act_prof_id, grp_h, mbr_h, watch_2, watch_1));

  EXPECT_OK(watch_port_enforcer.delete_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_UP);
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_id, grp_h, mbr_h, watch_1));
}

TEST_F(WatchPortEnforcerTest, UpdateHw) {
  ::pi::fe::proto::common::SessionTemp session;
  ::pi::ActProf ap(session.get(), device_tgt, p4info, act_prof_id);

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_DOWN);
  EXPECT_CALL(
      *mock, action_prof_group_deactivate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.add_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1));

  // down -> up
  EXPECT_CALL(
      *mock, action_prof_group_activate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.modify_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1, watch_2));

  // up -> down
  EXPECT_CALL(
      *mock, action_prof_group_deactivate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.modify_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_2, watch_1));

  EXPECT_OK(watch_port_enforcer.delete_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_UP);
  EXPECT_OK(watch_port_enforcer.add_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1));
}

TEST_F(WatchPortEnforcerTest, PortStatusEvents) {
  std::vector<pi_indirect_handle_t> mbrs(numPorts);
  pi_indirect_handle_t mbr_h = 0;
  std::generate(mbrs.begin(), mbrs.end(), [&mbr_h] { return mbr_h++; });

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    EXPECT_OK(watch_port_enforcer.add_member(
        act_prof_id, grp_h, mbrs[i], port));
  }

  EXPECT_CALL(*mock, action_prof_group_deactivate_member(act_prof_id, grp_h, _))
      .Times(numPorts);

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    watch_port_enforcer.handle_port_status_event_sync(
        port, PI_PORT_STATUS_DOWN);
  }

  EXPECT_CALL(*mock, action_prof_group_activate_member(act_prof_id, grp_h, _))
      .Times(numPorts);

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    watch_port_enforcer.handle_port_status_event_sync(
        port, PI_PORT_STATUS_UP);
  }

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    EXPECT_OK(watch_port_enforcer.delete_member(
        act_prof_id, grp_h, mbrs[i], port));
  }
}

TEST_F(WatchPortEnforcerTest, ConcurrentRead) {
  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_TRUE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(
      act_prof_id, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)));
  std::thread thread1([this, &action] {
      AccessArbitration::ReadAccess access(&access_arbitration);
      action();
  });
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

TEST_F(WatchPortEnforcerTest, ExclusiveWrite) {
  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_FALSE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(
      act_prof_id, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)));
  std::thread thread1([this, &action] {
      AccessArbitration::WriteAccess access(&access_arbitration, act_prof_id);
      action();
  });
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

// make sure that there is no deadlock when updating pipeline config
TEST_F(WatchPortEnforcerTest, UpdateConfig) {
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  AccessArbitration::UpdateAccess access(&access_arbitration);
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  EXPECT_OK(watch_port_enforcer.p4_change(p4info));
}

using ::testing::WithParamInterface;
using ::testing::Values;

class WatchPortEnforcerNoWriteAccessOneOfTest
    : public WatchPortEnforcerTest,
      public WithParamInterface<std::tuple<const char *, const char *> > { };

// We test that when there is an ongoing WriteRequest for one action profile,
// port status events can still be processed concurrently for other action
// profiles.
TEST_P(WatchPortEnforcerNoWriteAccessOneOfTest, ConcurrentAccess) {
  pi_p4_id_t act_prof_1_id = pi_p4info_act_prof_id_from_name(
      p4info, std::get<0>(GetParam()));
  pi_p4_id_t act_prof_2_id = pi_p4info_act_prof_id_from_name(
      p4info, std::get<1>(GetParam()));

  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_TRUE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(_, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)))
      .WillOnce(Return(PI_STATUS_SUCCESS));
  std::thread thread1([this, act_prof_1_id, &action] {
      AccessArbitration::WriteAccess access(&access_arbitration, act_prof_1_id);
      action();
  });
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_1_id, grp_h, mbr_h, watch_1));
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_2_id, grp_h, mbr_h, watch_1));
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

INSTANTIATE_TEST_CASE_P(
    ConcurrentAccess, WatchPortEnforcerNoWriteAccessOneOfTest,
    Values(std::make_tuple("ActProfWS", "ActProfWS2"),
           std::make_tuple("ActProfWS2", "ActProfWS")));

}  // namespace testing
}  // namespace proto
}  // namespace pi
<commit_msg>Fix one of the WatchPortEnforcer unit tests<commit_after>/* Copyright 2019-present Barefoot Networks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Antonin Bas (antonin@barefootnetworks.com)
 *
 */

#include <gmock/gmock.h>

#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <tuple>
#include <vector>

#include "PI/frontends/cpp/tables.h"
#include "PI/frontends/proto/device_mgr.h"
#include "PI/int/pi_int.h"

#include "src/access_arbitration.h"
#include "src/common.h"
#include "src/watch_port_enforcer.h"

#include "test_proto_fe_base.h"

namespace pi {
namespace proto {
namespace testing {

using pi::fe::proto::AccessArbitration;
using pi::fe::proto::WatchPortEnforcer;

using ::testing::_;
using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;

class WatchPortEnforcerTest : public ProtoFrontendBaseTest {
 public:
  WatchPortEnforcerTest()
      : watch_port_enforcer(device_tgt, &access_arbitration) {
    act_prof_id = pi_p4info_act_prof_id_from_name(p4info, "ActProfWS");
  }

  static void SetUpTestCase() {
    DeviceMgr::init(256);
    std::ifstream istream(input_path);
    google::protobuf::io::IstreamInputStream istream_(&istream);
    google::protobuf::TextFormat::Parse(&istream_, &p4info_proto);
    pi::p4info::p4info_proto_reader(p4info_proto, &p4info);
  }

  static void TearDownTestCase() {
    DeviceMgr::destroy();
  }

  void SetUp() override {
    for (size_t i = 0; i < numPorts; i++) {
      auto port = static_cast<pi_port_t>(i);
      EXPECT_EQ(mock->port_status_set(port, PI_PORT_STATUS_UP),
                PI_STATUS_SUCCESS);
    }
    ASSERT_OK(watch_port_enforcer.p4_change(p4info));
  };

  mutable std::condition_variable cv;
  mutable std::mutex mutex;

  static constexpr size_t numPorts = 16;
  static constexpr const char *input_path =
           TESTDATADIR "/" "unittest.p4info.txt";
  static constexpr std::chrono::milliseconds timeout{200};
  static pi_p4info_t *p4info;
  static p4configv1::P4Info p4info_proto;

  AccessArbitration access_arbitration;
  WatchPortEnforcer watch_port_enforcer;
  pi_p4_id_t act_prof_id;
  pi_indirect_handle_t grp_h{10};
  pi_indirect_handle_t mbr_h{20};
  pi_port_t watch_1{1};
  pi_port_t watch_2{2};
};

/* static */ constexpr std::chrono::milliseconds WatchPortEnforcerTest::timeout;
/* static */ pi_p4info_t *WatchPortEnforcerTest::p4info = nullptr;
/* static */ p4configv1::P4Info WatchPortEnforcerTest::p4info_proto;

TEST_F(WatchPortEnforcerTest, DontUpdateHw) {
  EXPECT_CALL(*mock, action_prof_group_activate_member(act_prof_id, _, _))
      .Times(0);
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(act_prof_id, _, _))
      .Times(0);

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_DOWN);
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  // down -> up
  EXPECT_OK(watch_port_enforcer.modify_member(
      act_prof_id, grp_h, mbr_h, watch_1, watch_2));

  // up -> down
  EXPECT_OK(watch_port_enforcer.modify_member(
      act_prof_id, grp_h, mbr_h, watch_2, watch_1));

  EXPECT_OK(watch_port_enforcer.delete_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_UP);
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_id, grp_h, mbr_h, watch_1));
}

TEST_F(WatchPortEnforcerTest, UpdateHw) {
  ::pi::fe::proto::common::SessionTemp session;
  ::pi::ActProf ap(session.get(), device_tgt, p4info, act_prof_id);

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_DOWN);
  EXPECT_CALL(
      *mock, action_prof_group_deactivate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.add_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1));

  // down -> up
  EXPECT_CALL(
      *mock, action_prof_group_activate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.modify_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1, watch_2));

  // up -> down
  EXPECT_CALL(
      *mock, action_prof_group_deactivate_member(act_prof_id, grp_h, mbr_h));
  EXPECT_OK(watch_port_enforcer.modify_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_2, watch_1));

  EXPECT_OK(watch_port_enforcer.delete_member(
      act_prof_id, grp_h, mbr_h, watch_1));

  watch_port_enforcer.handle_port_status_event_sync(
      watch_1, PI_PORT_STATUS_UP);
  EXPECT_OK(watch_port_enforcer.add_member_and_update_hw(
      &ap, grp_h, mbr_h, watch_1));
}

TEST_F(WatchPortEnforcerTest, PortStatusEvents) {
  std::vector<pi_indirect_handle_t> mbrs(numPorts);
  pi_indirect_handle_t mbr_h = 0;
  std::generate(mbrs.begin(), mbrs.end(), [&mbr_h] { return mbr_h++; });

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    EXPECT_OK(watch_port_enforcer.add_member(
        act_prof_id, grp_h, mbrs[i], port));
  }

  EXPECT_CALL(*mock, action_prof_group_deactivate_member(act_prof_id, grp_h, _))
      .Times(numPorts);

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    watch_port_enforcer.handle_port_status_event_sync(
        port, PI_PORT_STATUS_DOWN);
  }

  EXPECT_CALL(*mock, action_prof_group_activate_member(act_prof_id, grp_h, _))
      .Times(numPorts);

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    watch_port_enforcer.handle_port_status_event_sync(
        port, PI_PORT_STATUS_UP);
  }

  for (size_t i = 0; i < numPorts; i++) {
    auto port = static_cast<pi_port_t>(i);
    EXPECT_OK(watch_port_enforcer.delete_member(
        act_prof_id, grp_h, mbrs[i], port));
  }
}

TEST_F(WatchPortEnforcerTest, ConcurrentRead) {
  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_TRUE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(
      act_prof_id, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)));
  std::thread thread1([this, &action] {
      AccessArbitration::ReadAccess access(&access_arbitration);
      action();
  });
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

TEST_F(WatchPortEnforcerTest, ExclusiveWrite) {
  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_FALSE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(
      act_prof_id, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)));
  std::thread thread1([this, &action] {
      AccessArbitration::WriteAccess access(&access_arbitration, act_prof_id);
      action();
  });
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

// make sure that there is no deadlock when updating pipeline config
TEST_F(WatchPortEnforcerTest, UpdateConfig) {
  EXPECT_OK(watch_port_enforcer.add_member(act_prof_id, grp_h, mbr_h, watch_1));
  AccessArbitration::UpdateAccess access(&access_arbitration);
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  EXPECT_OK(watch_port_enforcer.p4_change(p4info));
}

using ::testing::WithParamInterface;
using ::testing::Values;

class WatchPortEnforcerNoWriteAccessOneOfTest
    : public WatchPortEnforcerTest,
      public WithParamInterface<std::tuple<const char *, const char *> > { };

// We test that when there is an ongoing WriteRequest for one action profile,
// port status events can still be processed concurrently for other action
// profiles.
TEST_P(WatchPortEnforcerNoWriteAccessOneOfTest, ConcurrentAccess) {
  pi_p4_id_t act_prof_1_id = pi_p4info_act_prof_id_from_name(
      p4info, std::get<0>(GetParam()));
  pi_p4_id_t act_prof_2_id = pi_p4info_act_prof_id_from_name(
      p4info, std::get<1>(GetParam()));

  int x = 0;
  auto action = [this, &x] {
    std::unique_lock<std::mutex> lock(mutex);
    if (x == 0) {
      x = 1;
      cv.notify_one();
      EXPECT_TRUE(cv.wait_for(lock, timeout, [&x] { return x == 0; }));
    } else {
      x = 0;
      cv.notify_one();
    }
  };
  EXPECT_CALL(*mock, action_prof_group_deactivate_member(_, grp_h, mbr_h))
      .WillOnce(DoAll(InvokeWithoutArgs(action), Return(PI_STATUS_SUCCESS)))
      .WillOnce(Return(PI_STATUS_SUCCESS));
  std::thread thread1([this, act_prof_1_id, &action] {
      AccessArbitration::WriteAccess access(&access_arbitration, act_prof_1_id);
      action();
  });
  {
    std::unique_lock<std::mutex> lock(mutex);
    cv.wait(lock, [&x] { return x == 1; });
  }
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_1_id, grp_h, mbr_h, watch_1));
  EXPECT_OK(watch_port_enforcer.add_member(
      act_prof_2_id, grp_h, mbr_h, watch_1));
  // Make sure that thread1 has grabbed WriteAccess before we bring the port
  // down. Otherwise the WatchPortEnforcer may grab access to act_prof_1 first
  // and block thread1. The wait_for would then timeout in thread1 and the test
  // would fail.
  EXPECT_EQ(mock->port_status_set(watch_1, PI_PORT_STATUS_DOWN),
            PI_STATUS_SUCCESS);
  thread1.join();
}

INSTANTIATE_TEST_CASE_P(
    ConcurrentAccess, WatchPortEnforcerNoWriteAccessOneOfTest,
    Values(std::make_tuple("ActProfWS", "ActProfWS2"),
           std::make_tuple("ActProfWS2", "ActProfWS")));

}  // namespace testing
}  // namespace proto
}  // namespace pi
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: attributemap.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 20:23:50 $
 *
 *  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
 *
 ************************************************************************/

// must be first
#include <canvas/debug.hxx>
#include <attributemap.hxx>

#include <tools.hxx>

namespace presentation
{
    namespace internal
    {
        typedef ValueMap< AttributeType > AnimateAttributeMap;

        AttributeType mapAttributeName( const ::rtl::OUString& rAttrName )
        {
            /** Maps attribute name to AttributeType enum.

                String entries are all case-insensitive and MUST
                BE STORED lowercase.

                String entries MUST BE SORTED in ascending order!
            */
            static AnimateAttributeMap::MapEntry lcl_attributeMap[] =
                {
                    { "charcolor", ATTRIBUTE_CHAR_COLOR },

                    { "charfontname", ATTRIBUTE_CHAR_FONT_NAME },

                    { "charheight", ATTRIBUTE_CHAR_HEIGHT },

                    { "charposture", ATTRIBUTE_CHAR_POSTURE },

                    // TODO(Q1): This should prolly be changed in PPT import
                    // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
                    { "charrotation", ATTRIBUTE_ROTATE },

                    { "charunderline", ATTRIBUTE_CHAR_UNDERLINE },

                    { "charweight", ATTRIBUTE_CHAR_WEIGHT },

                    { "color", ATTRIBUTE_COLOR },

                    { "dimcolor", ATTRIBUTE_DIMCOLOR },

                    { "fillcolor", ATTRIBUTE_FILL_COLOR },

                    { "fillstyle", ATTRIBUTE_FILL_STYLE },

                    { "height", ATTRIBUTE_HEIGHT },

                    { "linecolor", ATTRIBUTE_LINE_COLOR },

                    { "linestyle", ATTRIBUTE_LINE_STYLE },

                    { "opacity", ATTRIBUTE_OPACITY },

                    { "rotate", ATTRIBUTE_ROTATE },

                    { "skewx", ATTRIBUTE_SKEW_X },

                    { "skewy", ATTRIBUTE_SKEW_Y },

                    { "visibility", ATTRIBUTE_VISIBILITY },

                    { "width", ATTRIBUTE_WIDTH },

                    { "x", ATTRIBUTE_POS_X },

                    { "y", ATTRIBUTE_POS_Y }
                };

            static AnimateAttributeMap aMap( lcl_attributeMap,
                                             sizeof(lcl_attributeMap)/sizeof(AnimateAttributeMap::MapEntry),
                                             false );

            AttributeType eAttributeType;

            // determine the type from the attribute name
            if( !aMap.lookup( rAttrName,
                              eAttributeType ) )
            {
                OSL_TRACE( "mapAttributeName(): attribute name %s not found in map.",
                           ::rtl::OUStringToOString( rAttrName,
                                                     RTL_TEXTENCODING_ASCII_US ).getStr() );
                return ATTRIBUTE_INVALID;
            }

            return eAttributeType;
        }

    }
}
<commit_msg>INTEGRATION: CWS canvas02 (1.3.4); FILE MERGED 2005/10/19 14:41:25 thb 1.3.4.1: #i48939# Moved ValueMap from slideshow; adapted AttributeMap accordingly; added debug trigger code, which initiates a screen dump, after an animation batch has completed<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: attributemap.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-02 14:02:09 $
 *
 *  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
 *
 ************************************************************************/

// must be first
#include <canvas/debug.hxx>
#include <canvas/canvastools.hxx>

#include "attributemap.hxx"
#include "tools.hxx"

namespace presentation
{
    namespace internal
    {
        typedef ::canvas::tools::ValueMap< AttributeType > AnimateAttributeMap;

        AttributeType mapAttributeName( const ::rtl::OUString& rAttrName )
        {
            /** Maps attribute name to AttributeType enum.

                String entries are all case-insensitive and MUST
                BE STORED lowercase.

                String entries MUST BE SORTED in ascending order!
            */
            static AnimateAttributeMap::MapEntry lcl_attributeMap[] =
                {
                    { "charcolor", ATTRIBUTE_CHAR_COLOR },

                    { "charfontname", ATTRIBUTE_CHAR_FONT_NAME },

                    { "charheight", ATTRIBUTE_CHAR_HEIGHT },

                    { "charposture", ATTRIBUTE_CHAR_POSTURE },

                    // TODO(Q1): This should prolly be changed in PPT import
                    // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
                    { "charrotation", ATTRIBUTE_ROTATE },

                    { "charunderline", ATTRIBUTE_CHAR_UNDERLINE },

                    { "charweight", ATTRIBUTE_CHAR_WEIGHT },

                    { "color", ATTRIBUTE_COLOR },

                    { "dimcolor", ATTRIBUTE_DIMCOLOR },

                    { "fillcolor", ATTRIBUTE_FILL_COLOR },

                    { "fillstyle", ATTRIBUTE_FILL_STYLE },

                    { "height", ATTRIBUTE_HEIGHT },

                    { "linecolor", ATTRIBUTE_LINE_COLOR },

                    { "linestyle", ATTRIBUTE_LINE_STYLE },

                    { "opacity", ATTRIBUTE_OPACITY },

                    { "rotate", ATTRIBUTE_ROTATE },

                    { "skewx", ATTRIBUTE_SKEW_X },

                    { "skewy", ATTRIBUTE_SKEW_Y },

                    { "visibility", ATTRIBUTE_VISIBILITY },

                    { "width", ATTRIBUTE_WIDTH },

                    { "x", ATTRIBUTE_POS_X },

                    { "y", ATTRIBUTE_POS_Y }
                };

            static AnimateAttributeMap aMap( lcl_attributeMap,
                                             sizeof(lcl_attributeMap)/sizeof(AnimateAttributeMap::MapEntry),
                                             false );

            AttributeType eAttributeType;

            // determine the type from the attribute name
            if( !aMap.lookup( rAttrName,
                              eAttributeType ) )
            {
                OSL_TRACE( "mapAttributeName(): attribute name %s not found in map.",
                           ::rtl::OUStringToOString( rAttrName,
                                                     RTL_TEXTENCODING_ASCII_US ).getStr() );
                return ATTRIBUTE_INVALID;
            }

            return eAttributeType;
        }

    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: pardlg.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2003-04-17 15:16:22 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#include "hintids.hxx"

#ifndef _SVX_TABSTPGE_HXX //autogen
#include <svx/tabstpge.hxx>
#endif
#ifndef _SVX_PARAGRPH_HXX //autogen
#include <svx/paragrph.hxx>
#endif
#ifndef _SVX_BACKGRND_HXX
#include <svx/backgrnd.hxx>
#endif
#ifndef _SVX_BORDER_HXX
#include <svx/border.hxx>
#endif
#ifndef _SVX_HTMLMODE_HXX
#include <svx/htmlmode.hxx>
#endif
#ifndef _SFXSTYLE_HXX //autogen
#include <svtools/style.hxx>
#endif
#ifndef _OFA_HTMLCFG_HXX //autogen
#include <offmgr/htmlcfg.hxx>
#endif
#ifndef _OFF_APP_HXX //autogen
#include <offmgr/app.hxx>
#endif

#ifndef _SVSTDARR_STRINGSISORTDTOR
#define _SVSTDARR_STRINGSISORTDTOR
#include <svtools/svstdarr.hxx>
#endif
#ifndef _SVTOOLS_CJKOPTIONS_HXX
#include <svtools/cjkoptions.hxx>
#endif
#include "docsh.hxx"
#include "wrtsh.hxx"
#include "frmatr.hxx"
#include "view.hxx"
#include "globals.hrc"
#include "pardlg.hxx"
#include "pagedesc.hxx"
#include "paratr.hxx"
#include "drpcps.hxx"
#include "uitool.hxx"
#include "viewopt.hxx"

#ifndef _NUMPARA_HXX
#include <numpara.hxx>
#endif
#include "chrdlg.hrc"
#include "poolfmt.hrc"

// STATIC DATA -----------------------------------------------------------

SwParaDlg::SwParaDlg(Window *pParent,
                    SwView& rVw,
                    const SfxItemSet& rCoreSet,
                    BYTE nDialogMode,
                    const String *pTitle,
                    BOOL bDraw,
                    UINT16 nDefPage):

    SfxTabDialog(pParent, bDraw ? SW_RES(DLG_DRAWPARA) : SW_RES(DLG_PARA),
                    &rCoreSet,  0 != pTitle),

    rView(rVw),
    nDlgMode(nDialogMode),
    bDrawParaDlg(bDraw)

{
    FreeResource();

    nHtmlMode = ::GetHtmlMode(rVw.GetDocShell());
    BOOL bHtmlMode = nHtmlMode & HTMLMODE_ON;
    if(pTitle)
    {
            // Update des Titels
        String aTmp( GetText() );
        aTmp += SW_RESSTR(STR_TEXTCOLL_HEADER);
        aTmp += *pTitle;
        aTmp += ')';
        SetText(aTmp);
    }

    AddTabPage(TP_PARA_STD,  SvxStdParagraphTabPage::Create,SvxStdParagraphTabPage::GetRanges);
    AddTabPage(TP_PARA_ALIGN,  SvxParaAlignTabPage::Create,SvxParaAlignTabPage::GetRanges);

    OfaHtmlOptions* pHtmlOpt = OFF_APP()->GetHtmlOptions();
    if (!bDrawParaDlg && (!bHtmlMode || pHtmlOpt->IsPrintLayoutExtension()))
        AddTabPage(TP_PARA_EXT,  SvxExtParagraphTabPage::Create,SvxExtParagraphTabPage::GetRanges);
    else
        RemoveTabPage(TP_PARA_EXT);

    SvtCJKOptions aCJKOptions;
    if(!bHtmlMode && aCJKOptions.IsAsianTypographyEnabled())
        AddTabPage(TP_PARA_ASIAN,  SvxAsianTabPage::Create,SvxAsianTabPage::GetRanges);
    else
        RemoveTabPage(TP_PARA_ASIAN);

    USHORT nWhich(rCoreSet.GetPool()->GetWhich(SID_ATTR_LRSPACE));
    BOOL bLRValid = SFX_ITEM_AVAILABLE <= rCoreSet.GetItemState(nWhich);
    if(bHtmlMode || !bLRValid)
        RemoveTabPage(TP_TABULATOR);
    else
        AddTabPage(TP_TABULATOR, SvxTabulatorTabPage::Create,   SvxTabulatorTabPage::GetRanges);

    if (!bDrawParaDlg)
    {
        if(!(nDlgMode & DLG_ENVELOP))
            AddTabPage(TP_NUMPARA,   SwParagraphNumTabPage::Create,SwParagraphNumTabPage::GetRanges);
        else
            RemoveTabPage(TP_NUMPARA);
        if(!bHtmlMode || (nHtmlMode & HTMLMODE_FULL_STYLES))
        {
            AddTabPage(TP_DROPCAPS,  SwDropCapsPage::Create,        SwDropCapsPage::GetRanges);
            AddTabPage(TP_BACKGROUND,SvxBackgroundTabPage::Create,  SvxBackgroundTabPage::GetRanges);
        }
        else
        {
            RemoveTabPage(TP_DROPCAPS);
            RemoveTabPage(TP_BACKGROUND);
        }
        if(!bHtmlMode || (nHtmlMode & HTMLMODE_PARA_BORDER))
            AddTabPage(TP_BORDER,    SvxBorderTabPage::Create,      SvxBorderTabPage::GetRanges);
        else
            RemoveTabPage(TP_BORDER);
    }

    if (nDefPage)
        SetCurPageId(nDefPage);
}

__EXPORT SwParaDlg::~SwParaDlg()
{
}

void __EXPORT SwParaDlg::PageCreated(USHORT nId, SfxTabPage& rPage)
{
    SwWrtShell& rSh = rView.GetWrtShell();

    // Bei Tabellenumrandung kann im Writer kein Schatten eingestellt werden
    if (nId == TP_BORDER)
    {
        ((SvxBorderTabPage&) rPage).SetSWMode(SW_BORDER_MODE_PARA);
    }
    else if( nId == TP_PARA_STD )
    {
        ((SvxStdParagraphTabPage&)rPage).SetPageWidth(
                                            rSh.GetAnyCurRect(RECT_PAGE_PRT).Width());
        if (!bDrawParaDlg)
        {
            ((SvxStdParagraphTabPage&)rPage).EnableRegisterMode();
            ((SvxStdParagraphTabPage&)rPage).EnableAutoFirstLine();
            ((SvxStdParagraphTabPage&)rPage).EnableAbsLineDist(MM50/2);
            ((SvxStdParagraphTabPage&)rPage).EnableNegativeMode();
        }
    }
    else if( TP_PARA_ALIGN == nId)
    {
        if (!bDrawParaDlg)
            ((SvxParaAlignTabPage&)rPage).EnableJustifyExt();
    }
    else if( TP_PARA_EXT == nId )
    {
        // Seitenumbruch nur, wenn der Cursor im Body-Bereich und nicht in
        // einer Tabelle steht
        const USHORT eType = rSh.GetFrmType(0,TRUE);
        if( !(FRMTYPE_BODY & eType) ||
            rSh.GetSelectionType() & SwWrtShell::SEL_TBL )
            ((SvxExtParagraphTabPage&)rPage).DisablePageBreak();
    }
    else if( TP_DROPCAPS == nId )
    {
        ((SwDropCapsPage&)rPage).SetFormat(FALSE);
    }
    else if( TP_BACKGROUND == nId )
    {
      if(!( nHtmlMode & HTMLMODE_ON ) ||
        nHtmlMode & HTMLMODE_SOME_STYLES)
            ((SvxBackgroundTabPage&)rPage).ShowSelector();
    }
    else if( TP_NUMPARA == nId)
    {
        ((SwParagraphNumTabPage&)rPage).EnableNewStart();
        ListBox & rBox = ((SwParagraphNumTabPage&)rPage).GetStyleBox();
        SfxStyleSheetBasePool* pPool = rView.GetDocShell()->GetStyleSheetPool();
        pPool->SetSearchMask(SFX_STYLE_FAMILY_PSEUDO, SFXSTYLEBIT_ALL);
        const SfxStyleSheetBase* pBase = pPool->First();
        SvStringsISortDtor aNames;
        while(pBase)
        {
            aNames.Insert(new String(pBase->GetName()));
            pBase = pPool->Next();
        }
        for(USHORT i = 0; i < aNames.Count(); i++)
            rBox.InsertEntry(*aNames.GetObject(i));
    }

}

<commit_msg>INTEGRATION: CWS dialogdiet (1.5.276); FILE MERGED 2003/12/01 09:07:20 mba 1.5.276.1: #i22972#: options moved from offmgr<commit_after>/*************************************************************************
 *
 *  $RCSfile: pardlg.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2004-02-03 16:35:38 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#include "hintids.hxx"

#ifndef _SVX_TABSTPGE_HXX //autogen
#include <svx/tabstpge.hxx>
#endif
#ifndef _SVX_PARAGRPH_HXX //autogen
#include <svx/paragrph.hxx>
#endif
#ifndef _SVX_BACKGRND_HXX
#include <svx/backgrnd.hxx>
#endif
#ifndef _SVX_BORDER_HXX
#include <svx/border.hxx>
#endif
#ifndef _SVX_HTMLMODE_HXX
#include <svx/htmlmode.hxx>
#endif
#ifndef _SFXSTYLE_HXX //autogen
#include <svtools/style.hxx>
#endif

#include <svx/htmlcfg.hxx>

#ifndef _SVSTDARR_STRINGSISORTDTOR
#define _SVSTDARR_STRINGSISORTDTOR
#include <svtools/svstdarr.hxx>
#endif
#ifndef _SVTOOLS_CJKOPTIONS_HXX
#include <svtools/cjkoptions.hxx>
#endif
#include "docsh.hxx"
#include "wrtsh.hxx"
#include "frmatr.hxx"
#include "view.hxx"
#include "globals.hrc"
#include "pardlg.hxx"
#include "pagedesc.hxx"
#include "paratr.hxx"
#include "drpcps.hxx"
#include "uitool.hxx"
#include "viewopt.hxx"

#ifndef _NUMPARA_HXX
#include <numpara.hxx>
#endif
#include "chrdlg.hrc"
#include "poolfmt.hrc"

// STATIC DATA -----------------------------------------------------------

SwParaDlg::SwParaDlg(Window *pParent,
                    SwView& rVw,
                    const SfxItemSet& rCoreSet,
                    BYTE nDialogMode,
                    const String *pTitle,
                    BOOL bDraw,
                    UINT16 nDefPage):

    SfxTabDialog(pParent, bDraw ? SW_RES(DLG_DRAWPARA) : SW_RES(DLG_PARA),
                    &rCoreSet,  0 != pTitle),

    rView(rVw),
    nDlgMode(nDialogMode),
    bDrawParaDlg(bDraw)

{
    FreeResource();

    nHtmlMode = ::GetHtmlMode(rVw.GetDocShell());
    BOOL bHtmlMode = nHtmlMode & HTMLMODE_ON;
    if(pTitle)
    {
            // Update des Titels
        String aTmp( GetText() );
        aTmp += SW_RESSTR(STR_TEXTCOLL_HEADER);
        aTmp += *pTitle;
        aTmp += ')';
        SetText(aTmp);
    }

    AddTabPage(TP_PARA_STD,  SvxStdParagraphTabPage::Create,SvxStdParagraphTabPage::GetRanges);
    AddTabPage(TP_PARA_ALIGN,  SvxParaAlignTabPage::Create,SvxParaAlignTabPage::GetRanges);

    SvxHtmlOptions* pHtmlOpt = SvxHtmlOptions::Get();
    if (!bDrawParaDlg && (!bHtmlMode || pHtmlOpt->IsPrintLayoutExtension()))
        AddTabPage(TP_PARA_EXT,  SvxExtParagraphTabPage::Create,SvxExtParagraphTabPage::GetRanges);
    else
        RemoveTabPage(TP_PARA_EXT);

    SvtCJKOptions aCJKOptions;
    if(!bHtmlMode && aCJKOptions.IsAsianTypographyEnabled())
        AddTabPage(TP_PARA_ASIAN,  SvxAsianTabPage::Create,SvxAsianTabPage::GetRanges);
    else
        RemoveTabPage(TP_PARA_ASIAN);

    USHORT nWhich(rCoreSet.GetPool()->GetWhich(SID_ATTR_LRSPACE));
    BOOL bLRValid = SFX_ITEM_AVAILABLE <= rCoreSet.GetItemState(nWhich);
    if(bHtmlMode || !bLRValid)
        RemoveTabPage(TP_TABULATOR);
    else
        AddTabPage(TP_TABULATOR, SvxTabulatorTabPage::Create,   SvxTabulatorTabPage::GetRanges);

    if (!bDrawParaDlg)
    {
        if(!(nDlgMode & DLG_ENVELOP))
            AddTabPage(TP_NUMPARA,   SwParagraphNumTabPage::Create,SwParagraphNumTabPage::GetRanges);
        else
            RemoveTabPage(TP_NUMPARA);
        if(!bHtmlMode || (nHtmlMode & HTMLMODE_FULL_STYLES))
        {
            AddTabPage(TP_DROPCAPS,  SwDropCapsPage::Create,        SwDropCapsPage::GetRanges);
            AddTabPage(TP_BACKGROUND,SvxBackgroundTabPage::Create,  SvxBackgroundTabPage::GetRanges);
        }
        else
        {
            RemoveTabPage(TP_DROPCAPS);
            RemoveTabPage(TP_BACKGROUND);
        }
        if(!bHtmlMode || (nHtmlMode & HTMLMODE_PARA_BORDER))
            AddTabPage(TP_BORDER,    SvxBorderTabPage::Create,      SvxBorderTabPage::GetRanges);
        else
            RemoveTabPage(TP_BORDER);
    }

    if (nDefPage)
        SetCurPageId(nDefPage);
}

__EXPORT SwParaDlg::~SwParaDlg()
{
}

void __EXPORT SwParaDlg::PageCreated(USHORT nId, SfxTabPage& rPage)
{
    SwWrtShell& rSh = rView.GetWrtShell();

    // Bei Tabellenumrandung kann im Writer kein Schatten eingestellt werden
    if (nId == TP_BORDER)
    {
        ((SvxBorderTabPage&) rPage).SetSWMode(SW_BORDER_MODE_PARA);
    }
    else if( nId == TP_PARA_STD )
    {
        ((SvxStdParagraphTabPage&)rPage).SetPageWidth(
                                            rSh.GetAnyCurRect(RECT_PAGE_PRT).Width());
        if (!bDrawParaDlg)
        {
            ((SvxStdParagraphTabPage&)rPage).EnableRegisterMode();
            ((SvxStdParagraphTabPage&)rPage).EnableAutoFirstLine();
            ((SvxStdParagraphTabPage&)rPage).EnableAbsLineDist(MM50/2);
            ((SvxStdParagraphTabPage&)rPage).EnableNegativeMode();
        }
    }
    else if( TP_PARA_ALIGN == nId)
    {
        if (!bDrawParaDlg)
            ((SvxParaAlignTabPage&)rPage).EnableJustifyExt();
    }
    else if( TP_PARA_EXT == nId )
    {
        // Seitenumbruch nur, wenn der Cursor im Body-Bereich und nicht in
        // einer Tabelle steht
        const USHORT eType = rSh.GetFrmType(0,TRUE);
        if( !(FRMTYPE_BODY & eType) ||
            rSh.GetSelectionType() & SwWrtShell::SEL_TBL )
            ((SvxExtParagraphTabPage&)rPage).DisablePageBreak();
    }
    else if( TP_DROPCAPS == nId )
    {
        ((SwDropCapsPage&)rPage).SetFormat(FALSE);
    }
    else if( TP_BACKGROUND == nId )
    {
      if(!( nHtmlMode & HTMLMODE_ON ) ||
        nHtmlMode & HTMLMODE_SOME_STYLES)
            ((SvxBackgroundTabPage&)rPage).ShowSelector();
    }
    else if( TP_NUMPARA == nId)
    {
        ((SwParagraphNumTabPage&)rPage).EnableNewStart();
        ListBox & rBox = ((SwParagraphNumTabPage&)rPage).GetStyleBox();
        SfxStyleSheetBasePool* pPool = rView.GetDocShell()->GetStyleSheetPool();
        pPool->SetSearchMask(SFX_STYLE_FAMILY_PSEUDO, SFXSTYLEBIT_ALL);
        const SfxStyleSheetBase* pBase = pPool->First();
        SvStringsISortDtor aNames;
        while(pBase)
        {
            aNames.Insert(new String(pBase->GetName()));
            pBase = pPool->Next();
        }
        for(USHORT i = 0; i < aNames.Count(); i++)
            rBox.InsertEntry(*aNames.GetObject(i));
    }

}

<|endoftext|>


<commit_before>
/*
 * Copyright (C) 2012 - 2013  微蔡 <microcai@fedoraproject.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#pragma once

#include <string>
#include <iostream>

#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/urlencode.hpp>
#include <boost/logger.hpp>

#include <avhttp.hpp>
#include <avhttp/async_read_body.hpp>

#include "webqq_impl.hpp"

#include "constant.hpp"

namespace webqq {
namespace qqimpl {
namespace detail {

// qq 登录办法
template<class Handler>
class SYMBOL_HIDDEN check_login_op : boost::asio::coroutine
{
public:
	check_login_op( std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
		: m_webqq( webqq ), m_handler(handler)
	{
		// 首先登录一下 w.qq.com
		stream = std::make_shared<avhttp::http_stream>( boost::ref(m_webqq->get_ioservice()));
		m_buffer = std::make_shared<boost::asio::streambuf>();

		m_webqq->logger.dbg() << "go w.qq.com";

		avhttp::async_read_body( *stream, "http://w.qq.com", * m_buffer,  *this );
	}

	// 在这里实现　QQ 的登录.
	void operator()(const boost::system::error_code& ec, std::size_t bytes_transfered)
	{
		std::string response;
		response.resize(bytes_transfered);
		m_buffer->sgetn(&response[0], bytes_transfered);

		boost::regex ex, ex2;
		boost::smatch what;
		std::string url;

		BOOST_ASIO_CORO_REENTER(this)
		{
			m_webqq->m_cookie_mgr.save_cookie(*stream);

	  		// 获得版本.
	  		stream = std::make_shared<avhttp::http_stream>( boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

	  		m_webqq->logger.dbg() << "Get webqq version from " <<  LWQQ_URL_VERSION ;
			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(
				*stream, LWQQ_URL_VERSION, *m_buffer, *this
			);

			ex.set_expression("ptuiV\\(([0-9]*)\\);");

			if(boost::regex_search(response, what, ex))
			{
				m_webqq->m_version = what[1];
			}

			m_webqq->logger.info() << "Get webqq version: " << m_webqq->m_version;

			// 接着获得验证码.
			m_webqq->m_clientid.clear();
			m_webqq->m_groups.clear();
			m_webqq->m_psessionid.clear();
			m_webqq->m_vfwebqq.clear();
			m_webqq->m_status = LWQQ_STATUS_OFFLINE;

			// 获取　login_sig

			stream = std::make_shared<avhttp::http_stream>(boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(*stream,/*url*/
					boost::str(
						boost::format("%s?daid=164&target=self&style=5&mibao_css=m_webqq&appid=%s&enable_qlogin=0&s_url=%s&strong_login=1&login_state=10&t=20131024001")
							% LWQQ_URL_CHECK_LOGIN_SIG_HOST
							% APPID
							% avhttp::detail::escape_string(std::string("http://w.qq.com/proxy.html"))
					),
					*m_buffer,
					*this);

			// 类似这样的
			// 是一个正常的 HTML 文件，　但是内容包含
			// g_login_sig=encodeURIComponent("PpbBnX213jzzSH8*xXyySm9qq1jAnP2uo1fXkGaC5t0ZDaxE5MzSR59qh1EhmjqA");

			if (boost::regex_search(response, what, boost::regex("g_login_sig *= *encodeURIComponent\\(\"([^\"]*)\"\\);")))
			{
				m_webqq->m_login_sig = what[1];
			}
			else if (boost::regex_search(response, what, boost::regex("g_login_sig=encodeURIComponent\\(\"([^\"]*)\"\\);")))
			{
				m_webqq->m_login_sig = what[1];
			}

			m_webqq->logger.info() << "Get g_login_sig: " << m_webqq->m_login_sig;

			//获取验证码.

			stream = std::make_shared<avhttp::http_stream>(boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

			stream->request_options(
				avhttp::request_opts()
				(avhttp::http_options::connection, "close")
				(avhttp::http_options::referer, "https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001")
			);

			url = boost::str(boost::format("%s%s?pt_tea=1&uin=%s&appid=%s&js_ver=10114&js_type=0&login_sig=%s&u1=%s&r=%.16lf")
                    % LWQQ_URL_CHECK_HOST
                    % VCCHECKPATH % m_webqq->m_qqnum % APPID
                    % m_webqq->m_login_sig
                    % "http%3A%2F%2Fw.qq.com%2Fproxy.html"
					% rand()
			);

			m_webqq->m_cookie_mgr.get_cookie(url, *stream);

			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(*stream, url , *m_buffer, *this);

			// 解析验证码，然后带验证码登录.

			/**
			*
			* The http message body has two format:
			*
			* ptui_checkVC('1','9ed32e3f644d968809e8cbeaaf2cce42de62dfee12c14b74', '\x00\x00\x00\x00\x54\xb3\x3c\x53', 'ptvfsession');
			* ptui_checkVC('1','6kn6cK_Xz9skMLUNbxNq3RcG9uYR7-H2','\\x00\\x00\\x00\\x00\\x68\\xe9\\x0b\\x58', 'ptvfsession');
			* ptui_checkVC('0','!IJG', '\x00\x00\x00\x00\x54\xb3\x3c\x53', 'ptvfsession');
			* The former means we need verify code image and the second
			* parameter is vc_type.
			* The later means we don't need the verify code image. The second
			* parameter is the verify code. The vc_type is in the header
			* "Set-Cookie".
			*/
			ex.set_expression("ptui_checkVC\\('([0-9])',[ ]?'([0-9a-zA-Z!]*)',[ ]?'([0-9a-zA-Z\\\\]*)',[ ]?'([0-9a-zA-Z\\\\]*)'");
			ex2.set_expression("ptui_checkVC\\('([0-9])','([_\\-0-9a-zA-Z!]*)','([0-9a-zA-Z\\\\]*)',[ ]?'([0-9a-zA-Z\\\\]*)'");

			if (boost::regex_search(response, what, ex) || boost::regex_search(response, what, ex2))
			{
				std::string type = what[1];
				std::string vc = what[2];
				m_webqq->m_verifycode.uin = what[3];
				std::string vfsession = what[4];
				if (!vfsession.empty())
					m_webqq->m_ptvfsession = vfsession;

				/* We need get the ptvfsession from the header "Set-Cookie" */
				if(type == "0")
				{
					m_webqq->m_cookie_mgr.save_cookie(*stream);
					m_webqq->pt_verifysession = stream->http_cookies()["ptvfsession"];
					m_handler(boost::system::error_code(), vc);
					return;
				}
				else if(type == "1")
				{
					m_webqq->get_verify_image(vc ,  *this);
					return;
				}
			}

			// 未知错误.
			m_handler(error::make_error_code(error::login_failed_other), std::string());
		}
	}

	void operator()(boost::system::error_code ec, std::string vc)
	{
		if (!ec)
			ec = error::login_check_need_vc;

		m_webqq->pt_verifysession = m_webqq->m_cookie_mgr.get_cookie("http://qq.com")["verifysession"];
		m_handler(ec, vc);
	}
private:
	std::shared_ptr<qqimpl::WebQQ> m_webqq;
	Handler m_handler;

	read_streamptr stream;
	std::shared_ptr<boost::asio::streambuf> m_buffer;
};

template<class Handler>
check_login_op<Handler> make_check_login_op(std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
{
	return check_login_op<Handler>(webqq, handler);
}

} // namespace detail

template<class Handler>
void async_check_login(std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
{
	detail::make_check_login_op(webqq, handler);
}

} // namespace qqimpl
} // namespace webqq
<commit_msg>fix compile error<commit_after>
/*
 * Copyright (C) 2012 - 2013  微蔡 <microcai@fedoraproject.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#pragma once

#include <string>
#include <iostream>

#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/urlencode.hpp>
#include <boost/logger.hpp>

#include <avhttp.hpp>
#include <avhttp/async_read_body.hpp>

#include "webqq_impl.hpp"

#include "constant.hpp"

namespace webqq {
namespace qqimpl {
namespace detail {

// qq 登录办法
template<class Handler>
class SYMBOL_HIDDEN check_login_op : boost::asio::coroutine
{
public:
	check_login_op( std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
		: m_webqq( webqq ), m_handler(handler)
	{
		// 首先登录一下 w.qq.com
		stream = std::make_shared<avhttp::http_stream>( boost::ref(m_webqq->get_ioservice()));
		m_buffer = std::make_shared<boost::asio::streambuf>();

		m_webqq->logger.dbg() << "go w.qq.com";

		avhttp::async_read_body( *stream, "http://w.qq.com", * m_buffer,  *this );
	}

	// 在这里实现　QQ 的登录.
	void operator()(const boost::system::error_code& ec, std::size_t bytes_transfered)
	{
		std::string response;
		response.resize(bytes_transfered);
		m_buffer->sgetn(&response[0], bytes_transfered);

		boost::regex ex, ex2;
		boost::smatch what;
		std::string url;

		BOOST_ASIO_CORO_REENTER(this)
		{
			m_webqq->m_cookie_mgr.save_cookie(*stream);

	  		// 获得版本.
	  		stream = std::make_shared<avhttp::http_stream>( boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

	  		m_webqq->logger.dbg() << "Get webqq version from " <<  LWQQ_URL_VERSION ;
			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(
				*stream, LWQQ_URL_VERSION, *m_buffer, *this
			);

			ex.set_expression("ptuiV\\(([0-9]*)\\);");

			if(boost::regex_search(response, what, ex))
			{
				m_webqq->m_version = what[1];
			}

			m_webqq->logger.info() << "Get webqq version: " << m_webqq->m_version;

			// 接着获得验证码.
			m_webqq->m_clientid.clear();
			m_webqq->m_groups.clear();
			m_webqq->m_psessionid.clear();
			m_webqq->m_vfwebqq.clear();
			m_webqq->m_status = LWQQ_STATUS_OFFLINE;

			// 获取　login_sig

			stream = std::make_shared<avhttp::http_stream>(boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(*stream,/*url*/
					boost::str(
						boost::format("%s?daid=164&target=self&style=5&mibao_css=m_webqq&appid=%s&enable_qlogin=0&s_url=%s&strong_login=1&login_state=10&t=20131024001")
							% LWQQ_URL_CHECK_LOGIN_SIG_HOST
							% APPID
							% avhttp::detail::escape_string(std::string("http://w.qq.com/proxy.html"))
					),
					*m_buffer,
					*this);

			// 类似这样的
			// 是一个正常的 HTML 文件，　但是内容包含
			// g_login_sig=encodeURIComponent("PpbBnX213jzzSH8*xXyySm9qq1jAnP2uo1fXkGaC5t0ZDaxE5MzSR59qh1EhmjqA");

			if (boost::regex_search(response, what, boost::regex("g_login_sig *= *encodeURIComponent\\(\"([^\"]*)\"\\);")))
			{
				m_webqq->m_login_sig = what[1];
			}
			else if (boost::regex_search(response, what, boost::regex("g_login_sig=encodeURIComponent\\(\"([^\"]*)\"\\);")))
			{
				m_webqq->m_login_sig = what[1];
			}

			m_webqq->logger.info() << "Get g_login_sig: " << m_webqq->m_login_sig;

			//获取验证码.

			stream = std::make_shared<avhttp::http_stream>(boost::ref(m_webqq->get_ioservice()));
			m_buffer = std::make_shared<boost::asio::streambuf>();

			stream->request_options(
				avhttp::request_opts()
				(avhttp::http_options::connection, "close")
				(avhttp::http_options::referer, "https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001")
			);

			url = boost::str(boost::format("%s%s?pt_tea=1&uin=%s&appid=%s&js_ver=10114&js_type=0&login_sig=%s&u1=%s&r=%.16lf")
                    % LWQQ_URL_CHECK_HOST
                    % VCCHECKPATH % m_webqq->m_qqnum % APPID
                    % m_webqq->m_login_sig
                    % "http%3A%2F%2Fw.qq.com%2Fproxy.html"
					% rand()
			);

			m_webqq->m_cookie_mgr.get_cookie(url, *stream);

			BOOST_ASIO_CORO_YIELD avhttp::async_read_body(*stream, url , *m_buffer, *this);

			// 解析验证码，然后带验证码登录.

			/**
			*
			* The http message body has two format:
			*
			* ptui_checkVC('1','9ed32e3f644d968809e8cbeaaf2cce42de62dfee12c14b74', '\x00\x00\x00\x00\x54\xb3\x3c\x53', 'ptvfsession');
			* ptui_checkVC('1','6kn6cK_Xz9skMLUNbxNq3RcG9uYR7-H2','\\x00\\x00\\x00\\x00\\x68\\xe9\\x0b\\x58', 'ptvfsession');
			* ptui_checkVC('0','!IJG', '\x00\x00\x00\x00\x54\xb3\x3c\x53', 'ptvfsession');
			* The former means we need verify code image and the second
			* parameter is vc_type.
			* The later means we don't need the verify code image. The second
			* parameter is the verify code. The vc_type is in the header
			* "Set-Cookie".
			*/
			ex.set_expression("ptui_checkVC\\('([0-9])',[ ]?'([0-9a-zA-Z!]*)',[ ]?'([0-9a-zA-Z\\\\]*)',[ ]?'([0-9a-zA-Z\\\\]*)'");
			ex2.set_expression("ptui_checkVC\\('([0-9])','([_\\-0-9a-zA-Z!]*)','([0-9a-zA-Z\\\\]*)',[ ]?'([0-9a-zA-Z\\\\]*)'");

			if (boost::regex_search(response, what, ex) || boost::regex_search(response, what, ex2))
			{
				std::string type = what[1];
				std::string vc = what[2];
				m_webqq->m_verifycode.uin = what[3];
				std::string vfsession = what[4];
				if (!vfsession.empty())
					m_webqq->pt_verifysession = vfsession;

				/* We need get the ptvfsession from the header "Set-Cookie" */
				if(type == "0")
				{
					m_webqq->m_cookie_mgr.save_cookie(*stream);
					m_webqq->pt_verifysession = stream->http_cookies()["ptvfsession"];
					m_handler(boost::system::error_code(), vc);
					return;
				}
				else if(type == "1")
				{
					m_webqq->get_verify_image(vc ,  *this);
					return;
				}
			}

			// 未知错误.
			m_handler(error::make_error_code(error::login_failed_other), std::string());
		}
	}

	void operator()(boost::system::error_code ec, std::string vc)
	{
		if (!ec)
			ec = error::login_check_need_vc;

		m_webqq->pt_verifysession = m_webqq->m_cookie_mgr.get_cookie("http://qq.com")["verifysession"];
		m_handler(ec, vc);
	}
private:
	std::shared_ptr<qqimpl::WebQQ> m_webqq;
	Handler m_handler;

	read_streamptr stream;
	std::shared_ptr<boost::asio::streambuf> m_buffer;
};

template<class Handler>
check_login_op<Handler> make_check_login_op(std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
{
	return check_login_op<Handler>(webqq, handler);
}

} // namespace detail

template<class Handler>
void async_check_login(std::shared_ptr<qqimpl::WebQQ> webqq, Handler handler)
{
	detail::make_check_login_op(webqq, handler);
}

} // namespace qqimpl
} // namespace webqq
<|endoftext|>