Merge branch 'develop' into glview_improvements

This commit is contained in:
Ricardo Quesada 2014-01-24 14:22:25 -08:00
commit 8c62fcb7ba
97 changed files with 8462 additions and 780 deletions

View File

@ -511,6 +511,7 @@ Developers:
Lee, Jae-Hong (pyrasis)
Maintainer of tizen port.
localStorageGetItem crashes when column text is NULL.
fix image bug on Android
lumendes
Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386.
@ -729,6 +730,9 @@ Developers:
pandamicro
Exposed SAXParser to JS, it is used for parsing XML in JS.
hanjukim
Fixed a bug that color and opacity settings were not applied when invoking Label::alignText.
Retired Core Developers:
WenSheng Yang

View File

@ -12,16 +12,19 @@ cocos2d-x-3.0beta2 ?.? ?
[NEW] Renderer: Added BatchCommand. This command is not "batchable" with other commands, but improves performance in about 10%
[NEW] LuaBindings: Bindings-generator supports to bind namespace for lua.
[FIX] Uses EventDispatcher to access event in LUA testcase.
[FIX] Exposes SAXParser class to JS, it is used for parsing XML in JS.
[FIX] Uses unified `desktop/CCEGLView.h/cpp` for desktop platforms (windows, mac, linux).
[FIX] Bindings-generator supports Windows again and remove dependency of LLVM since we only need binary(libclang.so/dll).
[FIX] Removes unused files for MAC platform after using glfw3 to create opengl context.
[FIX] Wrong arithmetic of child's position in ParallaxNode::addChild()
[FIX] CocoStudio: TestColliderDetector in ArmatureTest can't work.
[FIX] CocoStudio: The order of transform calculation in Skin::getNodeToWorldTransform() is incorrect.
[FIX] Crash if file doesn't exist when using FileUtils::getStringFromFile.
[FIX] If setting a shorter string than before while using LabelAtlas, the effect will be wrong.
[FIX] Label: Crash when using unknown characters.
[FIX] Label: Missing line breaks and wrong alignment.
[FIX] Label: Color and opacity settings aren't applied when invoking Label::alignText.
[FIX] Console: log(format, va_args) is private to prevent possible resolution errors
[FIX] Configuration: dumpInfo() -> getInfo()
[FIX] ControlSlider doesn't support to set selected thumb sprite.

View File

@ -1 +1 @@
72b2e67ce3473ec4d8adf2412a9ce1d9390e0882
c6e696abdf3766882e2926f4366f33e849b8fc90

View File

@ -152,7 +152,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
tempDef.width = tempRect.size.width + _letterPadding;
tempDef.height = tempRect.size.height + _letterPadding;
tempDef.offsetX = tempRect.origin.x + offsetAdjust;
tempDef.offsetY = tempRect.origin.y - offsetAdjust;
tempDef.offsetY = _commonLineHeight + tempRect.origin.y - offsetAdjust;
}
fontDefs[utf16String[i]] = tempDef;
}
@ -238,4 +238,4 @@ const Font * FontAtlas::getFont() const
return _font;
}
NS_CC_END
NS_CC_END

View File

@ -471,6 +471,8 @@ void Label::alignText()
insertQuadFromSprite(_reusedLetter,vaildIndex++);
}
}
updateColor();
}
bool Label::computeHorizontalKernings(unsigned short int *stringToRender)

View File

@ -335,7 +335,14 @@ bool LabelTextFormatter::createStringSprites(Label *theLabel)
// If the last character processed has an xAdvance which is less that the width of the characters image, then we need
// to adjust the width of the string to take this into account, or the character will overlap the end of the bounding
// box
tmpSize.width = longestLine - charAdvance + lastCharWidth;
if(charAdvance < lastCharWidth)
{
tmpSize.width = longestLine - charAdvance + lastCharWidth;
}
else
{
tmpSize.width = longestLine;
}
tmpSize.height = totalHeight;
theLabel->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize));

View File

@ -290,7 +290,7 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type)
break;
case kShaderType_PositionTextureColorAlphaTest:
p->initWithVertexShaderByteArray(ccPositionTextureColor_noMVP_vert, ccPositionTextureColorAlphaTest_frag);
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);
p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);

View File

@ -250,8 +250,9 @@ public:
inline void setStoringCharacters(bool storingCharacters) { _storingCharacters = storingCharacters; };
/// properties
inline ValueMap getProperties() const { return _properties; };
inline void setProperties(ValueMap properties) {
inline const ValueMap& getProperties() const { return _properties; }
inline ValueMap& getProperties() { return _properties; }
inline void setProperties(const ValueMap& properties) {
_properties = properties;
};

View File

@ -107,9 +107,9 @@ Color4B::Color4B(GLubyte _r, GLubyte _g, GLubyte _b, GLubyte _a)
{}
Color4B::Color4B(const Color3B& color)
: r(color.r * 255)
, g(color.g * 255)
, b(color.b * 255)
: r(color.r)
, g(color.g)
, b(color.b)
, a(255)
{}

View File

@ -28,14 +28,20 @@ THE SOFTWARE.
NS_CC_BEGIN
AutoreleasePool::AutoreleasePool()
:_name("")
: _name("")
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
, _isClearing(false)
#endif
{
_managedObjectArray.reserve(150);
PoolManager::getInstance()->push(this);
}
AutoreleasePool::AutoreleasePool(const std::string &name)
:_name(name)
: _name(name)
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
, _isClearing(false)
#endif
{
_managedObjectArray.reserve(150);
PoolManager::getInstance()->push(this);
@ -56,11 +62,27 @@ void AutoreleasePool::addObject(Object* object)
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
for (const auto &obj : _managedObjectArray)
{
obj->release();
}
_managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}
bool AutoreleasePool::contains(Object* object) const
{
for (const auto& obj : _managedObjectArray)
{
if (obj == object)
return true;
}
return false;
}
void AutoreleasePool::dump()
@ -89,7 +111,7 @@ PoolManager* PoolManager::getInstance()
s_singleInstance = new PoolManager();
// Add the first auto release pool
s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool");
s_singleInstance->_releasePoolStack.push(s_singleInstance->_curReleasePool);
s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool);
}
return s_singleInstance;
}
@ -110,8 +132,8 @@ PoolManager::~PoolManager()
while (!_releasePoolStack.empty())
{
AutoreleasePool* pool = _releasePoolStack.top();
_releasePoolStack.pop();
AutoreleasePool* pool = _releasePoolStack.back();
_releasePoolStack.pop_back();
delete pool;
}
@ -123,9 +145,19 @@ AutoreleasePool* PoolManager::getCurrentPool() const
return _curReleasePool;
}
bool PoolManager::isObjectInPools(Object* obj) const
{
for (const auto& pool : _releasePoolStack)
{
if (pool->contains(obj))
return true;
}
return false;
}
void PoolManager::push(AutoreleasePool *pool)
{
_releasePoolStack.push(pool);
_releasePoolStack.push_back(pool);
_curReleasePool = pool;
}
@ -134,12 +166,12 @@ void PoolManager::pop()
// Can not pop the pool that created by engine
CC_ASSERT(_releasePoolStack.size() >= 1);
_releasePoolStack.pop();
_releasePoolStack.pop_back();
// Should update _curReleasePool if a temple pool is released
if (_releasePoolStack.size() > 1)
{
_curReleasePool = _releasePoolStack.top();
_curReleasePool = _releasePoolStack.back();
}
}

View File

@ -81,6 +81,18 @@ public:
*/
void clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
/**
* Whether the pool is doing `clear` operation.
*/
bool isClearing() const { return _isClearing; };
#endif
/**
* Checks whether the pool contains the specified object.
*/
bool contains(Object* object) const;
/**
* Dump the objects that are put into autorelease pool. It is used for debugging.
*
@ -102,6 +114,13 @@ private:
*/
std::vector<Object*> _managedObjectArray;
std::string _name;
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
/**
* The flag for checking whether the pool is doing `clear` operation.
*/
bool _isClearing;
#endif
};
class CC_DLL PoolManager
@ -127,6 +146,8 @@ public:
*/
AutoreleasePool *getCurrentPool() const;
bool isObjectInPools(Object* obj) const;
/**
* @js NA
* @lua NA
@ -142,7 +163,7 @@ private:
static PoolManager* s_singleInstance;
std::stack<AutoreleasePool*> _releasePoolStack;
std::deque<AutoreleasePool*> _releasePoolStack;
AutoreleasePool *_curReleasePool;
};

View File

@ -63,6 +63,52 @@ Object* Object::autorelease()
return this;
}
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
void Object::release()
{
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
auto poolManager = PoolManager::getInstance();
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
{
// Trigger an assert if the reference count is 0 but the object is still in autorelease pool.
// This happens when 'autorelease/release' were not used in pairs with 'new/retain'.
//
// Wrong usage (1):
//
// auto obj = Node::create(); // Ref = 1, but it's an autorelease object which means it was in the autorelease pool.
// obj->autorelease(); // Wrong: If you wish to invoke autorelease several times, you should retain `obj` first.
//
// Wrong usage (2):
//
// auto obj = Node::create();
// obj->release(); // Wrong: obj is an autorelease object, it will be released when clearing current pool.
//
// Correct usage (1):
//
// auto obj = Node::create();
// |- new Node(); // `new` is the pair of the `autorelease` of next line
// |- autorelease(); // The pair of `new Node`.
//
// obj->retain();
// obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line.
//
// Correct usage (2):
//
// auto obj = Node::create();
// obj->retain();
// obj->release(); // This `release` is the pair of `retain` of previous line.
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
}
delete this;
}
}
#endif
bool Object::isSingleReference() const
{
return _referenceCount == 1;

View File

@ -103,15 +103,16 @@ public:
* @see retain, autorelease
* @js NA
*/
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
void release();
#else
inline void release()
{
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
--_referenceCount;
if (_referenceCount == 0)
delete this;
}
#endif
/**
* Retains the ownership.
*

View File

@ -144,10 +144,10 @@ Node* SceneReader::createObject(const rapidjson::Value &dict, cocos2d::Node* par
{
gb->addComponent(com);
}
else
{
CC_SAFE_RELEASE_NULL(com);
}
else
{
com = nullptr;
}
}
if(_fnSelector != nullptr)
{

View File

@ -216,7 +216,7 @@ kmMat4 Skin::getNodeToWorldTransformAR() const
displayTransform.mat[12] = anchorPoint.x;
displayTransform.mat[13] = anchorPoint.y;
return TransformConcat(displayTransform, _bone->getArmature()->getNodeToWorldTransform());
return TransformConcat( _bone->getArmature()->getNodeToWorldTransform(),displayTransform);
}
void Skin::draw()

View File

@ -178,7 +178,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
CCASSERT(con != nullptr, "");
con->serialize(subDict);
con->init();
con->autorelease();
_cons.pushBack(con);
}
@ -199,7 +198,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
}
act->serialize(subDict);
act->init();
act->autorelease();
_acts.pushBack(act);
}

@ -1 +1 @@
Subproject commit 37451f4ec2e2d01da9286ae97952582b81d02be8
Subproject commit e8828b9aa8b1bfdf08bc3c077ec2cc1ebd9b9c82

View File

@ -37,7 +37,25 @@ LOCAL_SRC_FILES := CCLuaBridge.cpp \
../../../../external/lua/tolua/tolua_map.c \
../../../../external/lua/tolua/tolua_push.c \
../../../../external/lua/tolua/tolua_to.c \
tolua_fix.c
tolua_fix.c \
socket/auxiliar.c \
socket/luasocket_buffer.c \
socket/except.c \
socket/inet.c \
socket/luasocket_io.c \
socket/luasocket.c \
socket/mime.c \
socket/options.c \
socket/select.c \
socket/serial.c \
socket/socket_scripts.c \
socket/tcp.c \
socket/timeout.c \
socket/udp.c \
socket/unix.c \
socket/usocket.c \
lua_extensions.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../external/lua/tolua \
$(LOCAL_PATH)/../../auto-generated/lua-bindings \

View File

@ -31,6 +31,9 @@ extern "C" {
#include "lualib.h"
#include "lauxlib.h"
#include "tolua_fix.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "lua_extensions.h"
#endif
}
#include "Cocos2dxLuaLoader.h"
@ -146,6 +149,9 @@ bool LuaStack::init(void)
{NULL, NULL}
};
luaL_register(_state, "_G", global_functions);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
luaopen_lua_extensions(_state);
#endif
g_luaType.clear();
register_all_cocos2dx(_state);
register_all_cocos2dx_extension(_state);

View File

@ -1071,7 +1071,7 @@ bool luavals_variadic_to_array(lua_State* L,int argc, Array** ret)
else if (lua_isuserdata(L, i + 2))
{
tolua_Error err;
if (!tolua_isusertype(L, i + 2, "Object", 0, &err))
if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err))
{
#if COCOS2D_DEBUG >=1
luaval_to_native_err(L,"#ferror:",&err);

View File

@ -88,7 +88,7 @@ bool luavals_variadic_to_ccvector( lua_State* L, int argc, cocos2d::Vector<T>* r
{
tolua_Error err;
//Undo check
if (!tolua_isusertype(L, i + 2, "Object", 0, &err))
if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err))
{
ok = false;
break;

View File

@ -0,0 +1,37 @@
#include "lua_extensions.h"
#if __cplusplus
extern "C" {
#endif
// socket
#include "socket/luasocket.h"
#include "socket/mime.h"
#include "socket/socket_scripts.h"
static luaL_Reg luax_exts[] = {
{"socket.core", luaopen_socket_core},
{"mime.core", luaopen_mime_core},
{NULL, NULL}
};
void luaopen_lua_extensions(lua_State *L)
{
// load extensions
luaL_Reg* lib = luax_exts;
lua_getglobal(L, "package");
lua_getfield(L, -1, "preload");
for (; lib->func; lib++)
{
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 2);
// load extensions script
luaopen_socket_scripts(L);
}
#if __cplusplus
} // extern "C"
#endif

View File

@ -0,0 +1,23 @@
#ifndef __LUA_EXTRA_H_
#define __LUA_EXTRA_H_
#if defined(_USRDLL)
#define LUA_EXTENSIONS_DLL __declspec(dllexport)
#else /* use a DLL library */
#define LUA_EXTENSIONS_DLL
#endif
#if __cplusplus
extern "C" {
#endif
#include "lauxlib.h"
void LUA_EXTENSIONS_DLL luaopen_lua_extensions(lua_State *L);
#if __cplusplus
}
#endif
#endif /* __LUA_EXTRA_H_ */

View File

@ -0,0 +1,158 @@
/*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include <stdio.h>
#include "auxiliar.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes the module
\*-------------------------------------------------------------------------*/
int auxiliar_open(lua_State *L) {
(void) L;
return 0;
}
/*-------------------------------------------------------------------------*\
* Creates a new class with given methods
* Methods whose names start with __ are passed directly to the metatable.
\*-------------------------------------------------------------------------*/
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
luaL_newmetatable(L, classname); /* mt */
/* create __index table to place methods */
lua_pushstring(L, "__index"); /* mt,"__index" */
lua_newtable(L); /* mt,"__index",it */
/* put class name into class metatable */
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
lua_rawset(L, -3); /* mt,"__index",it */
/* pass all methods that start with _ to the metatable, and all others
* to the index table */
for (; func->name; func++) { /* mt,"__index",it */
lua_pushstring(L, func->name);
lua_pushcfunction(L, func->func);
lua_rawset(L, func->name[0] == '_' ? -5: -3);
}
lua_rawset(L, -3); /* mt */
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Prints the value of a class in a nice way
\*-------------------------------------------------------------------------*/
int auxiliar_tostring(lua_State *L) {
char buf[32];
if (!lua_getmetatable(L, 1)) goto error;
lua_pushstring(L, "__index");
lua_gettable(L, -2);
if (!lua_istable(L, -1)) goto error;
lua_pushstring(L, "class");
lua_gettable(L, -2);
if (!lua_isstring(L, -1)) goto error;
sprintf(buf, "%p", lua_touserdata(L, 1));
lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
return 1;
error:
lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
lua_error(L);
return 1;
}
/*-------------------------------------------------------------------------*\
* Insert class into group
\*-------------------------------------------------------------------------*/
void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) {
luaL_getmetatable(L, classname);
lua_pushstring(L, groupname);
lua_pushboolean(L, 1);
lua_rawset(L, -3);
lua_pop(L, 1);
}
/*-------------------------------------------------------------------------*\
* Make sure argument is a boolean
\*-------------------------------------------------------------------------*/
int auxiliar_checkboolean(lua_State *L, int objidx) {
if (!lua_isboolean(L, objidx))
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
return lua_toboolean(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given class, abort with
* error otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
void *data = auxiliar_getclassudata(L, classname, objidx);
if (!data) {
char msg[45];
sprintf(msg, "%.35s expected", classname);
luaL_argerror(L, objidx, msg);
}
return data;
}
/*-------------------------------------------------------------------------*\
* Return userdata pointer if object belongs to a given group, abort with
* error otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
void *data = auxiliar_getgroupudata(L, groupname, objidx);
if (!data) {
char msg[45];
sprintf(msg, "%.35s expected", groupname);
luaL_argerror(L, objidx, msg);
}
return data;
}
/*-------------------------------------------------------------------------*\
* Set object class
\*-------------------------------------------------------------------------*/
void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
luaL_getmetatable(L, classname);
if (objidx < 0) objidx--;
lua_setmetatable(L, objidx);
}
/*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given group. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
if (!lua_getmetatable(L, objidx))
return NULL;
lua_pushstring(L, groupname);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 2);
return NULL;
} else {
lua_pop(L, 2);
return lua_touserdata(L, objidx);
}
}
/*-------------------------------------------------------------------------*\
* Get a userdata pointer if object belongs to a given class. Return NULL
* otherwise
\*-------------------------------------------------------------------------*/
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
return luaL_checkudata(L, objidx, classname);
}
/*-------------------------------------------------------------------------*\
* Throws error when argument does not have correct type.
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
\*-------------------------------------------------------------------------*/
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}

View File

@ -0,0 +1,47 @@
#ifndef AUXILIAR_H
#define AUXILIAR_H
/*=========================================================================*\
* Auxiliar routines for class hierarchy manipulation
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
*
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
* group is a name associated with a class. A class can belong to any number
* of groups. This module provides the functionality to:
*
* - create new classes
* - add classes to groups
* - set the class of objects
* - check if an object belongs to a given class or group
* - get the userdata associated to objects
* - print objects in a pretty way
*
* LuaSocket class names follow the convention <module>{<class>}. Modules
* can define any number of classes and groups. The module tcp.c, for
* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
* the groups tcp{client,server} and tcp{any}. Module functions can then
* perform type-checking on their arguments by either class or group.
*
* LuaSocket metatables define the __index metamethod as being a table. This
* table has one field for each method supported by the class, and a field
* "class" with the class name.
*
* The mapping from class name to the corresponding metatable and the
* reverse mapping are done using lauxlib.
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
int auxiliar_open(lua_State *L);
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
int auxiliar_checkboolean(lua_State *L, int objidx);
int auxiliar_tostring(lua_State *L);
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
#endif /* AUXILIAR_H */

View File

@ -0,0 +1,97 @@
/*=========================================================================*\
* Simple exception support
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "except.h"
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static int global_protect(lua_State *L);
static int global_newtry(lua_State *L);
static int protected_(lua_State *L);
static int finalize(lua_State *L);
static int do_nothing(lua_State *L);
/* except functions */
static luaL_Reg func[] = {
{"newtry", global_newtry},
{"protect", global_protect},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Try factory
\*-------------------------------------------------------------------------*/
static void wrap(lua_State *L) {
lua_newtable(L);
lua_pushnumber(L, 1);
lua_pushvalue(L, -3);
lua_settable(L, -3);
lua_insert(L, -2);
lua_pop(L, 1);
}
static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, 0);
lua_settop(L, 2);
wrap(L);
lua_error(L);
return 0;
} else return lua_gettop(L);
}
static int do_nothing(lua_State *L) {
(void) L;
return 0;
}
static int global_newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Protect factory
\*-------------------------------------------------------------------------*/
static int unwrap(lua_State *L) {
if (lua_istable(L, -1)) {
lua_pushnumber(L, 1);
lua_gettable(L, -2);
lua_pushnil(L);
lua_insert(L, -2);
return 1;
} else return 0;
}
static int protected_(lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
if (unwrap(L)) return 2;
else lua_error(L);
return 0;
} else return lua_gettop(L);
}
static int global_protect(lua_State *L) {
lua_pushcclosure(L, protected_, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Init module
\*-------------------------------------------------------------------------*/
int except_open(lua_State *L) {
luaL_openlib(L, NULL, func, 0);
return 0;
}

View File

@ -0,0 +1,33 @@
#ifndef EXCEPT_H
#define EXCEPT_H
/*=========================================================================*\
* Exception control
* LuaSocket toolkit (but completely independent from other modules)
*
* This provides support for simple exceptions in Lua. During the
* development of the HTTP/FTP/SMTP support, it became aparent that
* error checking was taking a substantial amount of the coding. These
* function greatly simplify the task of checking errors.
*
* The main idea is that functions should return nil as its first return
* value when it finds an error, and return an error message (or value)
* following nil. In case of success, as long as the first value is not nil,
* the other values don't matter.
*
* The idea is to nest function calls with the "try" function. This function
* checks the first value, and calls "error" on the second if the first is
* nil. Otherwise, it returns all values it received.
*
* The protect function returns a new function that behaves exactly like the
* function it receives, but the new function doesn't throw exceptions: it
* returns nil followed by the error message instead.
*
* With these two function, it's easy to write functions that throw
* exceptions on error, but that don't interrupt the user script.
\*=========================================================================*/
#include "lua.h"
int except_open(lua_State *L);
#endif

View File

@ -0,0 +1,528 @@
/*=========================================================================*\
* Internet domain functions
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "inet.h"
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static int inet_global_toip(lua_State *L);
static int inet_global_getaddrinfo(lua_State *L);
static int inet_global_tohostname(lua_State *L);
static int inet_global_getnameinfo(lua_State *L);
static void inet_pushresolved(lua_State *L, struct hostent *hp);
static int inet_global_gethostname(lua_State *L);
/* DNS functions */
static luaL_Reg func[] = {
{ "toip", inet_global_toip},
{ "getaddrinfo", inet_global_getaddrinfo},
{ "tohostname", inet_global_tohostname},
{ "getnameinfo", inet_global_getnameinfo},
{ "gethostname", inet_global_gethostname},
{ NULL, NULL}
};
#ifdef _WINDOWS_
/****luodx patch for windows xp start**/
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length)
{
char* result = inet_ntoa(*(IN_ADDR*)src);
if (result != NULL){
strcpy(dest, result);
}
return result;
}
int win32xp_inet_pton(int family, const char* string, PVOID dest) {
return inet_aton(string, (IN_ADDR*)dest);
}
/****luodx patch for windows xp end**/
#endif
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int inet_open(lua_State *L)
{
lua_pushstring(L, "dns");
lua_newtable(L);
luaL_openlib(L, NULL, func, 0);
lua_settable(L, -3);
return 0;
}
/*=========================================================================*\
* Global Lua functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name
* or ip address
\*-------------------------------------------------------------------------*/
static int inet_gethost(const char *address, struct hostent **hp) {
struct in_addr addr;
if (inet_aton(address, &addr))
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
else
return socket_gethostbyname(address, hp);
}
/*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name
* or ip address
\*-------------------------------------------------------------------------*/
static int inet_global_tohostname(lua_State *L) {
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_hoststrerror(err));
return 2;
}
lua_pushstring(L, hp->h_name);
inet_pushresolved(L, hp);
return 2;
}
static int inet_global_getnameinfo(lua_State *L) {
int i, ret;
char host[1024];
char serv[32];
struct addrinfo hints;
struct addrinfo *resolved, *iter;
const char *node = luaL_optstring(L, 1, NULL);
const char *service = luaL_optstring(L, 2, NULL);
if (!(node || service))
luaL_error(L, "You have to specify a hostname, a service, or both");
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
/* getaddrinfo must get a node and a service argument */
ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7",
&hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host,
node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0);
if (node) {
lua_pushnumber(L, i);
lua_pushstring(L, host);
lua_settable(L, -3);
}
}
freeaddrinfo(resolved);
if (service) {
lua_pushstring(L, serv);
return 2;
} else {
return 1;
}
}
/*-------------------------------------------------------------------------*\
* Returns all information provided by the resolver given a host name
* or ip address
\*-------------------------------------------------------------------------*/
static int inet_global_toip(lua_State *L)
{
const char *address = luaL_checkstring(L, 1);
struct hostent *hp = NULL;
int err = inet_gethost(address, &hp);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_hoststrerror(err));
return 2;
}
lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
inet_pushresolved(L, hp);
return 2;
}
int inet_optfamily(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
int inet_optsocktype(lua_State* L, int narg, const char* def)
{
static const char* optname[] = { "stream", "dgram", NULL };
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
return optvalue[luaL_checkoption(L, narg, def, optname)];
}
static int inet_global_getaddrinfo(lua_State *L)
{
const char *hostname = luaL_checkstring(L, 1);
struct addrinfo *iterator = NULL, *resolved = NULL;
struct addrinfo hints;
int i = 1, ret = 0;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = PF_UNSPEC;
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
if (ret != 0) {
lua_pushnil(L);
lua_pushstring(L, socket_gaistrerror(ret));
return 2;
}
lua_newtable(L);
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf,
(socklen_t) sizeof(hbuf), sbuf, 0, NI_NUMERICHOST);
lua_pushnumber(L, i);
lua_newtable(L);
switch (iterator->ai_family) {
case AF_INET:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet");
lua_settable(L, -3);
break;
case AF_INET6:
lua_pushliteral(L, "family");
lua_pushliteral(L, "inet6");
lua_settable(L, -3);
break;;
}
lua_pushliteral(L, "addr");
lua_pushstring(L, hbuf);
lua_settable(L, -3);
lua_settable(L, -3);
i++;
}
freeaddrinfo(resolved);
return 1;
}
/*-------------------------------------------------------------------------*\
* Gets the host name
\*-------------------------------------------------------------------------*/
static int inet_global_gethostname(lua_State *L)
{
char name[257];
name[256] = '\0';
if (gethostname(name, 256) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
lua_pushstring(L, name);
return 1;
}
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Retrieves socket peer name
\*-------------------------------------------------------------------------*/
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
{
switch (family) {
case PF_INET: {
struct sockaddr_in peer;
socklen_t peer_len = sizeof(peer);
char name[INET_ADDRSTRLEN];
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
my_inet_ntop(family, &peer.sin_addr, name, sizeof(name));
lua_pushstring(L, name);
lua_pushnumber(L, ntohs(peer.sin_port));
lua_pushliteral(L, "inet");
return 3;
}
}
case PF_INET6: {
struct sockaddr_in6 peer;
socklen_t peer_len = sizeof(peer);
char name[INET6_ADDRSTRLEN];
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
my_inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
lua_pushstring(L, name);
lua_pushnumber(L, ntohs(peer.sin6_port));
lua_pushliteral(L, "inet6");
return 3;
}
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", family);
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Retrieves socket local name
\*-------------------------------------------------------------------------*/
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
{
switch (family) {
case PF_INET: {
struct sockaddr_in local;
socklen_t local_len = sizeof(local);
char name[INET_ADDRSTRLEN];
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
my_inet_ntop(family, &local.sin_addr, name, sizeof(name));
lua_pushstring(L, name);
lua_pushnumber(L, ntohs(local.sin_port));
lua_pushliteral(L, "inet");
return 3;
}
}
case PF_INET6: {
struct sockaddr_in6 local;
socklen_t local_len = sizeof(local);
char name[INET6_ADDRSTRLEN];
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
my_inet_ntop(family, &local.sin6_addr, name, sizeof(name));
lua_pushstring(L, name);
lua_pushnumber(L, ntohs(local.sin6_port));
lua_pushliteral(L, "inet6");
return 3;
}
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", family);
return 2;
}
}
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Passes all resolver information to Lua as a table
\*-------------------------------------------------------------------------*/
static void inet_pushresolved(lua_State *L, struct hostent *hp)
{
char **alias;
struct in_addr **addr;
int i, resolved;
lua_newtable(L); resolved = lua_gettop(L);
lua_pushstring(L, "name");
lua_pushstring(L, hp->h_name);
lua_settable(L, resolved);
lua_pushstring(L, "ip");
lua_pushstring(L, "alias");
i = 1;
alias = hp->h_aliases;
lua_newtable(L);
if (alias) {
while (*alias) {
lua_pushnumber(L, i);
lua_pushstring(L, *alias);
lua_settable(L, -3);
i++; alias++;
}
}
lua_settable(L, resolved);
i = 1;
lua_newtable(L);
addr = (struct in_addr **) hp->h_addr_list;
if (addr) {
while (*addr) {
lua_pushnumber(L, i);
lua_pushstring(L, inet_ntoa(**addr));
lua_settable(L, -3);
i++; addr++;
}
}
lua_settable(L, resolved);
}
/*-------------------------------------------------------------------------*\
* Tries to create a new inet socket
\*-------------------------------------------------------------------------*/
const char *inet_trycreate(p_socket ps, int family, int type) {
return socket_strerror(socket_create(ps, family, type, 0));
}
/*-------------------------------------------------------------------------*\
* "Disconnects" a DGRAM socket
\*-------------------------------------------------------------------------*/
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
{
switch (family) {
case PF_INET: {
struct sockaddr_in sin;
memset((char *) &sin, 0, sizeof(sin));
sin.sin_family = AF_UNSPEC;
sin.sin_addr.s_addr = INADDR_ANY;
return socket_strerror(socket_connect(ps, (SA *) &sin,
sizeof(sin), tm));
}
case PF_INET6: {
struct sockaddr_in6 sin6;
struct in6_addr addrany = IN6ADDR_ANY_INIT;
memset((char *) &sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_UNSPEC;
fprintf(stderr, "disconnecting\n");
sin6.sin6_addr = addrany;
return socket_strerror(socket_connect(ps, (SA *) &sin6,
sizeof(sin6), tm));
}
}
return NULL;
}
/*-------------------------------------------------------------------------*\
* Tries to connect to remote address (address, port)
\*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_socket ps, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints)
{
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
timeout_markstart(tm);
/* try connecting to remote address */
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
/*-------------------------------------------------------------------------*\
* Tries to accept a socket
\*-------------------------------------------------------------------------*/
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm)
{
socklen_t len;
t_sockaddr_storage addr;
if (family == PF_INET6) {
len = sizeof(struct sockaddr_in6);
} else {
len = sizeof(struct sockaddr_in);
}
return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm));
}
/*-------------------------------------------------------------------------*\
* Tries to bind socket to (address, port)
\*-------------------------------------------------------------------------*/
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints)
{
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
t_socket sock = *ps;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
if (err) {
if (resolved) freeaddrinfo(resolved);
return err;
}
/* iterate over resolved addresses until one is good */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
if(sock == SOCKET_INVALID) {
err = socket_strerror(socket_create(&sock, iterator->ai_family,
iterator->ai_socktype, iterator->ai_protocol));
if(err)
continue;
}
/* try binding to local address */
err = socket_strerror(socket_bind(&sock,
(SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen));
/* keep trying unless bind succeeded */
if (err) {
if(sock != *ps)
socket_destroy(&sock);
} else {
/* remember what we connected to, particularly the family */
*bindhints = *iterator;
break;
}
}
/* cleanup and return error */
freeaddrinfo(resolved);
*ps = sock;
return err;
}
/*-------------------------------------------------------------------------*\
* Some systems do not provide this so that we provide our own. It's not
* marvelously fast, but it works just fine.
\*-------------------------------------------------------------------------*/
#ifdef INET_ATON
int inet_aton(const char *cp, struct in_addr *inp)
{
unsigned int a = 0, b = 0, c = 0, d = 0;
int n = 0, r;
unsigned long int addr = 0;
r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
if (r == 0 || n == 0) return 0;
cp += n;
if (*cp) return 0;
if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
if (inp) {
addr += a; addr <<= 8;
addr += b; addr <<= 8;
addr += c; addr <<= 8;
addr += d;
inp->s_addr = htonl(addr);
}
return 1;
}
#endif

View File

@ -0,0 +1,56 @@
#ifndef INET_H
#define INET_H
/*=========================================================================*\
* Internet domain functions
* LuaSocket toolkit
*
* This module implements the creation and connection of internet domain
* sockets, on top of the socket.h interface, and the interface of with the
* resolver.
*
* The function inet_aton is provided for the platforms where it is not
* available. The module also implements the interface of the internet
* getpeername and getsockname functions as seen by Lua programs.
*
* The Lua functions toip and tohostname are also implemented here.
\*=========================================================================*/
#include "lua.h"
#include "socket.h"
#include "timeout.h"
#ifdef _WIN32
#define INET_ATON
#endif
int inet_open(lua_State *L);
const char *inet_trycreate(p_socket ps, int family, int type);
const char *inet_tryconnect(p_socket ps, const char *address,
const char *serv, p_timeout tm, struct addrinfo *connecthints);
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints);
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
int inet_optfamily(lua_State* L, int narg, const char* def);
int inet_optsocktype(lua_State* L, int narg, const char* def);
#ifdef INET_ATON
int inet_aton(const char *cp, struct in_addr *inp);
#endif
#ifndef _WINDOWS_
#define my_inet_ntop(a,b,c,d) inet_ntop(a,b,c,d)
#define my_inet_pton(a,b,c) inet_pton(a,b,c)
#else
int win32xp_inet_pton(int family, const char* string, PVOID dest);
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length);
#define my_inet_ntop(a,b,c,d) win32xp_inet_ntop(a,b,c,d)
#define my_inet_pton(a,b,c) win32xp_inet_pton(a,b,c)
#endif
#endif /* INET_H */

View File

@ -0,0 +1,116 @@
/*=========================================================================*\
* LuaSocket toolkit
* Networking support for the Lua language
* Diego Nehab
* 26/11/1999
*
* This library is part of an effort to progressively increase the network
* connectivity of the Lua language. The Lua interface to networking
* functions follows the Sockets API closely, trying to simplify all tasks
* involved in setting up both client and server connections. The provided
* IO routines, however, follow the Lua style, being very similar to the
* standard Lua read and write functions.
\*=========================================================================*/
/*=========================================================================*\
* Standard include files
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
/*=========================================================================*\
* LuaSocket includes
\*=========================================================================*/
#include "luasocket.h"
#include "auxiliar.h"
#include "except.h"
#include "timeout.h"
#include "luasocket_buffer.h"
#include "inet.h"
#include "tcp.h"
#include "udp.h"
#include "select.h"
/*-------------------------------------------------------------------------*\
* Internal function prototypes
\*-------------------------------------------------------------------------*/
static int global_skip(lua_State *L);
static int global_unload(lua_State *L);
static int base_open(lua_State *L);
/*-------------------------------------------------------------------------*\
* Modules and functions
\*-------------------------------------------------------------------------*/
static const luaL_Reg mod[] = {
{"auxiliar", auxiliar_open},
{"except", except_open},
{"timeout", timeout_open},
{"buffer", buffer_open},
{"inet", inet_open},
{"tcp", tcp_open},
{"udp", udp_open},
{"select", select_open},
{NULL, NULL}
};
static luaL_Reg func[] = {
{"skip", global_skip},
{"__unload", global_unload},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Skip a few arguments
\*-------------------------------------------------------------------------*/
static int global_skip(lua_State *L) {
int amount = luaL_checkint(L, 1);
int ret = lua_gettop(L) - amount - 1;
return ret >= 0 ? ret : 0;
}
/*-------------------------------------------------------------------------*\
* Unloads the library
\*-------------------------------------------------------------------------*/
static int global_unload(lua_State *L) {
(void) L;
socket_close();
return 0;
}
/*-------------------------------------------------------------------------*\
* Setup basic stuff.
\*-------------------------------------------------------------------------*/
static int base_open(lua_State *L) {
if (socket_open()) {
/* export functions (and leave namespace table on top of stack) */
luaL_openlib(L, "socket", func, 0);
#ifdef LUASOCKET_DEBUG
lua_pushstring(L, "_DEBUG");
lua_pushboolean(L, 1);
lua_rawset(L, -3);
#endif
/* make version string available to scripts */
lua_pushstring(L, "_VERSION");
lua_pushstring(L, LUASOCKET_VERSION);
lua_rawset(L, -3);
return 1;
} else {
lua_pushstring(L, "unable to initialize library");
lua_error(L);
return 0;
}
}
/*-------------------------------------------------------------------------*\
* Initializes all library modules.
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socket_core(lua_State *L) {
int i;
base_open(L);
for (i = 0; mod[i].name; i++) mod[i].func(L);
return 1;
}

View File

@ -0,0 +1,34 @@
#ifndef LUASOCKET_H
#define LUASOCKET_H
/*=========================================================================*\
* LuaSocket toolkit
* Networking support for the Lua language
* Diego Nehab
* 9/11/1999
\*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\
* Current socket library version
\*-------------------------------------------------------------------------*/
#define LUASOCKET_VERSION "LuaSocket 2.1-rc1"
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2012 Diego Nehab"
#define LUASOCKET_AUTHORS "Diego Nehab"
/*-------------------------------------------------------------------------*\
* This macro prefixes all exported API functions
\*-------------------------------------------------------------------------*/
#ifndef LUASOCKET_API
#define LUASOCKET_API extern
#endif
#if LUA_VERSION_NUM > 501 & !( defined LUA_COMPAT_MODULE)
# error Lua 5.2 requires LUA_COMPAT_MODULE defined for luaL_openlib
#endif
/*-------------------------------------------------------------------------*\
* Initializes the library.
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socket_core(lua_State *L);
#endif /* LUASOCKET_H */

View File

@ -0,0 +1,276 @@
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
\*=========================================================================*/
#include "lua.h"
#include "lauxlib.h"
#include "luasocket_buffer.h"
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
static int recvline(p_buffer buf, luaL_Buffer *b);
static int recvall(p_buffer buf, luaL_Buffer *b);
static int buffer_get(p_buffer buf, const char **data, size_t *count);
static void buffer_skip(p_buffer buf, size_t count);
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int buffer_open(lua_State *L) {
(void) L;
return 0;
}
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
buf->received = buf->sent = 0;
buf->birthday = timeout_gettime();
}
/*-------------------------------------------------------------------------*\
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
lua_pushnumber(L, (lua_Number) buf->received);
lua_pushnumber(L, (lua_Number) buf->sent);
lua_pushnumber(L, timeout_gettime() - buf->birthday);
return 3;
}
/*-------------------------------------------------------------------------*\
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* object:send() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_send(lua_State *L, p_buffer buf) {
int top = lua_gettop(L);
int err = IO_DONE;
size_t size = 0, sent = 0;
const char *data = luaL_checklstring(L, 2, &size);
long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1;
if (end > (long) size) end = (long) size;
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
/* check if there was an error */
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushnumber(L, (lua_Number) (sent+start-1));
} else {
lua_pushnumber(L, (lua_Number) (sent+start-1));
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* object:receive() interface
\*-------------------------------------------------------------------------*/
int buffer_meth_receive(lua_State *L, p_buffer buf) {
int err = IO_DONE, top = lua_gettop(L);
luaL_Buffer b;
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
#ifdef LUASOCKET_DEBUG
p_timeout tm = timeout_markstart(buf->tm);
#endif
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
luaL_addlstring(&b, part, size);
/* receive new patterns */
if (!lua_isnumber(L, 2)) {
const char *p= luaL_optstring(L, 2, "*l");
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes (minus what was already partially
* received) */
} else {
double n = lua_tonumber(L, 2);
size_t wanted = (size_t) n;
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
if (size == 0 || wanted > size)
err = recvraw(buf, wanted-size, &b);
}
/* check if there was an error */
if (err != IO_DONE) {
/* we can't push anyting in the stack before pushing the
* contents of the buffer. this is the reason for the complication */
luaL_pushresult(&b);
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2);
lua_pushnil(L);
lua_replace(L, -4);
} else {
luaL_pushresult(&b);
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
/* push time elapsed during operation as the last return value */
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* Determines if there is any data in the read buffer
\*-------------------------------------------------------------------------*/
int buffer_isempty(p_buffer buf) {
return buf->first >= buf->last;
}
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Sends a block of data (unbuffered)
\*-------------------------------------------------------------------------*/
#define STEPSIZE 8192
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
p_io io = buf->io;
p_timeout tm = buf->tm;
size_t total = 0;
int err = IO_DONE;
while (total < count && err == IO_DONE) {
size_t done = 0;
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm);
total += done;
}
*sent = total;
buf->sent += total;
return err;
}
/*-------------------------------------------------------------------------*\
* Reads a fixed number of bytes (buffered)
\*-------------------------------------------------------------------------*/
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
int err = IO_DONE;
size_t total = 0;
while (err == IO_DONE) {
size_t count; const char *data;
err = buffer_get(buf, &data, &count);
count = MIN(count, wanted - total);
luaL_addlstring(b, data, count);
buffer_skip(buf, count);
total += count;
if (total >= wanted) break;
}
return err;
}
/*-------------------------------------------------------------------------*\
* Reads everything until the connection is closed (buffered)
\*-------------------------------------------------------------------------*/
static int recvall(p_buffer buf, luaL_Buffer *b) {
int err = IO_DONE;
size_t total = 0;
while (err == IO_DONE) {
const char *data; size_t count;
err = buffer_get(buf, &data, &count);
total += count;
luaL_addlstring(b, data, count);
buffer_skip(buf, count);
}
if (err == IO_CLOSED) {
if (total > 0) return IO_DONE;
else return IO_CLOSED;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
* are not returned by the function and are discarded from the buffer
\*-------------------------------------------------------------------------*/
static int recvline(p_buffer buf, luaL_Buffer *b) {
int err = IO_DONE;
while (err == IO_DONE) {
size_t count, pos; const char *data;
err = buffer_get(buf, &data, &count);
pos = 0;
while (pos < count && data[pos] != '\n') {
/* we ignore all \r's */
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
pos++;
}
if (pos < count) { /* found '\n' */
buffer_skip(buf, pos+1); /* skip '\n' too */
break; /* we are done */
} else /* reached the end of the buffer */
buffer_skip(buf, pos);
}
return err;
}
/*-------------------------------------------------------------------------*\
* Skips a given number of bytes from read buffer. No data is read from the
* transport layer
\*-------------------------------------------------------------------------*/
static void buffer_skip(p_buffer buf, size_t count) {
buf->received += count;
buf->first += count;
if (buffer_isempty(buf))
buf->first = buf->last = 0;
}
/*-------------------------------------------------------------------------*\
* Return any data available in buffer, or get more data from transport layer
* if buffer is empty
\*-------------------------------------------------------------------------*/
static int buffer_get(p_buffer buf, const char **data, size_t *count) {
int err = IO_DONE;
p_io io = buf->io;
p_timeout tm = buf->tm;
if (buffer_isempty(buf)) {
size_t got;
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
buf->first = 0;
buf->last = got;
}
*count = buf->last - buf->first;
*data = buf->data + buf->first;
return err;
}

View File

@ -0,0 +1,45 @@
#ifndef BUF_H
#define BUF_H
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
*
* Line patterns require buffering. Reading one character at a time involves
* too many system calls and is very slow. This module implements the
* LuaSocket interface for input/output on connected objects, as seen by
* Lua programs.
*
* Input is buffered. Output is *not* buffered because there was no simple
* way of making sure the buffered output data would ever be sent.
*
* The module is built on top of the I/O abstraction defined in io.h and the
* timeout management is done with the timeout.h interface.
\*=========================================================================*/
#include "lua.h"
#include "luasocket_io.h"
#include "timeout.h"
/* buffer size in bytes */
#define BUF_SIZE 8192
/* buffer control structure */
typedef struct t_buffer_ {
double birthday; /* throttle support info: creation time, */
size_t sent, received; /* bytes sent, and bytes received */
p_io io; /* IO driver used for this buffer */
p_timeout tm; /* timeout management for this buffer */
size_t first, last; /* index of first and last bytes of stored data */
char data[BUF_SIZE]; /* storage space for buffer data */
} t_buffer;
typedef t_buffer *p_buffer;
int buffer_open(lua_State *L);
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
int buffer_meth_send(lua_State *L, p_buffer buf);
int buffer_meth_receive(lua_State *L, p_buffer buf);
int buffer_meth_getstats(lua_State *L, p_buffer buf);
int buffer_meth_setstats(lua_State *L, p_buffer buf);
int buffer_isempty(p_buffer buf);
#endif /* BUF_H */

View File

@ -0,0 +1,30 @@
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket_io.h"
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) {
io->send = send;
io->recv = recv;
io->error = error;
io->ctx = ctx;
}
/*-------------------------------------------------------------------------*\
* I/O error strings
\*-------------------------------------------------------------------------*/
const char *io_strerror(int err) {
switch (err) {
case IO_DONE: return NULL;
case IO_CLOSED: return "closed";
case IO_TIMEOUT: return "timeout";
default: return "unknown error";
}
}

View File

@ -0,0 +1,65 @@
#ifndef IO_H
#define IO_H
/*=========================================================================*\
* Input/Output abstraction
* LuaSocket toolkit
*
* This module defines the interface that LuaSocket expects from the
* transport layer for streamed input/output. The idea is that if any
* transport implements this interface, then the buffer.c functions
* automatically work on it.
*
* The module socket.h implements this interface, and thus the module tcp.h
* is very simple.
\*=========================================================================*/
#include <stdio.h>
#include "lua.h"
#include "timeout.h"
/* IO error codes */
enum {
IO_DONE = 0, /* operation completed successfully */
IO_TIMEOUT = -1, /* operation timed out */
IO_CLOSED = -2, /* the connection has been closed */
IO_UNKNOWN = -3
};
/* interface to error message function */
typedef const char *(*p_error) (
void *ctx, /* context needed by send */
int err /* error code */
);
/* interface to send function */
typedef int (*p_send) (
void *ctx, /* context needed by send */
const char *data, /* pointer to buffer with data to send */
size_t count, /* number of bytes to send from buffer */
size_t *sent, /* number of bytes sent uppon return */
p_timeout tm /* timeout control */
);
/* interface to recv function */
typedef int (*p_recv) (
void *ctx, /* context needed by recv */
char *data, /* pointer to buffer where data will be writen */
size_t count, /* number of bytes to receive into buffer */
size_t *got, /* number of bytes received uppon return */
p_timeout tm /* timeout control */
);
/* IO driver definition */
typedef struct t_io_ {
void *ctx; /* context needed by send/recv */
p_send send; /* send function pointer */
p_recv recv; /* receive function pointer */
p_error error; /* strerror function */
} t_io;
typedef t_io *p_io;
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
const char *io_strerror(int err);
#endif /* IO_H */

View File

@ -0,0 +1,723 @@
/*=========================================================================*\
* MIME support functions
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
#include "compat-5.1.h"
#endif
#include "mime.h"
/*=========================================================================*\
* Don't want to trust escape character constants
\*=========================================================================*/
typedef unsigned char UC;
static const char CRLF[] = "\r\n";
static const char EQCRLF[] = "=\r\n";
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static int mime_global_wrp(lua_State *L);
static int mime_global_b64(lua_State *L);
static int mime_global_unb64(lua_State *L);
static int mime_global_qp(lua_State *L);
static int mime_global_unqp(lua_State *L);
static int mime_global_qpwrp(lua_State *L);
static int mime_global_eol(lua_State *L);
static int mime_global_dot(lua_State *L);
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
static void b64setup(UC *base);
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static void qpsetup(UC *class, UC *unbase);
static void qpquote(UC c, luaL_Buffer *buffer);
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
static size_t qpencode(UC c, UC *input, size_t size,
const char *marker, luaL_Buffer *buffer);
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
/* code support functions */
static luaL_Reg func[] = {
{ "dot", mime_global_dot },
{ "b64", mime_global_b64 },
{ "eol", mime_global_eol },
{ "qp", mime_global_qp },
{ "qpwrp", mime_global_qpwrp },
{ "unb64", mime_global_unb64 },
{ "unqp", mime_global_unqp },
{ "wrp", mime_global_wrp },
{ NULL, NULL }
};
/*-------------------------------------------------------------------------*\
* Quoted-printable globals
\*-------------------------------------------------------------------------*/
static UC qpclass[256];
static UC qpbase[] = "0123456789ABCDEF";
static UC qpunbase[256];
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
/*-------------------------------------------------------------------------*\
* Base64 globals
\*-------------------------------------------------------------------------*/
static const UC b64base[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static UC b64unbase[256];
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
MIME_API int luaopen_mime_core(lua_State *L)
{
luaL_openlib(L, "mime", func, 0);
/* make version string available to scripts */
lua_pushstring(L, "_VERSION");
lua_pushstring(L, MIME_VERSION);
lua_rawset(L, -3);
/* initialize lookup tables */
qpsetup(qpclass, qpunbase);
b64setup(b64unbase);
return 1;
}
/*=========================================================================*\
* Global Lua functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
* A, n = wrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A.
\*-------------------------------------------------------------------------*/
static int mime_global_wrp(lua_State *L)
{
size_t size = 0;
int left = (int) luaL_checknumber(L, 1);
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
const UC *last = input + size;
int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer;
/* end of input black-hole */
if (!input) {
/* if last line has not been terminated, add a line break */
if (left < length) lua_pushstring(L, CRLF);
/* otherwise, we are done */
else lua_pushnil(L);
lua_pushnumber(L, length);
return 2;
}
luaL_buffinit(L, &buffer);
while (input < last) {
switch (*input) {
case '\r':
break;
case '\n':
luaL_addstring(&buffer, CRLF);
left = length;
break;
default:
if (left <= 0) {
left = length;
luaL_addstring(&buffer, CRLF);
}
luaL_addchar(&buffer, *input);
left--;
break;
}
input++;
}
luaL_pushresult(&buffer);
lua_pushnumber(L, left);
return 2;
}
/*-------------------------------------------------------------------------*\
* Fill base64 decode map.
\*-------------------------------------------------------------------------*/
static void b64setup(UC *unbase)
{
int i;
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
unbase['='] = 0;
}
/*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 3 bytes are available.
* Translate the 3 bytes into Base64 form and append to buffer.
* Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/
static size_t b64encode(UC c, UC *input, size_t size,
luaL_Buffer *buffer)
{
input[size++] = c;
if (size == 3) {
UC code[4];
unsigned long value = 0;
value += input[0]; value <<= 8;
value += input[1]; value <<= 8;
value += input[2];
code[3] = b64base[value & 0x3f]; value >>= 6;
code[2] = b64base[value & 0x3f]; value >>= 6;
code[1] = b64base[value & 0x3f]; value >>= 6;
code[0] = b64base[value];
luaL_addlstring(buffer, (char *) code, 4);
size = 0;
}
return size;
}
/*-------------------------------------------------------------------------*\
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
* Result, if any, is appended to buffer.
* Returns 0.
\*-------------------------------------------------------------------------*/
static size_t b64pad(const UC *input, size_t size,
luaL_Buffer *buffer)
{
unsigned long value = 0;
UC code[4] = {'=', '=', '=', '='};
switch (size) {
case 1:
value = input[0] << 4;
code[1] = b64base[value & 0x3f]; value >>= 6;
code[0] = b64base[value];
luaL_addlstring(buffer, (char *) code, 4);
break;
case 2:
value = input[0]; value <<= 8;
value |= input[1]; value <<= 2;
code[2] = b64base[value & 0x3f]; value >>= 6;
code[1] = b64base[value & 0x3f]; value >>= 6;
code[0] = b64base[value];
luaL_addlstring(buffer, (char *) code, 4);
break;
default:
break;
}
return 0;
}
/*-------------------------------------------------------------------------*\
* Acumulates bytes in input buffer until 4 bytes are available.
* Translate the 4 bytes from Base64 form and append to buffer.
* Returns new number of bytes in buffer.
\*-------------------------------------------------------------------------*/
static size_t b64decode(UC c, UC *input, size_t size,
luaL_Buffer *buffer)
{
/* ignore invalid characters */
if (b64unbase[c] > 64) return size;
input[size++] = c;
/* decode atom */
if (size == 4) {
UC decoded[3];
int valid, value = 0;
value = b64unbase[input[0]]; value <<= 6;
value |= b64unbase[input[1]]; value <<= 6;
value |= b64unbase[input[2]]; value <<= 6;
value |= b64unbase[input[3]];
decoded[2] = (UC) (value & 0xff); value >>= 8;
decoded[1] = (UC) (value & 0xff); value >>= 8;
decoded[0] = (UC) value;
/* take care of paddding */
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
luaL_addlstring(buffer, (char *) decoded, valid);
return 0;
/* need more data */
} else return size;
}
/*-------------------------------------------------------------------------*\
* Incrementally applies the Base64 transfer content encoding to a string
* A, B = b64(C, D)
* A is the encoded version of the largest prefix of C .. D that is
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
* The easiest thing would be to concatenate the two strings and
* encode the result, but we can't afford that or Lua would dupplicate
* every chunk we received.
\*-------------------------------------------------------------------------*/
static int mime_global_b64(lua_State *L)
{
UC atom[3];
size_t isize = 0, asize = 0;
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize;
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
asize = b64encode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */
if (!input) {
size_t osize = 0;
asize = b64pad(atom, asize, &buffer);
luaL_pushresult(&buffer);
/* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* otherwise process the second part */
last = input + isize;
while (input < last)
asize = b64encode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize);
return 2;
}
/*-------------------------------------------------------------------------*\
* Incrementally removes the Base64 transfer content encoding from a string
* A, B = b64(C, D)
* A is the encoded version of the largest prefix of C .. D that is
* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/
static int mime_global_unb64(lua_State *L)
{
UC atom[4];
size_t isize = 0, asize = 0;
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize;
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of the input */
luaL_buffinit(L, &buffer);
while (input < last)
asize = b64decode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second is nil, we are done */
if (!input) {
size_t osize = 0;
luaL_pushresult(&buffer);
/* if the output is empty and the input is nil, return nil */
lua_tolstring(L, -1, &osize);
if (osize == 0) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* otherwise, process the rest of the input */
last = input + isize;
while (input < last)
asize = b64decode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize);
return 2;
}
/*-------------------------------------------------------------------------*\
* Quoted-printable encoding scheme
* all (except CRLF in text) can be =XX
* CLRL in not text must be =XX=XX
* 33 through 60 inclusive can be plain
* 62 through 126 inclusive can be plain
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
* encoded lines must be no longer than 76 not counting CRLF
* soft line-break are =CRLF
* To encode one byte, we need to see the next two.
* Worst case is when we see a space, and wonder if a CRLF is comming
\*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*\
* Split quoted-printable characters into classes
* Precompute reverse map for encoding
\*-------------------------------------------------------------------------*/
static void qpsetup(UC *cl, UC *unbase)
{
int i;
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
cl['\t'] = QP_IF_LAST;
cl[' '] = QP_IF_LAST;
cl['\r'] = QP_CR;
for (i = 0; i < 256; i++) unbase[i] = 255;
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
unbase['f'] = 15;
}
/*-------------------------------------------------------------------------*\
* Output one character in form =XX
\*-------------------------------------------------------------------------*/
static void qpquote(UC c, luaL_Buffer *buffer)
{
luaL_addchar(buffer, '=');
luaL_addchar(buffer, qpbase[c >> 4]);
luaL_addchar(buffer, qpbase[c & 0x0F]);
}
/*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/
static size_t qpencode(UC c, UC *input, size_t size,
const char *marker, luaL_Buffer *buffer)
{
input[size++] = c;
/* deal with all characters we can have */
while (size > 0) {
switch (qpclass[input[0]]) {
/* might be the CR of a CRLF sequence */
case QP_CR:
if (size < 2) return size;
if (input[1] == '\n') {
luaL_addstring(buffer, marker);
return 0;
} else qpquote(input[0], buffer);
break;
/* might be a space and that has to be quoted if last in line */
case QP_IF_LAST:
if (size < 3) return size;
/* if it is the last, quote it and we are done */
if (input[1] == '\r' && input[2] == '\n') {
qpquote(input[0], buffer);
luaL_addstring(buffer, marker);
return 0;
} else luaL_addchar(buffer, input[0]);
break;
/* might have to be quoted always */
case QP_QUOTED:
qpquote(input[0], buffer);
break;
/* might never have to be quoted */
default:
luaL_addchar(buffer, input[0]);
break;
}
input[0] = input[1]; input[1] = input[2];
size--;
}
return 0;
}
/*-------------------------------------------------------------------------*\
* Deal with the final characters
\*-------------------------------------------------------------------------*/
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
{
size_t i;
for (i = 0; i < size; i++) {
if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
else qpquote(input[i], buffer);
}
if (size > 0) luaL_addstring(buffer, EQCRLF);
return 0;
}
/*-------------------------------------------------------------------------*\
* Incrementally converts a string to quoted-printable
* A, B = qp(C, D, marker)
* Marker is the text to be used to replace CRLF sequences found in A.
* A is the encoded version of the largest prefix of C .. D that
* can be encoded without doubts.
* B has the remaining bytes of C .. D, *without* encoding.
\*-------------------------------------------------------------------------*/
static int mime_global_qp(lua_State *L)
{
size_t asize = 0, isize = 0;
UC atom[3];
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 3);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
asize = qpencode(*input++, atom, asize, marker, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */
if (!input) {
asize = qppad(atom, asize, &buffer);
luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* otherwise process rest of input */
last = input + isize;
while (input < last)
asize = qpencode(*input++, atom, asize, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize);
return 2;
}
/*-------------------------------------------------------------------------*\
* Accumulate characters until we are sure about how to deal with them.
* Once we are sure, output the to the buffer, in the correct form.
\*-------------------------------------------------------------------------*/
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
int d;
input[size++] = c;
/* deal with all characters we can deal */
switch (input[0]) {
/* if we have an escape character */
case '=':
if (size < 3) return size;
/* eliminate soft line break */
if (input[1] == '\r' && input[2] == '\n') return 0;
/* decode quoted representation */
c = qpunbase[input[1]]; d = qpunbase[input[2]];
/* if it is an invalid, do not decode */
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
else luaL_addchar(buffer, (char) ((c << 4) + d));
return 0;
case '\r':
if (size < 2) return size;
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
return 0;
default:
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
luaL_addchar(buffer, input[0]);
return 0;
}
}
/*-------------------------------------------------------------------------*\
* Incrementally decodes a string in quoted-printable
* A, B = qp(C, D)
* A is the decoded version of the largest prefix of C .. D that
* can be decoded without doubts.
* B has the remaining bytes of C .. D, *without* decoding.
\*-------------------------------------------------------------------------*/
static int mime_global_unqp(lua_State *L)
{
size_t asize = 0, isize = 0;
UC atom[3];
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
const UC *last = input + isize;
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* make sure we don't confuse buffer stuff with arguments */
lua_settop(L, 2);
/* process first part of input */
luaL_buffinit(L, &buffer);
while (input < last)
asize = qpdecode(*input++, atom, asize, &buffer);
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
/* if second part is nil, we are done */
if (!input) {
luaL_pushresult(&buffer);
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
lua_pushnil(L);
return 2;
}
/* otherwise process rest of input */
last = input + isize;
while (input < last)
asize = qpdecode(*input++, atom, asize, &buffer);
luaL_pushresult(&buffer);
lua_pushlstring(L, (char *) atom, asize);
return 2;
}
/*-------------------------------------------------------------------------*\
* Incrementally breaks a quoted-printed string into lines
* A, n = qpwrp(l, B, length)
* A is a copy of B, broken into lines of at most 'length' bytes.
* 'l' is how many bytes are left for the first line of B.
* 'n' is the number of bytes left in the last line of A.
* There are two complications: lines can't be broken in the middle
* of an encoded =XX, and there might be line breaks already
\*-------------------------------------------------------------------------*/
static int mime_global_qpwrp(lua_State *L)
{
size_t size = 0;
int left = (int) luaL_checknumber(L, 1);
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
const UC *last = input + size;
int length = (int) luaL_optnumber(L, 3, 76);
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
if (left < length) lua_pushstring(L, EQCRLF);
else lua_pushnil(L);
lua_pushnumber(L, length);
return 2;
}
/* process all input */
luaL_buffinit(L, &buffer);
while (input < last) {
switch (*input) {
case '\r':
break;
case '\n':
left = length;
luaL_addstring(&buffer, CRLF);
break;
case '=':
if (left <= 3) {
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_addchar(&buffer, *input);
left--;
break;
default:
if (left <= 1) {
left = length;
luaL_addstring(&buffer, EQCRLF);
}
luaL_addchar(&buffer, *input);
left--;
break;
}
input++;
}
luaL_pushresult(&buffer);
lua_pushnumber(L, left);
return 2;
}
/*-------------------------------------------------------------------------*\
* Here is what we do: \n, and \r are considered candidates for line
* break. We issue *one* new line marker if any of them is seen alone, or
* followed by a different one. That is, \n\n and \r\r will issue two
* end of line markers each, but \r\n, \n\r etc will only issue *one*
* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
* probably other more obscure conventions.
*
* c is the current character being processed
* last is the previous character
\*-------------------------------------------------------------------------*/
#define eolcandidate(c) (c == '\r' || c == '\n')
static int eolprocess(int c, int last, const char *marker,
luaL_Buffer *buffer)
{
if (eolcandidate(c)) {
if (eolcandidate(last)) {
if (c == last) luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_addchar(buffer, (char) c);
return 0;
}
}
/*-------------------------------------------------------------------------*\
* Converts a string to uniform EOL convention.
* A, n = eol(o, B, marker)
* A is the converted version of the largest prefix of B that can be
* converted unambiguously. 'o' is the context returned by the previous
* call. 'n' is the new context.
\*-------------------------------------------------------------------------*/
static int mime_global_eol(lua_State *L)
{
int ctx = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
/* end of input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
/* process all input */
while (input < last)
ctx = eolprocess(*input++, ctx, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, ctx);
return 2;
}
/*-------------------------------------------------------------------------*\
* Takes one byte and stuff it if needed.
\*-------------------------------------------------------------------------*/
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
{
luaL_addchar(buffer, (char) c);
switch (c) {
case '\r':
return 1;
case '\n':
return (state == 1)? 2: 0;
case '.':
if (state == 2)
luaL_addchar(buffer, '.');
default:
return 0;
}
}
/*-------------------------------------------------------------------------*\
* Incrementally applies smtp stuffing to a string
* A, n = dot(l, D)
\*-------------------------------------------------------------------------*/
static int mime_global_dot(lua_State *L)
{
size_t isize = 0, state = (size_t) luaL_checknumber(L, 1);
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
luaL_Buffer buffer;
/* end-of-input blackhole */
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 2);
return 2;
}
/* process all input */
luaL_buffinit(L, &buffer);
while (input < last)
state = dot(*input++, state, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, (lua_Number) state);
return 2;
}

View File

@ -0,0 +1,29 @@
#ifndef MIME_H
#define MIME_H
/*=========================================================================*\
* Core MIME support
* LuaSocket toolkit
*
* This module provides functions to implement transfer content encodings
* and formatting conforming to RFC 2045. It is used by mime.lua, which
* provide a higher level interface to this functionality.
\*=========================================================================*/
#include "lua.h"
/*-------------------------------------------------------------------------*\
* Current MIME library version
\*-------------------------------------------------------------------------*/
#define MIME_VERSION "MIME 1.0.3-rc1"
#define MIME_COPYRIGHT "Copyright (C) 2004-2012 Diego Nehab"
#define MIME_AUTHORS "Diego Nehab"
/*-------------------------------------------------------------------------*\
* This macro prefixes all exported API functions
\*-------------------------------------------------------------------------*/
#ifndef MIME_API
#define MIME_API extern
#endif
MIME_API int luaopen_mime_core(lua_State *L);
#endif /* MIME_H */

View File

@ -0,0 +1,262 @@
/*=========================================================================*\
* Common option interface
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lauxlib.h"
#include "auxiliar.h"
#include "options.h"
#include "inet.h"
/*=========================================================================*\
* Internal functions prototypes
\*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
static int opt_set(lua_State *L, p_socket ps, int level, int name,
void *val, int len);
static int opt_get(lua_State *L, p_socket ps, int level, int name,
void *val, int* len);
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Calls appropriate option handler
\*-------------------------------------------------------------------------*/
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
{
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
return opt->func(L, ps);
}
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
{
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
while (opt->name && strcmp(name, opt->name))
opt++;
if (!opt->func) {
char msg[45];
sprintf(msg, "unsupported option `%.35s'", name);
luaL_argerror(L, 2, msg);
}
return opt->func(L, ps);
}
/* enables reuse of local address */
int opt_set_reuseaddr(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
int opt_get_reuseaddr(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
}
/* enables reuse of local port */
int opt_set_reuseport(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
int opt_get_reuseport(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
}
/* disables the Naggle algorithm */
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
}
int opt_set_keepalive(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_get_keepalive(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
}
int opt_set_dontroute(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
}
int opt_set_broadcast(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
}
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
{
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
}
int opt_set_linger(lua_State *L, p_socket ps)
{
struct linger li; /* obj, name, table */
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "on");
lua_gettable(L, 3);
if (!lua_isboolean(L, -1))
luaL_argerror(L, 3, "boolean 'on' field expected");
li.l_onoff = (u_short) lua_toboolean(L, -1);
lua_pushstring(L, "timeout");
lua_gettable(L, 3);
if (!lua_isnumber(L, -1))
luaL_argerror(L, 3, "number 'timeout' field expected");
li.l_linger = (u_short) lua_tonumber(L, -1);
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
}
int opt_get_linger(lua_State *L, p_socket ps)
{
struct linger li; /* obj, name */
int len = sizeof(li);
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
if (err)
return err;
lua_newtable(L);
lua_pushboolean(L, li.l_onoff);
lua_setfield(L, -2, "on");
lua_pushinteger(L, li.l_linger);
lua_setfield(L, -2, "timeout");
return 1;
}
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
{
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_TTL,
(char *) &val, sizeof(val));
}
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
{
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
struct in_addr val;
val.s_addr = htonl(INADDR_ANY);
if (strcmp(address, "*") && !inet_aton(address, &val))
luaL_argerror(L, 3, "ip expected");
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &val, sizeof(val));
}
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
{
struct in_addr val;
socklen_t len = sizeof(val);
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
lua_pushstring(L, inet_ntoa(val));
return 1;
}
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
{
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
}
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
{
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
}
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
{
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
}
/*=========================================================================*\
* Auxiliar functions
\*=========================================================================*/
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
{
struct ip_mreq val; /* obj, name, table */
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
lua_pushstring(L, "multiaddr");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'multiaddr' field expected");
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
lua_pushstring(L, "interface");
lua_gettable(L, 3);
if (!lua_isstring(L, -1))
luaL_argerror(L, 3, "string 'interface' field expected");
val.imr_interface.s_addr = htonl(INADDR_ANY);
if (strcmp(lua_tostring(L, -1), "*") &&
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
luaL_argerror(L, 3, "invalid 'interface' ip address");
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}
static
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
{
socklen_t socklen = *len;
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
lua_pushnil(L);
lua_pushstring(L, "getsockopt failed");
return 2;
}
*len = socklen;
return 0;
}
static
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
{
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
lua_pushnil(L);
lua_pushstring(L, "setsockopt failed");
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = 0;
int len = sizeof(val);
int err = opt_get(L, ps, level, name, (char *) &val, &len);
if (err)
return err;
lua_pushboolean(L, val);
return 1;
}
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
{
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
}

View File

@ -0,0 +1,50 @@
#ifndef OPTIONS_H
#define OPTIONS_H
/*=========================================================================*\
* Common option interface
* LuaSocket toolkit
*
* This module provides a common interface to socket options, used mainly by
* modules UDP and TCP.
\*=========================================================================*/
#include "lua.h"
#include "socket.h"
/* option registry */
typedef struct t_opt {
const char *name;
int (*func)(lua_State *L, p_socket ps);
} t_opt;
typedef t_opt *p_opt;
/* supported options for setoption */
int opt_set_dontroute(lua_State *L, p_socket ps);
int opt_set_broadcast(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
int opt_set_keepalive(lua_State *L, p_socket ps);
int opt_set_linger(lua_State *L, p_socket ps);
int opt_set_reuseaddr(lua_State *L, p_socket ps);
int opt_set_reuseport(lua_State *L, p_socket ps);
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
/* supported options for getoption */
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
int opt_get_keepalive(lua_State *L, p_socket ps);
int opt_get_linger(lua_State *L, p_socket ps);
int opt_get_reuseaddr(lua_State *L, p_socket ps);
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
/* invokes the appropriate option handler */
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
#endif

View File

@ -0,0 +1,216 @@
/*=========================================================================*\
* Select implementation
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "socket.h"
#include "timeout.h"
#include "select.h"
/*=========================================================================*\
* Internal function prototypes.
\*=========================================================================*/
static t_socket getfd(lua_State *L);
static int dirty(lua_State *L);
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd);
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start);
static void make_assoc(lua_State *L, int tab);
static int global_select(lua_State *L);
/* functions in library namespace */
static luaL_Reg func[] = {
{"select", global_select},
{NULL, NULL}
};
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int select_open(lua_State *L) {
lua_pushstring(L, "_SETSIZE");
lua_pushnumber(L, FD_SETSIZE);
lua_rawset(L, -3);
luaL_openlib(L, NULL, func, 0);
return 0;
}
/*=========================================================================*\
* Global Lua functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Waits for a set of sockets until a condition is met or timeout.
\*-------------------------------------------------------------------------*/
static int global_select(lua_State *L) {
int rtab, wtab, itab, ret, ndirty;
t_socket max_fd = SOCKET_INVALID;
fd_set rset, wset;
t_timeout tm;
double t = luaL_optnumber(L, 3, -1);
FD_ZERO(&rset); FD_ZERO(&wset);
lua_settop(L, 3);
lua_newtable(L); itab = lua_gettop(L);
lua_newtable(L); rtab = lua_gettop(L);
lua_newtable(L); wtab = lua_gettop(L);
collect_fd(L, 1, itab, &rset, &max_fd);
collect_fd(L, 2, itab, &wset, &max_fd);
ndirty = check_dirty(L, 1, rtab, &rset);
t = ndirty > 0? 0.0: t;
timeout_init(&tm, t, -1);
timeout_markstart(&tm);
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
if (ret > 0 || ndirty > 0) {
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
make_assoc(L, rtab);
make_assoc(L, wtab);
return 2;
} else if (ret == 0) {
lua_pushstring(L, "timeout");
return 3;
} else {
luaL_error(L, "select failed");
return 3;
}
}
/*=========================================================================*\
* Internal functions
\*=========================================================================*/
static t_socket getfd(lua_State *L) {
t_socket fd = SOCKET_INVALID;
lua_pushstring(L, "getfd");
lua_gettable(L, -2);
if (!lua_isnil(L, -1)) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
if (lua_isnumber(L, -1)) {
double numfd = lua_tonumber(L, -1);
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
}
}
lua_pop(L, 1);
return fd;
}
static int dirty(lua_State *L) {
int is = 0;
lua_pushstring(L, "dirty");
lua_gettable(L, -2);
if (!lua_isnil(L, -1)) {
lua_pushvalue(L, -2);
lua_call(L, 1, 1);
is = lua_toboolean(L, -1);
}
lua_pop(L, 1);
return is;
}
static void collect_fd(lua_State *L, int tab, int itab,
fd_set *set, t_socket *max_fd) {
int i = 1, n = 0;
/* nil is the same as an empty table */
if (lua_isnil(L, tab)) return;
/* otherwise we need it to be a table */
luaL_checktype(L, tab, LUA_TTABLE);
for ( ;; ) {
t_socket fd;
lua_pushnumber(L, i);
lua_gettable(L, tab);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
/* getfd figures out if this is a socket */
fd = getfd(L);
if (fd != SOCKET_INVALID) {
/* make sure we don't overflow the fd_set */
#ifdef _WIN32
if (n >= FD_SETSIZE)
luaL_argerror(L, tab, "too many sockets");
#else
if (fd >= FD_SETSIZE)
luaL_argerror(L, tab, "descriptor too large for set size");
#endif
FD_SET(fd, set);
n++;
/* keep track of the largest descriptor so far */
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
*max_fd = fd;
/* make sure we can map back from descriptor to the object */
lua_pushnumber(L, (lua_Number) fd);
lua_pushvalue(L, -2);
lua_settable(L, itab);
}
lua_pop(L, 1);
i = i + 1;
}
}
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
int ndirty = 0, i = 1;
if (lua_isnil(L, tab))
return 0;
for ( ;; ) {
t_socket fd;
lua_pushnumber(L, i);
lua_gettable(L, tab);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
break;
}
fd = getfd(L);
if (fd != SOCKET_INVALID && dirty(L)) {
lua_pushnumber(L, ++ndirty);
lua_pushvalue(L, -2);
lua_settable(L, dtab);
FD_CLR(fd, set);
}
lua_pop(L, 1);
i = i + 1;
}
return ndirty;
}
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
int itab, int tab, int start) {
t_socket fd;
for (fd = 0; fd < max_fd; fd++) {
if (FD_ISSET(fd, set)) {
lua_pushnumber(L, ++start);
lua_pushnumber(L, (lua_Number) fd);
lua_gettable(L, itab);
lua_settable(L, tab);
}
}
}
static void make_assoc(lua_State *L, int tab) {
int i = 1, atab;
lua_newtable(L); atab = lua_gettop(L);
for ( ;; ) {
lua_pushnumber(L, i);
lua_gettable(L, tab);
if (!lua_isnil(L, -1)) {
lua_pushnumber(L, i);
lua_pushvalue(L, -2);
lua_settable(L, atab);
lua_pushnumber(L, i);
lua_settable(L, atab);
} else {
lua_pop(L, 1);
break;
}
i = i+1;
}
}

View File

@ -0,0 +1,15 @@
#ifndef SELECT_H
#define SELECT_H
/*=========================================================================*\
* Select implementation
* LuaSocket toolkit
*
* Each object that can be passed to the select function has to export
* method getfd() which returns the descriptor to be passed to the
* underlying select function. Another method, dirty(), should return
* true if there is data ready for reading (required for buffered input).
\*=========================================================================*/
int select_open(lua_State *L);
#endif /* SELECT_H */

View File

@ -0,0 +1,183 @@
/*=========================================================================*\
* Serial stream
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <sys/un.h>
/*
Reuses userdata definition from unix.h, since it is useful for all
stream-like objects.
If we stored the serial path for use in error messages or userdata
printing, we might need our own userdata definition.
Group usage is semi-inherited from unix.c, but unnecessary since we
have only one object type.
*/
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_send(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_close(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
/* serial object methods */
static luaL_Reg serial_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"close", meth_close},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"settimeout", meth_settimeout},
{NULL, NULL}
};
/* our socket creation function */
static luaL_Reg func[] = {
{"serial", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "serial{client}", serial_methods);
/* create class groups */
auxiliar_add2group(L, "serial{client}", "serial{any}");
/* make sure the function ends up in the package table */
luaL_openlib(L, "socket", func, 0);
/* return the function instead of the 'socket' table */
lua_pushstring(L, "serial");
lua_gettable(L, -2);
return 1;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a serial object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
const char* path = luaL_checkstring(L, 1);
/* allocate unix object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* open serial device */
t_socket sock = open(path, O_NOCTTY|O_RDWR);
/*printf("open %s on %d\n", path, sock);*/
if (sock < 0) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(errno));
lua_pushnumber(L, errno);
return 3;
}
/* set its type as client object */
auxiliar_setclass(L, "serial{client}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
}

View File

@ -0,0 +1,78 @@
#ifndef SOCKET_H
#define SOCKET_H
/*=========================================================================*\
* Socket compatibilization module
* LuaSocket toolkit
*
* BSD Sockets and WinSock are similar, but there are a few irritating
* differences. Also, not all *nix platforms behave the same. This module
* (and the associated usocket.h and wsocket.h) factor these differences and
* creates a interface compatible with the io.h module.
\*=========================================================================*/
#include "luasocket_io.h"
/*=========================================================================*\
* Platform specific compatibilization
\*=========================================================================*/
#ifdef _WIN32
#include "wsocket.h"
#else
#include "usocket.h"
#endif
/*=========================================================================*\
* The connect and accept functions accept a timeout and their
* implementations are somewhat complicated. We chose to move
* the timeout control into this module for these functions in
* order to simplify the modules that use them.
\*=========================================================================*/
#include "timeout.h"
/* we are lazy... */
typedef struct sockaddr SA;
/*=========================================================================*\
* Functions bellow implement a comfortable platform independent
* interface to sockets
\*=========================================================================*/
int socket_open(void);
int socket_close(void);
void socket_destroy(p_socket ps);
void socket_shutdown(p_socket ps, int how);
int socket_sendto(p_socket ps, const char *data, size_t count,
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_recvfrom(p_socket ps, char *data, size_t count,
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
void socket_setnonblocking(p_socket ps);
void socket_setblocking(p_socket ps);
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm);
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
int socket_create(p_socket ps, int domain, int type, int protocol);
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
int socket_listen(p_socket ps, int backlog);
int socket_accept(p_socket ps, p_socket pa, SA *addr,
socklen_t *addr_len, p_timeout tm);
const char *socket_hoststrerror(int err);
const char *socket_gaistrerror(int err);
const char *socket_strerror(int err);
/* these are perfect to use with the io abstraction module
and the buffered input module */
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm);
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
const char *socket_ioerror(p_socket ps, int err);
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
int socket_gethostbyname(const char *addr, struct hostent **hp);
#endif /* SOCKET_H */

View File

@ -0,0 +1 @@
e79358cdf4b02c66a50e684543e505002bdbcc91

View File

@ -0,0 +1,32 @@
/* socket_scripts.h */
#ifndef __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
#define __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
#if __cplusplus
extern "C" {
#endif
#include "lua.h"
void luaopen_socket_scripts(lua_State* L);
/*
int luaopen_lua_m_ltn12(lua_State* L);
int luaopen_lua_m_mime(lua_State* L);
int luaopen_lua_m_socket_ftp(lua_State* L);
int luaopen_lua_m_socket_headers(lua_State* L);
int luaopen_lua_m_socket_http(lua_State* L);
int luaopen_lua_m_socket_mbox(lua_State* L);
int luaopen_lua_m_socket_smtp(lua_State* L);
int luaopen_lua_m_socket_tp(lua_State* L);
int luaopen_lua_m_socket_url(lua_State* L);
int luaopen_lua_m_socket(lua_State* L);
*/
#if __cplusplus
}
#endif
#endif /* __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ */

View File

@ -0,0 +1,475 @@
/*=========================================================================*\
* TCP object
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "socket.h"
#include "inet.h"
#include "options.h"
#include "tcp.h"
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create6(lua_State *L);
static int global_connect(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L);
static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
/* tcp object methods */
static luaL_Reg tcp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd},
{"getoption", meth_getoption},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"listen", meth_listen},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"settimeout", meth_settimeout},
{"shutdown", meth_shutdown},
{NULL, NULL}
};
/* socket option handlers */
static t_opt optget[] = {
{"keepalive", opt_get_keepalive},
{"reuseaddr", opt_get_reuseaddr},
{"tcp-nodelay", opt_get_tcp_nodelay},
{"linger", opt_get_linger},
{NULL, NULL}
};
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"tcp-nodelay", opt_set_tcp_nodelay},
{"ipv6-v6only", opt_set_ip6_v6only},
{"linger", opt_set_linger},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"tcp", global_create},
{"tcp6", global_create6},
{"connect", global_connect},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int tcp_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "tcp{master}", tcp_methods);
auxiliar_newclass(L, "tcp{client}", tcp_methods);
auxiliar_newclass(L, "tcp{server}", tcp_methods);
/* create class groups */
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */
luaL_openlib(L, NULL, func, 0);
return 0;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
return buffer_meth_send(L, &tcp->buf);
}
static int meth_receive(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
return buffer_meth_receive(L, &tcp->buf);
}
static int meth_getstats(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
return buffer_meth_getstats(L, &tcp->buf);
}
static int meth_setstats(lua_State *L) {
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
return buffer_meth_setstats(L, &tcp->buf);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_getoption(L, optget, &tcp->sock);
}
static int meth_setoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return opt_meth_setoption(L, optset, &tcp->sock);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
lua_pushnumber(L, (int) tcp->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
tcp->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
lua_pushboolean(L, !buffer_isempty(&tcp->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L)
{
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
/* if successful, push client socket */
if (err == NULL) {
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
auxiliar_setclass(L, "tcp{client}", -1);
/* initialize structure fields */
memset(clnt, 0, sizeof(t_tcp));
socket_setnonblocking(&sock);
clnt->sock = sock;
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
clnt->family = server->family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = tcp->family;
bindhints.ai_flags = AI_PASSIVE;
address = strcmp(address, "*")? address: NULL;
err = inet_trybind(&tcp->sock, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master tcp object into a client object.
\*-------------------------------------------------------------------------*/
static int meth_connect(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
struct addrinfo connecthints;
const char *err;
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = tcp->family;
timeout_markstart(&tcp->tm);
err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints);
/* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
socket_destroy(&tcp->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
if (tcp->family == PF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
}
/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
int backlog = (int) luaL_optnumber(L, 2, 32);
int err = socket_listen(&tcp->sock, backlog);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
/* turn master object into a server object */
auxiliar_setclass(L, "tcp{server}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Shuts the connection down partially
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call inet methods
\*-------------------------------------------------------------------------*/
static int meth_getpeername(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getpeername(L, &tcp->sock, tcp->family);
}
static int meth_getsockname(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return inet_meth_getsockname(L, &tcp->sock, tcp->family);
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
return timeout_meth_settimeout(L, &tcp->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master tcp object
\*-------------------------------------------------------------------------*/
static int tcp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
/* try to allocate a system socket */
if (!err) {
/* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
}
tcp->sock = sock;
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->family = family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
static int global_create(lua_State *L) {
return tcp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return tcp_create(L, AF_INET6);
}
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
struct addrinfo *connecthints, p_tcp tcp) {
struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL;
/* try resolving */
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
connecthints, &resolved));
if (err != NULL) {
if (resolved) freeaddrinfo(resolved);
return err;
}
/* iterate over all returned addresses trying to connect */
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
p_timeout tm = timeout_markstart(&tcp->tm);
/* create new socket if one wasn't created by the bind stage */
if (tcp->sock == SOCKET_INVALID) {
err = socket_strerror(socket_create(&tcp->sock,
iterator->ai_family, iterator->ai_socktype,
iterator->ai_protocol));
if (err != NULL) {
freeaddrinfo(resolved);
return err;
}
tcp->family = iterator->ai_family;
/* all sockets initially non-blocking */
socket_setnonblocking(&tcp->sock);
}
/* finally try connecting to remote address */
err = socket_strerror(socket_connect(&tcp->sock,
(SA *) iterator->ai_addr,
(socklen_t) iterator->ai_addrlen, tm));
/* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
}
static int global_connect(lua_State *L) {
const char *remoteaddr = luaL_checkstring(L, 1);
const char *remoteserv = luaL_checkstring(L, 2);
const char *localaddr = luaL_optstring(L, 3, NULL);
const char *localserv = luaL_optstring(L, 4, "0");
int family = inet_optfamily(L, 5, "unspec");
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
struct addrinfo bindhints, connecthints;
const char *err = NULL;
/* initialize tcp structure */
memset(tcp, 0, sizeof(t_tcp));
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
tcp->sock = SOCKET_INVALID;
/* allow user to pick local address and port */
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
bindhints.ai_family = family;
bindhints.ai_flags = AI_PASSIVE;
if (localaddr) {
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
tcp->family = bindhints.ai_family;
}
/* try to connect to remote address and port */
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = bindhints.ai_family;
err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
if (err) {
socket_destroy(&tcp->sock);
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
auxiliar_setclass(L, "tcp{client}", -1);
return 1;
}

View File

@ -0,0 +1,35 @@
#ifndef TCP_H
#define TCP_H
/*=========================================================================*\
* TCP object
* LuaSocket toolkit
*
* The tcp.h module is basicly a glue that puts together modules buffer.h,
* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET,
* SOCK_STREAM) support.
*
* Three classes are defined: master, client and server. The master class is
* a newly created tcp object, that has not been bound or connected. Server
* objects are tcp objects bound to some local address. Client objects are
* tcp objects either connected to some address or returned by the accept
* method of a server object.
\*=========================================================================*/
#include "lua.h"
#include "luasocket_buffer.h"
#include "timeout.h"
#include "socket.h"
typedef struct t_tcp_ {
t_socket sock;
t_io io;
t_buffer buf;
t_timeout tm;
int family;
} t_tcp;
typedef t_tcp *p_tcp;
int tcp_open(lua_State *L);
#endif /* TCP_H */

View File

@ -0,0 +1,217 @@
/*=========================================================================*\
* Timeout management functions
* LuaSocket toolkit
\*=========================================================================*/
#include <stdio.h>
#include <limits.h>
#include <float.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "timeout.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <time.h>
#include <sys/time.h>
#endif
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int timeout_lua_gettime(lua_State *L);
static int timeout_lua_sleep(lua_State *L);
static luaL_Reg func[] = {
{ "gettime", timeout_lua_gettime },
{ "sleep", timeout_lua_sleep },
{ NULL, NULL }
};
/*=========================================================================*\
* Exported functions.
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initialize structure
\*-------------------------------------------------------------------------*/
void timeout_init(p_timeout tm, double block, double total) {
tm->block = block;
tm->total = total;
}
/*-------------------------------------------------------------------------*\
* Determines how much time we have left for the next system call,
* if the previous call was successful
* Input
* tm: timeout control structure
* Returns
* the number of ms left or -1 if there is no time limit
\*-------------------------------------------------------------------------*/
double timeout_get(p_timeout tm) {
if (tm->block < 0.0 && tm->total < 0.0) {
return -1;
} else if (tm->block < 0.0) {
double t = tm->total - timeout_gettime() + tm->start;
return MAX(t, 0.0);
} else if (tm->total < 0.0) {
return tm->block;
} else {
double t = tm->total - timeout_gettime() + tm->start;
return MIN(tm->block, MAX(t, 0.0));
}
}
/*-------------------------------------------------------------------------*\
* Returns time since start of operation
* Input
* tm: timeout control structure
* Returns
* start field of structure
\*-------------------------------------------------------------------------*/
double timeout_getstart(p_timeout tm) {
return tm->start;
}
/*-------------------------------------------------------------------------*\
* Determines how much time we have left for the next system call,
* if the previous call was a failure
* Input
* tm: timeout control structure
* Returns
* the number of ms left or -1 if there is no time limit
\*-------------------------------------------------------------------------*/
double timeout_getretry(p_timeout tm) {
if (tm->block < 0.0 && tm->total < 0.0) {
return -1;
} else if (tm->block < 0.0) {
double t = tm->total - timeout_gettime() + tm->start;
return MAX(t, 0.0);
} else if (tm->total < 0.0) {
double t = tm->block - timeout_gettime() + tm->start;
return MAX(t, 0.0);
} else {
double t = tm->total - timeout_gettime() + tm->start;
return MIN(tm->block, MAX(t, 0.0));
}
}
/*-------------------------------------------------------------------------*\
* Marks the operation start time in structure
* Input
* tm: timeout control structure
\*-------------------------------------------------------------------------*/
p_timeout timeout_markstart(p_timeout tm) {
tm->start = timeout_gettime();
return tm;
}
/*-------------------------------------------------------------------------*\
* Gets time in s, relative to January 1, 1970 (UTC)
* Returns
* time in s.
\*-------------------------------------------------------------------------*/
#ifdef _WIN32
double timeout_gettime(void) {
FILETIME ft;
double t;
GetSystemTimeAsFileTime(&ft);
/* Windows file time (time since January 1, 1601 (UTC)) */
t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
/* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */
return (t - 11644473600.0);
}
#else
double timeout_gettime(void) {
struct timeval v;
gettimeofday(&v, (struct timezone *) NULL);
/* Unix Epoch time (time since January 1, 1970 (UTC)) */
return v.tv_sec + v.tv_usec/1.0e6;
}
#endif
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int timeout_open(lua_State *L) {
luaL_openlib(L, NULL, func, 0);
return 0;
}
/*-------------------------------------------------------------------------*\
* Sets timeout values for IO operations
* Lua Input: base, time [, mode]
* time: time out value in seconds
* mode: "b" for block timeout, "t" for total timeout. (default: b)
\*-------------------------------------------------------------------------*/
int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
double t = luaL_optnumber(L, 2, -1);
const char *mode = luaL_optstring(L, 3, "b");
switch (*mode) {
case 'b':
tm->block = t;
break;
case 'r': case 't':
tm->total = t;
break;
default:
luaL_argcheck(L, 0, 3, "invalid timeout mode");
break;
}
lua_pushnumber(L, 1);
return 1;
}
/*=========================================================================*\
* Test support functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Returns the time the system has been up, in secconds.
\*-------------------------------------------------------------------------*/
static int timeout_lua_gettime(lua_State *L)
{
lua_pushnumber(L, timeout_gettime());
return 1;
}
/*-------------------------------------------------------------------------*\
* Sleep for n seconds.
\*-------------------------------------------------------------------------*/
#ifdef _WIN32
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
if (n < 0.0) n = 0.0;
if (n < DBL_MAX/1000.0) n *= 1000.0;
if (n > INT_MAX) n = INT_MAX;
Sleep((int)n);
return 0;
}
#else
int timeout_lua_sleep(lua_State *L)
{
double n = luaL_checknumber(L, 1);
struct timespec t, r;
if (n < 0.0) n = 0.0;
if (n > INT_MAX) n = INT_MAX;
t.tv_sec = (int) n;
n -= t.tv_sec;
t.tv_nsec = (int) (n * 1000000000);
if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
while (nanosleep(&t, &r) != 0) {
t.tv_sec = r.tv_sec;
t.tv_nsec = r.tv_nsec;
}
return 0;
}
#endif

View File

@ -0,0 +1,28 @@
#ifndef TIMEOUT_H
#define TIMEOUT_H
/*=========================================================================*\
* Timeout management functions
* LuaSocket toolkit
\*=========================================================================*/
#include "lua.h"
/* timeout control structure */
typedef struct t_timeout_ {
double block; /* maximum time for blocking calls */
double total; /* total number of miliseconds for operation */
double start; /* time of start of operation */
} t_timeout;
typedef t_timeout *p_timeout;
int timeout_open(lua_State *L);
void timeout_init(p_timeout tm, double block, double total);
double timeout_get(p_timeout tm);
double timeout_getretry(p_timeout tm);
p_timeout timeout_markstart(p_timeout tm);
double timeout_getstart(p_timeout tm);
double timeout_gettime(void);
int timeout_meth_settimeout(lua_State *L, p_timeout tm);
#define timeout_iszero(tm) ((tm)->block == 0.0)
#endif /* TIMEOUT_H */

View File

@ -0,0 +1,468 @@
/*=========================================================================*\
* UDP object
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "socket.h"
#include "inet.h"
#include "options.h"
#include "udp.h"
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create6(lua_State *L);
static int meth_send(lua_State *L);
static int meth_sendto(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_receivefrom(lua_State *L);
static int meth_getfamily(lua_State *L);
static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L);
static int meth_setsockname(lua_State *L);
static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
/* udp object methods */
static luaL_Reg udp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"close", meth_close},
{"dirty", meth_dirty},
{"getfamily", meth_getfamily},
{"getfd", meth_getfd},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
{"receive", meth_receive},
{"receivefrom", meth_receivefrom},
{"send", meth_send},
{"sendto", meth_sendto},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"getoption", meth_getoption},
{"setpeername", meth_setpeername},
{"setsockname", meth_setsockname},
{"settimeout", meth_settimeout},
{NULL, NULL}
};
/* socket options for setoption */
static t_opt optset[] = {
{"dontroute", opt_set_dontroute},
{"broadcast", opt_set_broadcast},
{"reuseaddr", opt_set_reuseaddr},
{"reuseport", opt_set_reuseport},
{"ip-multicast-if", opt_set_ip_multicast_if},
{"ip-multicast-ttl", opt_set_ip_multicast_ttl},
{"ip-multicast-loop", opt_set_ip_multicast_loop},
{"ip-add-membership", opt_set_ip_add_membership},
{"ip-drop-membership", opt_set_ip_drop_membersip},
{"ipv6-v6only", opt_set_ip6_v6only},
{NULL, NULL}
};
/* socket options for getoption */
static t_opt optget[] = {
{"ip-multicast-if", opt_get_ip_multicast_if},
{"ip-multicast-loop", opt_get_ip_multicast_loop},
{NULL, NULL}
};
/* functions in library namespace */
static luaL_Reg func[] = {
{"udp", global_create},
{"udp6", global_create6},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int udp_open(lua_State *L)
{
/* create classes */
auxiliar_newclass(L, "udp{connected}", udp_methods);
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
/* create class groups */
auxiliar_add2group(L, "udp{connected}", "udp{any}");
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
auxiliar_add2group(L, "udp{connected}", "select{able}");
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */
luaL_openlib(L, NULL, func, 0);
return 0;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
const char *udp_strerror(int err) {
/* a 'closed' error on an unconnected means the target address was not
* accepted by the transport layer */
if (err == IO_CLOSED) return "refused";
else return socket_strerror(err);
}
/*-------------------------------------------------------------------------*\
* Send data through connected udp socket
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
p_timeout tm = &udp->tm;
size_t count, sent = 0;
int err;
const char *data = luaL_checklstring(L, 2, &count);
timeout_markstart(tm);
err = socket_send(&udp->sock, data, count, &sent, tm);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
/*-------------------------------------------------------------------------*\
* Send data through unconnected udp socket
\*-------------------------------------------------------------------------*/
static int meth_sendto(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
size_t count, sent = 0;
const char *data = luaL_checklstring(L, 2, &count);
const char *ip = luaL_checkstring(L, 3);
unsigned short port = (unsigned short) luaL_checknumber(L, 4);
p_timeout tm = &udp->tm;
int err;
switch (udp->family) {
case PF_INET: {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
if (!my_inet_pton(AF_INET, ip, &addr.sin_addr))
luaL_argerror(L, 3, "invalid ip address");
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
if (!my_inet_pton(AF_INET6, ip, &addr.sin6_addr))
luaL_argerror(L, 3, "invalid ip address");
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm);
break;
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", udp->family);
return 2;
}
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushnumber(L, (lua_Number) sent);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_receive(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
int err;
p_timeout tm = &udp->tm;
count = MIN(count, sizeof(buffer));
timeout_markstart(tm);
err = socket_recv(&udp->sock, buffer, count, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
lua_pushlstring(L, buffer, got);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data and sender from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_receivefrom(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
char buffer[UDP_DATAGRAMSIZE];
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
int err;
p_timeout tm = &udp->tm;
timeout_markstart(tm);
count = MIN(count, sizeof(buffer));
switch (udp->family) {
case PF_INET: {
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err == IO_DONE) {
char addrstr[INET_ADDRSTRLEN];
lua_pushlstring(L, buffer, got);
if (!my_inet_ntop(AF_INET, &addr.sin_addr,
addrstr, sizeof(addrstr))) {
lua_pushnil(L);
lua_pushstring(L, "invalid source address");
return 2;
}
lua_pushstring(L, addrstr);
lua_pushnumber(L, ntohs(addr.sin_port));
return 3;
}
break;
}
case PF_INET6: {
struct sockaddr_in6 addr;
socklen_t addr_len = sizeof(addr);
err = socket_recvfrom(&udp->sock, buffer, count, &got,
(SA *) &addr, &addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err == IO_CLOSED)
err = IO_DONE;
if (err == IO_DONE) {
char addrstr[INET6_ADDRSTRLEN];
lua_pushlstring(L, buffer, got);
if (!my_inet_ntop(AF_INET6, &addr.sin6_addr,
addrstr, sizeof(addrstr))) {
lua_pushnil(L);
lua_pushstring(L, "invalid source address");
return 2;
}
lua_pushstring(L, addrstr);
lua_pushnumber(L, ntohs(addr.sin6_port));
return 3;
}
break;
}
default:
lua_pushnil(L);
lua_pushfstring(L, "unknown family %d", udp->family);
return 2;
}
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
return 2;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
if (udp->family == PF_INET6) {
lua_pushliteral(L, "inet6");
return 1;
} else {
lua_pushliteral(L, "inet4");
return 1;
}
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
lua_pushnumber(L, (int) udp->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
udp->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
(void) udp;
lua_pushboolean(L, 0);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call inet methods
\*-------------------------------------------------------------------------*/
static int meth_getpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
return inet_meth_getpeername(L, &udp->sock, udp->family);
}
static int meth_getsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return inet_meth_getsockname(L, &udp->sock, udp->family);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_setoption(L, optset, &udp->sock);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_getoption(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return opt_meth_getoption(L, optget, &udp->sock);
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
return timeout_meth_settimeout(L, &udp->tm);
}
/*-------------------------------------------------------------------------*\
* Turns a master udp object into a client object.
\*-------------------------------------------------------------------------*/
static int meth_setpeername(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
p_timeout tm = &udp->tm;
const char *address = luaL_checkstring(L, 2);
int connecting = strcmp(address, "*");
const char *port = connecting? luaL_checkstring(L, 3): "0";
struct addrinfo connecthints;
const char *err;
memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_DGRAM;
/* make sure we try to connect only to the same family */
connecthints.ai_family = udp->family;
if (connecting) {
err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
auxiliar_setclass(L, "udp{connected}", 1);
} else {
/* we ignore possible errors because Mac OS X always
* returns EAFNOSUPPORT */
inet_trydisconnect(&udp->sock, udp->family, tm);
auxiliar_setclass(L, "udp{unconnected}", 1);
}
/* change class to connected or unconnected depending on address */
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
socket_destroy(&udp->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master object into a server object
\*-------------------------------------------------------------------------*/
static int meth_setsockname(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
const char *address = luaL_checkstring(L, 2);
const char *port = luaL_checkstring(L, 3);
const char *err;
struct addrinfo bindhints;
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_DGRAM;
bindhints.ai_family = udp->family;
bindhints.ai_flags = AI_PASSIVE;
err = inet_trybind(&udp->sock, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master udp object
\*-------------------------------------------------------------------------*/
static int udp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
/* try to allocate a system socket */
if (!err) {
/* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {
int yes = 1;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&yes, sizeof(yes));
}
udp->sock = sock;
timeout_init(&udp->tm, -1, -1);
udp->family = family;
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
static int global_create(lua_State *L) {
return udp_create(L, AF_INET);
}
static int global_create6(lua_State *L) {
return udp_create(L, AF_INET6);
}

View File

@ -0,0 +1,32 @@
#ifndef UDP_H
#define UDP_H
/*=========================================================================*\
* UDP object
* LuaSocket toolkit
*
* The udp.h module provides LuaSocket with support for UDP protocol
* (AF_INET, SOCK_DGRAM).
*
* Two classes are defined: connected and unconnected. UDP objects are
* originally unconnected. They can be "connected" to a given address
* with a call to the setpeername function. The same function can be used to
* break the connection.
\*=========================================================================*/
#include "lua.h"
#include "timeout.h"
#include "socket.h"
/* can't be larger than wsocket.c MAXCHUNK!!! */
#define UDP_DATAGRAMSIZE 8192
typedef struct t_udp_ {
t_socket sock;
t_timeout tm;
int family;
} t_udp;
typedef t_udp *p_udp;
int udp_open(lua_State *L);
#endif /* UDP_H */

View File

@ -0,0 +1,340 @@
/*=========================================================================*\
* Unix domain socket
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "auxiliar.h"
#include "socket.h"
#include "options.h"
#include "unix.h"
#include <sys/un.h>
/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
static int meth_getstats(lua_State *L);
static int meth_setstats(lua_State *L);
static const char *unix_tryconnect(p_unix un, const char *path);
static const char *unix_trybind(p_unix un, const char *path);
/* unix object methods */
static luaL_Reg unix_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
{"getfd", meth_getfd},
{"getstats", meth_getstats},
{"setstats", meth_setstats},
{"listen", meth_listen},
{"receive", meth_receive},
{"send", meth_send},
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"setpeername", meth_connect},
{"setsockname", meth_bind},
{"settimeout", meth_settimeout},
{"shutdown", meth_shutdown},
{NULL, NULL}
};
/* socket option handlers */
static t_opt optset[] = {
{"keepalive", opt_set_keepalive},
{"reuseaddr", opt_set_reuseaddr},
{"linger", opt_set_linger},
{NULL, NULL}
};
/* our socket creation function */
static luaL_Reg func[] = {
{"unix", global_create},
{NULL, NULL}
};
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int luaopen_socket_unix(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "unix{master}", unix_methods);
auxiliar_newclass(L, "unix{client}", unix_methods);
auxiliar_newclass(L, "unix{server}", unix_methods);
/* create class groups */
auxiliar_add2group(L, "unix{master}", "unix{any}");
auxiliar_add2group(L, "unix{client}", "unix{any}");
auxiliar_add2group(L, "unix{server}", "unix{any}");
/* make sure the function ends up in the package table */
luaL_openlib(L, "socket", func, 0);
/* return the function instead of the 'socket' table */
lua_pushstring(L, "unix");
lua_gettable(L, -2);
return 1;
}
/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_send(L, &un->buf);
}
static int meth_receive(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_receive(L, &un->buf);
}
static int meth_getstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_getstats(L, &un->buf);
}
static int meth_setstats(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
return buffer_meth_setstats(L, &un->buf);
}
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
static int meth_setoption(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
return opt_meth_setoption(L, optset, &un->sock);
}
/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
lua_pushnumber(L, (int) un->sock);
return 1;
}
/* this is very dangerous, but can be handy for those that are brave enough */
static int meth_setfd(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
un->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
static int meth_dirty(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
lua_pushboolean(L, !buffer_isempty(&un->buf));
return 1;
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L) {
p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
/* if successful, push client socket */
if (err == IO_DONE) {
p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
auxiliar_setclass(L, "unix{client}", -1);
/* initialize structure fields */
socket_setnonblocking(&sock);
clnt->sock = sock;
io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
static const char *unix_trybind(p_unix un, const char *path) {
struct sockaddr_un local;
size_t len = strlen(path);
int err;
if (len >= sizeof(local.sun_path)) return "path too long";
memset(&local, 0, sizeof(local));
strcpy(local.sun_path, path);
local.sun_family = AF_UNIX;
#ifdef UNIX_HAS_SUN_LEN
local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
+ len + 1;
err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
#else
err = socket_bind(&un->sock, (SA *) &local,
(socklen_t)(sizeof(local.sun_family) + len));
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_bind(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unix_trybind(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Turns a master unix object into a client object.
\*-------------------------------------------------------------------------*/
static const char *unix_tryconnect(p_unix un, const char *path)
{
struct sockaddr_un remote;
int err;
size_t len = strlen(path);
if (len >= sizeof(remote.sun_path)) return "path too long";
memset(&remote, 0, sizeof(remote));
strcpy(remote.sun_path, path);
remote.sun_family = AF_UNIX;
timeout_markstart(&un->tm);
#ifdef UNIX_HAS_SUN_LEN
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
+ len + 1;
err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
#else
err = socket_connect(&un->sock, (SA *) &remote,
(socklen_t)(sizeof(remote.sun_family) + len), &un->tm);
#endif
if (err != IO_DONE) socket_destroy(&un->sock);
return socket_strerror(err);
}
static int meth_connect(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
const char *path = luaL_checkstring(L, 2);
const char *err = unix_tryconnect(un, path);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
/* turn master object into a client object */
auxiliar_setclass(L, "unix{client}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
socket_destroy(&un->sock);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
{
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
int backlog = (int) luaL_optnumber(L, 2, 32);
int err = socket_listen(&un->sock, backlog);
if (err != IO_DONE) {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
/* turn master object into a server object */
auxiliar_setclass(L, "unix{server}", 1);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Shuts the connection down partially
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
static const char* methods[] = { "receive", "send", "both", NULL };
p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
int how = luaL_checkoption(L, 2, "both", methods);
socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L) {
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
return timeout_meth_settimeout(L, &un->tm);
}
/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master unix object
\*-------------------------------------------------------------------------*/
static int global_create(lua_State *L) {
t_socket sock;
int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
/* try to allocate a system socket */
if (err == IO_DONE) {
/* allocate unix object */
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
/* set its type as master object */
auxiliar_setclass(L, "unix{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
un->sock = sock;
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &un->sock);
timeout_init(&un->tm, -1, -1);
buffer_init(&un->buf, &un->io, &un->tm);
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, socket_strerror(err));
return 2;
}
}

View File

@ -0,0 +1,26 @@
#ifndef UNIX_H
#define UNIX_H
/*=========================================================================*\
* Unix domain object
* LuaSocket toolkit
*
* This module is just an example of how to extend LuaSocket with a new
* domain.
\*=========================================================================*/
#include "lua.h"
#include "luasocket.h"
#include "luasocket_buffer.h"
#include "timeout.h"
#include "socket.h"
typedef struct t_unix_ {
t_socket sock;
t_io io;
t_buffer buf;
t_timeout tm;
} t_unix;
typedef t_unix *p_unix;
LUASOCKET_API int luaopen_socket_unix(lua_State *L);
#endif /* UNIX_H */

View File

@ -0,0 +1,449 @@
/*=========================================================================*\
* Socket compatibilization module for Unix
* LuaSocket toolkit
*
* The code is now interrupt-safe.
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
\*=========================================================================*/
#include <string.h>
#include <signal.h>
#include "socket.h"
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
#ifndef SOCKET_SELECT
#include <sys/poll.h>
#define WAITFD_R POLLIN
#define WAITFD_W POLLOUT
#define WAITFD_C (POLLIN|POLLOUT)
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
struct pollfd pfd;
pfd.fd = *ps;
pfd.events = sw;
pfd.revents = 0;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
int t = (int)(timeout_getretry(tm)*1e3);
ret = poll(&pfd, 1, t >= 0? t: -1);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
return IO_DONE;
}
#else
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_C (WAITFD_R|WAITFD_W)
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, *rp, *wp;
struct timeval tv, *tp;
double t;
if (*ps >= FD_SETSIZE) return EINVAL;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
do {
/* must set bits within loop, because select may have modifed them */
rp = wp = NULL;
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; }
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
t = timeout_getretry(tm);
tp = NULL;
if (t >= 0.0) {
tv.tv_sec = (int)t;
tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(*ps+1, rp, wp, NULL, tp);
} while (ret == -1 && errno == EINTR);
if (ret == -1) return errno;
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED;
return IO_DONE;
}
#endif
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
/* instals a handler to ignore sigpipe or it will crash us */
signal(SIGPIPE, SIG_IGN);
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
return 1;
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps);
close(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
* Select with timeout control
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
int ret;
do {
struct timeval tv;
double t = timeout_getretry(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
/* timeout = 0 means no wait */
ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL);
} while (ret < 0 && errno == EINTR);
return ret;
}
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
int socket_create(p_socket ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCKET_INVALID) return IO_DONE;
else return errno;
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
int err = IO_DONE;
socket_setblocking(ps);
if (bind(*ps, addr, len) < 0) err = errno;
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
socket_setblocking(ps);
if (listen(*ps, backlog)) err = errno;
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
shutdown(*ps, how);
socket_setnonblocking(ps);
}
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
int err;
/* avoid calling on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* call connect until done or failed without being interrupted */
do if (connect(*ps, addr, len) == 0) return IO_DONE;
while ((err = errno) == EINTR);
/* if connection failed immediately, return error code */
if (err != EINPROGRESS && err != EAGAIN) return err;
/* zero timeout case optimization */
if (timeout_iszero(tm)) return IO_TIMEOUT;
/* wait until we have the result of the connection attempt or timeout */
err = socket_waitfd(ps, WAITFD_C, tm);
if (err == IO_CLOSED) {
if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE;
else return errno;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int err;
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
err = errno;
if (err == EINTR) continue;
if (err != EAGAIN && err != ECONNABORTED) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Send with timeout
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
long put = (long) send(*ps, data, count, 0);
/* if we sent anything, we are done */
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
if (err != EAGAIN) return err;
/* wait until we can send something or we timeout */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
*sent = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long put = (long) sendto(*ps, data, count, 0, addr, len);
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
if (err == EPIPE) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) recv(*ps, data, count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) recvfrom(*ps, data, count, 0, addr, len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Write with timeout
*
* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
* with send/recv replaced with write/read. We can't just use write/read
* in the socket version, because behaviour when size is zero is different.
\*-------------------------------------------------------------------------*/
int socket_write(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
long put = (long) write(*ps, data, count);
/* if we sent anything, we are done */
if (put >= 0) {
*sent = put;
return IO_DONE;
}
err = errno;
/* EPIPE means the connection was closed */
if (err == EPIPE) return IO_CLOSED;
/* we call was interrupted, just try again */
if (err == EINTR) continue;
/* if failed fatal reason, report error */
if (err != EAGAIN) return err;
/* wait until we can send something or we timeout */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
/* can't reach here */
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Read with timeout
* See note for socket_write
\*-------------------------------------------------------------------------*/
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
long taken = (long) read(*ps, data, count);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
err = errno;
if (taken == 0) return IO_CLOSED;
if (err == EINTR) continue;
if (err != EAGAIN) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags &= (~(O_NONBLOCK));
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
int flags = fcntl(*ps, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(*ps, F_SETFL, flags);
}
/*-------------------------------------------------------------------------*\
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
if (*hp) return IO_DONE;
else if (h_errno) return h_errno;
else if (errno) return errno;
else return IO_UNKNOWN;
}
int socket_gethostbyname(const char *addr, struct hostent **hp) {
*hp = gethostbyname(addr);
if (*hp) return IO_DONE;
else if (h_errno) return h_errno;
else if (errno) return errno;
else return IO_UNKNOWN;
}
/*-------------------------------------------------------------------------*\
* Error translation functions
* Make sure important error messages are standard
\*-------------------------------------------------------------------------*/
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case HOST_NOT_FOUND: return "host not found";
default: return hstrerror(err);
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case EADDRINUSE: return "address already in use";
case EISCONN: return "already connected";
case EACCES: return "permission denied";
case ECONNREFUSED: return "connection refused";
case ECONNABORTED: return "closed";
case ECONNRESET: return "closed";
case ETIMEDOUT: return "timeout";
default: return strerror(err);
}
}
const char *socket_ioerror(p_socket ps, int err) {
(void) ps;
return socket_strerror(err);
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
case EAI_OVERFLOW: return "argument buffer overflow";
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
case EAI_SYSTEM: return strerror(errno);
default: return gai_strerror(err);
}
}

View File

@ -0,0 +1,43 @@
#ifndef USOCKET_H
#define USOCKET_H
/*=========================================================================*\
* Socket compatibilization module for Unix
* LuaSocket toolkit
\*=========================================================================*/
/*=========================================================================*\
* BSD include files
\*=========================================================================*/
/* error codes */
#include <errno.h>
/* close function */
#include <unistd.h>
/* fnctnl function and associated constants */
#include <fcntl.h>
/* struct sockaddr */
#include <sys/types.h>
/* socket function */
#include <sys/socket.h>
/* struct timeval */
#include <sys/time.h>
/* gethostbyname and gethostbyaddr functions */
#include <netdb.h>
/* sigpipe handling */
#include <signal.h>
/* IP stuff*/
#include <netinet/in.h>
#include <arpa/inet.h>
/* TCP options (nagle algorithm disable) */
#include <netinet/tcp.h>
#ifndef SO_REUSEPORT
#define SO_REUSEPORT SO_REUSEADDR
#endif
typedef int t_socket;
typedef t_socket *p_socket;
typedef struct sockaddr_storage t_sockaddr_storage;
#define SOCKET_INVALID (-1)
#endif /* USOCKET_H */

View File

@ -0,0 +1,413 @@
/*=========================================================================*\
* Socket compatibilization module for Win32
* LuaSocket toolkit
*
* The penalty of calling select to avoid busy-wait is only paid when
* the I/O call fail in the first place.
\*=========================================================================*/
#include <string.h>
#include "socket.h"
/* WinSock doesn't have a strerror... */
static const char *wstrerror(int err);
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int socket_open(void) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
int err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) return 0;
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
WSACleanup();
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*\
* Close module
\*-------------------------------------------------------------------------*/
int socket_close(void) {
WSACleanup();
return 1;
}
/*-------------------------------------------------------------------------*\
* Wait for readable/writable/connected socket with timeout
\*-------------------------------------------------------------------------*/
#define WAITFD_R 1
#define WAITFD_W 2
#define WAITFD_E 4
#define WAITFD_C (WAITFD_E|WAITFD_W)
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
int ret;
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
struct timeval tv, *tp = NULL;
double t;
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
if (sw & WAITFD_R) {
FD_ZERO(&rfds);
FD_SET(*ps, &rfds);
rp = &rfds;
}
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
if ((t = timeout_get(tm)) >= 0.0) {
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
tp = &tv;
}
ret = select(0, rp, wp, ep, tp);
if (ret == -1) return WSAGetLastError();
if (ret == 0) return IO_TIMEOUT;
if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
return IO_DONE;
}
/*-------------------------------------------------------------------------*\
* Select with int timeout in ms
\*-------------------------------------------------------------------------*/
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
p_timeout tm) {
struct timeval tv;
double t = timeout_get(tm);
tv.tv_sec = (int) t;
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
if (n <= 0) {
Sleep((DWORD) (1000*t));
return 0;
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
}
/*-------------------------------------------------------------------------*\
* Close and inutilize socket
\*-------------------------------------------------------------------------*/
void socket_destroy(p_socket ps) {
if (*ps != SOCKET_INVALID) {
socket_setblocking(ps); /* close can take a long time on WIN32 */
closesocket(*ps);
*ps = SOCKET_INVALID;
}
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
void socket_shutdown(p_socket ps, int how) {
socket_setblocking(ps);
shutdown(*ps, how);
socket_setnonblocking(ps);
}
/*-------------------------------------------------------------------------*\
* Creates and sets up a socket
\*-------------------------------------------------------------------------*/
int socket_create(p_socket ps, int domain, int type, int protocol) {
*ps = socket(domain, type, protocol);
if (*ps != SOCKET_INVALID) return IO_DONE;
else return WSAGetLastError();
}
/*-------------------------------------------------------------------------*\
* Connects or returns error message
\*-------------------------------------------------------------------------*/
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
int err;
/* don't call on closed socket */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* ask system to connect */
if (connect(*ps, addr, len) == 0) return IO_DONE;
/* make sure the system is trying to connect */
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
/* zero timeout case optimization */
if (timeout_iszero(tm)) return IO_TIMEOUT;
/* we wait until something happens */
err = socket_waitfd(ps, WAITFD_C, tm);
if (err == IO_CLOSED) {
int len = sizeof(err);
/* give windows time to set the error (yes, disgusting) */
Sleep(10);
/* find out why we failed */
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
/* we KNOW there was an error. if 'why' is 0, we will return
* "unknown error", but it's not really our fault */
return err > 0? err: IO_UNKNOWN;
} else return err;
}
/*-------------------------------------------------------------------------*\
* Binds or returns error message
\*-------------------------------------------------------------------------*/
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
int err = IO_DONE;
socket_setblocking(ps);
if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
*
\*-------------------------------------------------------------------------*/
int socket_listen(p_socket ps, int backlog) {
int err = IO_DONE;
socket_setblocking(ps);
if (listen(*ps, backlog) < 0) err = WSAGetLastError();
socket_setnonblocking(ps);
return err;
}
/*-------------------------------------------------------------------------*\
* Accept with timeout
\*-------------------------------------------------------------------------*/
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
p_timeout tm) {
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int err;
/* try to get client socket */
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
/* find out why we failed */
err = WSAGetLastError();
/* if we failed because there was no connectoin, keep trying */
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
/* call select to avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Send with timeout
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
* this can take an awful lot of time and we will end up blocked.
* Therefore, whoever calls this function should not pass a huge buffer.
\*-------------------------------------------------------------------------*/
int socket_send(p_socket ps, const char *data, size_t count,
size_t *sent, p_timeout tm)
{
int err;
*sent = 0;
/* avoid making system calls on closed sockets */
if (*ps == SOCKET_INVALID) return IO_CLOSED;
/* loop until we send something or we give up on error */
for ( ;; ) {
/* try to send something */
int put = send(*ps, data, (int) count, 0);
/* if we sent something, we are done */
if (put > 0) {
*sent = put;
return IO_DONE;
}
/* deal with failure */
err = WSAGetLastError();
/* we can only proceed if there was no serious error */
if (err != WSAEWOULDBLOCK) return err;
/* avoid busy wait */
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Sendto with timeout
\*-------------------------------------------------------------------------*/
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
SA *addr, socklen_t len, p_timeout tm)
{
int err;
*sent = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int put = sendto(*ps, data, (int) count, 0, addr, len);
if (put > 0) {
*sent = put;
return IO_DONE;
}
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Receive with timeout
\*-------------------------------------------------------------------------*/
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int taken = recv(*ps, data, (int) count, 0);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Recvfrom with timeout
\*-------------------------------------------------------------------------*/
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
SA *addr, socklen_t *len, p_timeout tm) {
int err;
*got = 0;
if (*ps == SOCKET_INVALID) return IO_CLOSED;
for ( ;; ) {
int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
if (taken == 0) return IO_CLOSED;
err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) return err;
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
}
}
/*-------------------------------------------------------------------------*\
* Put socket into blocking mode
\*-------------------------------------------------------------------------*/
void socket_setblocking(p_socket ps) {
u_long argp = 0;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* Put socket into non-blocking mode
\*-------------------------------------------------------------------------*/
void socket_setnonblocking(p_socket ps) {
u_long argp = 1;
ioctlsocket(*ps, FIONBIO, &argp);
}
/*-------------------------------------------------------------------------*\
* DNS helpers
\*-------------------------------------------------------------------------*/
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
*hp = gethostbyaddr(addr, len, AF_INET);
if (*hp) return IO_DONE;
else return WSAGetLastError();
}
int socket_gethostbyname(const char *addr, struct hostent **hp) {
*hp = gethostbyname(addr);
if (*hp) return IO_DONE;
else return WSAGetLastError();
}
/*-------------------------------------------------------------------------*\
* Error translation functions
\*-------------------------------------------------------------------------*/
const char *socket_hoststrerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAHOST_NOT_FOUND: return "host not found";
default: return wstrerror(err);
}
}
const char *socket_strerror(int err) {
if (err <= 0) return io_strerror(err);
switch (err) {
case WSAEADDRINUSE: return "address already in use";
case WSAECONNREFUSED: return "connection refused";
case WSAEISCONN: return "already connected";
case WSAEACCES: return "permission denied";
case WSAECONNABORTED: return "closed";
case WSAECONNRESET: return "closed";
case WSAETIMEDOUT: return "timeout";
default: return wstrerror(err);
}
}
const char *socket_ioerror(p_socket ps, int err) {
(void) ps;
return socket_strerror(err);
}
static const char *wstrerror(int err) {
switch (err) {
case WSAEINTR: return "Interrupted function call";
case WSAEACCES: return "Permission denied";
case WSAEFAULT: return "Bad address";
case WSAEINVAL: return "Invalid argument";
case WSAEMFILE: return "Too many open files";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
case WSAEINPROGRESS: return "Operation now in progress";
case WSAEALREADY: return "Operation already in progress";
case WSAENOTSOCK: return "Socket operation on nonsocket";
case WSAEDESTADDRREQ: return "Destination address required";
case WSAEMSGSIZE: return "Message too long";
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
case WSAENOPROTOOPT: return "Bad protocol option";
case WSAEPROTONOSUPPORT: return "Protocol not supported";
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
case WSAEOPNOTSUPP: return "Operation not supported";
case WSAEPFNOSUPPORT: return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE: return "Address already in use";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
case WSAENETDOWN: return "Network is down";
case WSAENETUNREACH: return "Network is unreachable";
case WSAENETRESET: return "Network dropped connection on reset";
case WSAECONNABORTED: return "Software caused connection abort";
case WSAECONNRESET: return "Connection reset by peer";
case WSAENOBUFS: return "No buffer space available";
case WSAEISCONN: return "Socket is already connected";
case WSAENOTCONN: return "Socket is not connected";
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
case WSAETIMEDOUT: return "Connection timed out";
case WSAECONNREFUSED: return "Connection refused";
case WSAEHOSTDOWN: return "Host is down";
case WSAEHOSTUNREACH: return "No route to host";
case WSAEPROCLIM: return "Too many processes";
case WSASYSNOTREADY: return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON: return "Graceful shutdown in progress";
case WSAHOST_NOT_FOUND: return "Host not found";
case WSATRY_AGAIN: return "Nonauthoritative host not found";
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
case WSANO_DATA: return "Valid name, no data record of requested type";
default: return "Unknown error";
}
}
const char *socket_gaistrerror(int err) {
if (err == 0) return NULL;
switch (err) {
case EAI_AGAIN: return "temporary failure in name resolution";
case EAI_BADFLAGS: return "invalid value for ai_flags";
#ifdef EAI_BADHINTS
case EAI_BADHINTS: return "invalid value for hints";
#endif
case EAI_FAIL: return "non-recoverable failure in name resolution";
case EAI_FAMILY: return "ai_family not supported";
case EAI_MEMORY: return "memory allocation failure";
case EAI_NONAME:
return "host or service not provided, or not known";
// case EAI_OVERFLOW: return "argument buffer overflow";
#ifdef EAI_PROTOCOL
case EAI_PROTOCOL: return "resolved protocol is unknown";
#endif
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
// case EAI_SYSTEM: return strerror(errno);
default: return gai_strerrorA(err);
}
}

View File

@ -0,0 +1,25 @@
#ifndef WSOCKET_H
#define WSOCKET_H
/*=========================================================================*\
* Socket compatibilization module for Win32
* LuaSocket toolkit
\*=========================================================================*/
/*=========================================================================*\
* WinSock include files
\*=========================================================================*/
#include <winsock2.h>
#include <ws2tcpip.h>
typedef int socklen_t;
typedef SOCKADDR_STORAGE t_sockaddr_storage;
typedef SOCKET t_socket;
typedef t_socket *p_socket;
#define SOCKET_INVALID (INVALID_SOCKET)
#ifndef SO_REUSEPORT
#define SO_REUSEPORT SO_REUSEADDR
#endif
#endif /* WSOCKET_H */

View File

@ -367,3 +367,165 @@ cc.LabelEffect =
GLOW = 3,
}
cc.KeyCode =
{
KEY_NONE = 0,
KEY_PAUSE = 0x0013,
KEY_SCROLL_LOCK = 0x1014,
KEY_PRINT = 0x1061,
KEY_SYSREQ = 0x106A,
KEY_BREAK = 0x106B,
KEY_ESCAPE = 0x001B,
KEY_BACKSPACE = 0x0008,
KEY_TAB = 0x0009,
KEY_BACK_TAB = 0x0089,
KEY_RETURN = 0x000D,
KEY_CAPS_LOCK = 0x00E5,
KEY_SHIFT = 0x00E1,
KEY_CTRL = 0x00E3,
KEY_ALT = 0x00E9,
KEY_MENU = 0x1067,
KEY_HYPER = 0x10ED,
KEY_INSERT = 0x1063,
KEY_HOME = 0x1050,
KEY_PG_UP = 0x1055,
KEY_DELETE = 0x10FF,
KEY_END = 0x1057,
KEY_PG_DOWN = 0x1056,
KEY_LEFT_ARROW = 0x1051,
KEY_RIGHT_ARROW = 0x1053,
KEY_UP_ARROW = 0x1052,
KEY_DOWN_ARROW = 0x1054,
KEY_NUM_LOCK = 0x107F,
KEY_KP_PLUS = 0x10AB,
KEY_KP_MINUS = 0x10AD,
KEY_KP_MULTIPLY = 0x10AA,
KEY_KP_DIVIDE = 0x10AF,
KEY_KP_ENTER = 0x108D,
KEY_KP_HOME = 0x10B7,
KEY_KP_UP = 0x10B8,
KEY_KP_PG_UP = 0x10B9,
KEY_KP_LEFT = 0x10B4,
KEY_KP_FIVE = 0x10B5,
KEY_KP_RIGHT = 0x10B6,
KEY_KP_END = 0x10B1,
KEY_KP_DOWN = 0x10B2,
KEY_KP_PG_DOWN = 0x10B3,
KEY_KP_INSERT = 0x10B0,
KEY_KP_DELETE = 0x10AE,
KEY_F1 = 0x00BE,
KEY_F2 = 0x00BF,
KEY_F3 = 0x00C0,
KEY_F4 = 0x00C1,
KEY_F5 = 0x00C2,
KEY_F6 = 0x00C3,
KEY_F7 = 0x00C4,
KEY_F8 = 0x00C5,
KEY_F9 = 0x00C6,
KEY_F10 = 0x00C7,
KEY_F11 = 0x00C8,
KEY_F12 = 0x00C9,
KEY_SPACE = ' ',
KEY_EXCLAM = '!',
KEY_QUOTE = '"',
KEY_NUMBER = '#',
KEY_DOLLAR = '$',
KEY_PERCENT = '%',
KEY_CIRCUMFLEX = '^',
KEY_AMPERSAND = '&',
KEY_APOSTROPHE = '\'',
KEY_LEFT_PARENTHESIS = '(',
KEY_RIGHT_PARENTHESIS = ')',
KEY_ASTERISK = '*',
KEY_PLUS = '+',
KEY_COMMA = ',',
KEY_MINUS = '-',
KEY_PERIOD = '.',
KEY_SLASH = '/',
KEY_0 = '0',
KEY_1 = '1',
KEY_2 = '2',
KEY_3 = '3',
KEY_4 = '4',
KEY_5 = '5',
KEY_6 = '6',
KEY_7 = '7',
KEY_8 = '8',
KEY_9 = '9',
KEY_COLON = ':',
KEY_SEMICOLON = ';',
KEY_LESS_THAN = '<',
KEY_EQUAL = '=',
KEY_GREATER_THAN = '>',
KEY_QUESTION = '?',
KEY_AT = '@',
KEY_CAPITAL_A = 'A',
KEY_CAPITAL_B = 'B',
KEY_CAPITAL_C = 'C',
KEY_CAPITAL_D = 'D',
KEY_CAPITAL_E = 'E',
KEY_CAPITAL_F = 'F',
KEY_CAPITAL_G = 'G',
KEY_CAPITAL_H = 'H',
KEY_CAPITAL_I = 'I',
KEY_CAPITAL_J = 'J',
KEY_CAPITAL_K = 'K',
KEY_CAPITAL_L = 'L',
KEY_CAPITAL_M = 'M',
KEY_CAPITAL_N = 'N',
KEY_CAPITAL_O = 'O',
KEY_CAPITAL_P = 'P',
KEY_CAPITAL_Q = 'Q',
KEY_CAPITAL_R = 'R',
KEY_CAPITAL_S = 'S',
KEY_CAPITAL_T = 'T',
KEY_CAPITAL_U = 'U',
KEY_CAPITAL_V = 'V',
KEY_CAPITAL_W = 'W',
KEY_CAPITAL_X = 'X',
KEY_CAPITAL_Y = 'Y',
KEY_CAPITAL_Z = 'Z',
KEY_LEFT_BRACKET = '[',
KEY_BACK_SLASH = '\\',
KEY_RIGHT_BRACKET = ']',
KEY_UNDERSCORE = '_',
KEY_GRAVE = '`',
KEY_A = 'a',
KEY_B = 'b',
KEY_C = 'c',
KEY_D = 'd',
KEY_E = 'e',
KEY_F = 'f',
KEY_G = 'g',
KEY_H = 'h',
KEY_I = 'i',
KEY_J = 'j',
KEY_K = 'k',
KEY_L = 'l',
KEY_M = 'm',
KEY_N = 'n',
KEY_O = 'o',
KEY_P = 'p',
KEY_Q = 'q',
KEY_R = 'r',
KEY_S = 's',
KEY_T = 't',
KEY_U = 'u',
KEY_V = 'v',
KEY_W = 'w',
KEY_X = 'x',
KEY_Y = 'y',
KEY_Z = 'z',
KEY_LEFT_BRACE = '{',
KEY_BAR = '|',
KEY_RIGHT_BRACE = '}',
KEY_TILDE = '~',
KEY_EURO = 0x20AC,
KEY_POUND = 0x00A3,
KEY_YEN = 0x00A5,
KEY_MIDDLE_DOT = 0x0095,
KEY_SEARCH = 0xFFAA,
};

View File

@ -45,11 +45,13 @@
- [`ccTypes.h`](#cctypesh)
- [deprecated functions and global variables](#deprecated-functions-and--global-variables)
- [Changes in the Lua bindings](#changes-in-the-lua-bindings)
- [Use bindings-generator tool for Lua binding](#use-bindings-generator-tool-for-lua-binding)
- [Use bindings-generator tool for lua binding](#use-bindings-generator-tool-for-lua-binding)
- [Bind the classes with namespace to lua](#bind-the-classes-with-namespace-to-lua)
- [Use ScriptHandlerMgr to manage the register and unregister of lua function](#use-scripthandlermgr-to-manage-the-register-and-unregister-of-lua-function)
- [Use "cc" and "ccs" as module name](#use-cc-and-ccs-as-module-name)
- [Deprecated funtions, tables and classes](#deprecated-funtions-tables-and-classes)
- [Use the lua table instead of the some structs and classes binding](#use-the-lua-table-instead-of-the-some-structs-and-classes-binding)
- [Integrate more modules into lua](#integrate-more-modules-into-lua)
- [Known issues](#known-issues)
# Misc Information
@ -663,9 +665,21 @@ color3B = Color3B::WHITE;
## Changes in the Lua bindings
### Use bindings-generator tool for Lua binding
### Use bindings-generator tool for lua binding
Only configurating the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files
Only have to write an ini file for a module, don't have to write a lot of .pkg files
### Bind the classes with namespace to lua
In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, `CCNode` will be changed to `cc.Node`. This modification will affect some APIs as follows:
| v2.x | v3.0 |
| tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") |
| tolua_isusertable(tolua_S,1,"CCNode",0,&tolua_err | tolua_isusertable(tolua_S,1,"cc.Node",0,&tolua_err |
| tolua_isusertype(tolua_S,1,"CCNode",0,&tolua_err) | tolua_isusertype(tolua_S,1,"cc.Node",0,&tolua_err) |
| toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"CCNode") | toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cc.Node") |
| tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCFileUtils") | tolua_pushusertype(tolua_S,(void*)tolua_ret,"cc.FileUtils") |
| tolua.cast(pChildren[i + 1], "CCNode") | tolua.cast(pChildren[i + 1], "cc.Node") |
### Use ScriptHandlerMgr to manage the register and unregister of Lua function
@ -686,20 +700,29 @@ In v3.0 version, we only need to add the `HandlerType` enum in the `ScriptHandle
ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HANDLERTYPE_MENU_CLICKED)
```
### Use "cc" and "ccs" as module name
### Use "cc"、"ccs"、"ccui" and "sp" as module name
The classes in the `cocos2d`、`cocos2d::extension`、`CocosDenshion` and `cocosbuilder` namespace were bound to lua in the `cc` module;
The classes in the `cocos2d::gui` namespace were bound to lua in the `ccui` module;
The classes in the `spine` namespace were bound to lua in the `sp` module;
The classes in the `cocostudio` namespace were bound to lua in the `ccs` module.
The main differences in the script are as follows:
```lua
// v2.x
CCSprite:create(s_pPathGrossini)
CCEaseIn:create(createSimpleMoveBy(), 2.5)
UILayout:create()
CCArmature:create("bear")
ImageView:create()
// v3.0
cc.Director:getInstance():getWinSize()
cc.EaseIn:create(createSimpleMoveBy(), 2.5)
ccs.UILayer:create()
ccs.Armature:create("bear")
ccui.ImageView:create()
```
### Deprecated funtions, tables and classes
@ -735,6 +758,24 @@ local color4B = cc.c4b(0,0,0,0)
Through the funtions of the LuaBasicConversion file,they can be converted the Lua table when they are as a parameter in the bindings generator.
### Integrate more modules into lua
In the version 3.0,more modules were bound to lua,specific as follows:
```
1.physics
2.spine
3.XMLHttpRequest
```
The XMLHttpRequest and physics are in the "cc" module,and the spine is in the "sp" module.
The related test cases located in:
```
physics ---> TestLua/PhysicsTest
spine ---> TestLua/SpineTest
XMLHttpRequest ---> TestLua/XMLHttpRequestTest
```
## Known issues

View File

@ -0,0 +1,20 @@
LuaSocket 2.0.2 license
Copyright © 2004-2007 Diego Nehab
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 above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
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.

View File

@ -142,6 +142,8 @@ bool UpdateLayer::init()
{
Layer::init();
createDownloadedDir();
/** Creates assets manager */
pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip",
"https://raw.github.com/minggo/AssetsManagerTest/master/version",
@ -151,8 +153,6 @@ bool UpdateLayer::init()
addChild(pAssetsManager);
pAssetsManager->release();
createDownloadedDir();
auto size = Director::getInstance()->getWinSize();
pItemReset = MenuItemFont::create("reset", CC_CALLBACK_1(UpdateLayer::reset,this));

View File

@ -419,7 +419,11 @@ Atlas3::Atlas3()
label2->setAnchorPoint( Point(0.5f, 0.5f) );
label2->setColor( Color3B::RED );
addChild(label2, 0, kTagBitmapAtlas2);
label2->runAction( repeat->clone() );
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
TintTo::create(1, 0, 255, 0),
TintTo::create(1, 0, 0, 255),
NULL);
label2->runAction( RepeatForever::create(tint) );
auto label3 = LabelBMFont::create("Test", "fonts/bitmapFontTest2.fnt");
// testing anchors

View File

@ -68,7 +68,9 @@ static std::function<Layer*()> createFunctions[] =
CL(LabelTTFDistanceField),
CL(LabelTTFDistanceFieldEffect),
CL(LabelCharMapTest),
CL(LabelCrashTest)
CL(LabelCharMapColorTest),
CL(LabelCrashTest),
CL(LabelTTFOldNew)
};
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
@ -164,17 +166,17 @@ LabelTTFAlignmentNew::LabelTTFAlignmentNew()
auto ttf0 = Label::createWithTTF(config,"Alignment 0\nnew line",TextHAlignment::LEFT);
ttf0->setPosition(Point(s.width/2,(s.height/6)*2 - 30));
ttf0->setAnchorPoint(Point(0.5f,0.5f));
ttf0->setAnchorPoint(Point::ANCHOR_MIDDLE);
this->addChild(ttf0);
auto ttf1 = Label::createWithTTF(config,"Alignment 1\nnew line",TextHAlignment::CENTER);
ttf1->setPosition(Point(s.width/2,(s.height/6)*3 - 30));
ttf1->setAnchorPoint(Point(0.5f,0.5f));
ttf1->setAnchorPoint(Point::ANCHOR_MIDDLE);
this->addChild(ttf1);
auto ttf2 = Label::createWithTTF(config,"Alignment 2\nnew line",TextHAlignment::RIGHT);
ttf2->setPosition(Point(s.width/2,(s.height/6)*4 - 30));
ttf2->setAnchorPoint(Point(0.5f,0.5f));
ttf2->setAnchorPoint(Point::ANCHOR_MIDDLE);
this->addChild(ttf2);
}
@ -206,10 +208,14 @@ LabelFNTColorAndOpacity::LabelFNTColorAndOpacity()
label1->runAction(repeat);
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
label2->setAnchorPoint( Point(0.5f, 0.5f) );
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
label2->setColor( Color3B::RED );
addChild(label2, 0, kTagBitmapAtlas2);
label2->runAction( repeat->clone() );
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
TintTo::create(1, 0, 255, 0),
TintTo::create(1, 0, 0, 255),
NULL);
label2->runAction( RepeatForever::create(tint) );
auto label3 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
label3->setAnchorPoint( Point(1,1) );
@ -259,7 +265,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
auto s = Director::getInstance()->getWinSize();
label->setPosition( Point(s.width/2, s.height/2) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
auto BChar = (Sprite*) label->getLetter(0);
@ -293,6 +299,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest.fnt", "00.0");
addChild(label2, 0, kTagBitmapAtlas2);
label2->setPosition( Point(s.width/2.0f, 80) );
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
auto lastChar = (Sprite*) label2->getLetter(3);
lastChar->runAction( rot_4ever->clone() );
@ -348,7 +355,7 @@ LabelFNTPadding::LabelFNTPadding()
auto s = Director::getInstance()->getWinSize();
label->setPosition( Point(s.width/2, s.height/2) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
}
std::string LabelFNTPadding::title() const
@ -369,17 +376,17 @@ LabelFNTOffset::LabelFNTOffset()
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "FaFeFiFoFu");
addChild(label);
label->setPosition( Point(s.width/2, s.height/2+50) );
label->setAnchorPoint( Point(0.5f, 0.5f) ) ;
label->setAnchorPoint( Point::ANCHOR_MIDDLE ) ;
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "fafefifofu");
addChild(label);
label->setPosition( Point(s.width/2, s.height/2) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "aeiou");
addChild(label);
label->setPosition( Point(s.width/2, s.height/2-50) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
}
std::string LabelFNTOffset::title() const
@ -401,18 +408,18 @@ LabelFNTColor::LabelFNTColor()
label->setColor( Color3B::BLUE );
addChild(label);
label->setPosition( Point(s.width/2, s.height/4) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Red");
addChild(label);
label->setPosition( Point(s.width/2, 2*s.height/4) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
label->setColor( Color3B::RED );
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Green");
addChild(label);
label->setPosition( Point(s.width/2, 3*s.height/4) );
label->setAnchorPoint( Point(0.5f, 0.5f) );
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
label->setColor( Color3B::GREEN );
label->setString("Green");
}
@ -441,7 +448,7 @@ LabelFNTHundredLabels::LabelFNTHundredLabels()
auto p = Point( CCRANDOM_0_1() * s.width, CCRANDOM_0_1() * s.height);
label->setPosition( p );
label->setAnchorPoint(Point(0.5f, 0.5f));
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
}
}
@ -470,7 +477,7 @@ LabelFNTMultiLine::LabelFNTMultiLine()
// Center
auto label2 = Label::createWithBMFont( "fonts/bitmapFontTest3.fnt", "Multi line\nCenter");
label2->setAnchorPoint(Point(0.5f, 0.5f));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label2, 0, kTagBitmapAtlas2);
s= label2->getContentSize();
@ -502,20 +509,24 @@ std::string LabelFNTMultiLine::subtitle() const
LabelFNTandTTFEmpty::LabelFNTandTTFEmpty()
{
auto s = Director::getInstance()->getWinSize();
float delta = s.height/4;
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest3.fnt", "", TextHAlignment::CENTER, s.width);
addChild(label1, 0, kTagBitmapAtlas1);
label1->setAnchorPoint(Point(0.5f, 0.5f));
label1->setPosition(Point(s.width/2, delta));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
label1->setPosition(Point(s.width/2, s.height - 100));
// LabelTTF
TTFConfig ttfConfig("fonts/arial.ttf",48);
auto label2 = Label::createWithTTF(ttfConfig,"", TextHAlignment::CENTER,s.width);
addChild(label2, 0, kTagBitmapAtlas2);
label2->setAnchorPoint(Point(0.5f, 0.5f));
label2->setPosition(Point(s.width/2, delta * 2));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
label2->setPosition(Point(s.width/2, s.height / 2));
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label3, 0, kTagBitmapAtlas3);
label3->setPosition(Point(s.width/2, 100));
schedule(schedule_selector(LabelFNTandTTFEmpty::updateStrings), 1.0f);
@ -526,11 +537,13 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
{
auto label1 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas1) );
auto label2 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas2) );
auto label3 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas3) );
if( ! setEmpty )
{
label1->setString("not empty");
label2->setString("not empty");
label3->setString("hi");
setEmpty = true;
}
@ -538,6 +551,7 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
{
label1->setString("");
label2->setString("");
label3->setString("");
setEmpty = false;
}
@ -550,7 +564,7 @@ std::string LabelFNTandTTFEmpty::title() const
std::string LabelFNTandTTFEmpty::subtitle() const
{
return "2 empty labels: new Label + .FNT and new Label + .TTF";
return "3 empty labels: new Label + FNT/TTF/CharMap";
}
LabelFNTRetina::LabelFNTRetina()
@ -559,7 +573,7 @@ LabelFNTRetina::LabelFNTRetina()
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/konqa32.fnt", "TESTING RETINA DISPLAY");
label1->setAnchorPoint(Point(0.5f, 0.5f));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
label1->setPosition(Point(s.width/2, s.height/2));
}
@ -583,7 +597,7 @@ LabelFNTGlyphDesigner::LabelFNTGlyphDesigner()
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/futura-48.fnt", "Testing Glyph Designer");
label1->setAnchorPoint(Point(0.5f, 0.5f));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
label1->setPosition(Point(s.width/2, s.height/2));
}
@ -605,7 +619,7 @@ LabelTTFUnicodeChinese::LabelTTFUnicodeChinese()
// like "Error 3 error C2146: syntax error : missing ')' before identifier 'label'";
TTFConfig ttfConfig("fonts/wt021.ttf",55,GlyphCollection::CUSTOM, "美好的一天啊");
auto label = Label::createWithTTF(ttfConfig,"美好的一天啊", TextHAlignment::CENTER, size.width);
label->setAnchorPoint(Point(0.5f, 0.5f));
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
label->setPosition(Point(size.width / 2, size.height /2));
this->addChild(label);
}
@ -624,7 +638,7 @@ LabelFNTUnicodeChinese::LabelFNTUnicodeChinese()
{
auto size = Director::getInstance()->getWinSize();
auto label = Label::createWithBMFont("fonts/bitmapFontChinese.fnt", "中国");
label->setAnchorPoint(Point(0.5f, 0.5f));
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
label->setPosition(Point(size.width / 2, size.height /2));
this->addChild(label);
}
@ -673,7 +687,7 @@ LabelFNTMultiLineAlignment::LabelFNTMultiLineAlignment()
// create and initialize a Label
this->_labelShouldRetain = Label::createWithBMFont("fonts/markerFelt.fnt", LongSentencesExample, TextHAlignment::CENTER, size.width/1.5);
this->_labelShouldRetain->setAnchorPoint(Point(0.5f, 0.5f));
this->_labelShouldRetain->setAnchorPoint(Point::ANCHOR_MIDDLE);
this->_labelShouldRetain->retain();
this->_arrowsBarShouldRetain = Sprite::create("Images/arrowsBar.png");
@ -857,22 +871,22 @@ LabelFNTUNICODELanguages::LabelFNTUNICODELanguages()
auto label1 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", spanish, TextHAlignment::CENTER, 200);
addChild(label1);
label1->setAnchorPoint(Point(0.5f, 0.5f));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
label1->setPosition(Point(s.width/2, s.height/5*3));
auto label2 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", chinese);
addChild(label2);
label2->setAnchorPoint(Point(0.5f, 0.5f));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
label2->setPosition(Point(s.width/2, s.height/5*2.5));
auto label3 = Label::createWithBMFont("fonts/arial-26-en-ru.fnt", russian);
addChild(label3);
label3->setAnchorPoint(Point(0.5f, 0.5f));
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
label3->setPosition(Point(s.width/2, s.height/5*2));
auto label4 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", japanese);
addChild(label4);
label4->setAnchorPoint(Point(0.5f, 0.5f));
label4->setAnchorPoint(Point::ANCHOR_MIDDLE);
label4->setPosition(Point(s.width/2, s.height/5*1.5));
}
@ -895,7 +909,7 @@ LabelFNTBounds::LabelFNTBounds()
// LabelBMFont
label1 = Label::createWithBMFont("fonts/boundsTestFont.fnt", "Testing Glyph Designer", TextHAlignment::CENTER, s.width);
label1->setAnchorPoint(Point(0.5f, 0.5f));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
label1->setPosition(Point(s.width/2, s.height/2));
}
@ -972,21 +986,21 @@ LabelTTFColor::LabelTTFColor()
auto label1 = Label::createWithTTF(ttfConfig,"Green", TextHAlignment::CENTER, size.width);
label1->setPosition( Point(size.width/2, size.height/5 * 1.5) );
label1->setColor( Color3B::GREEN );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
// Red
auto label2 = Label::createWithTTF(ttfConfig,"Red", TextHAlignment::CENTER, size.width);
label2->setPosition( Point(size.width/2, size.height/5 * 2.0) );
label2->setColor( Color3B::RED );
label2->setAnchorPoint(Point(0.5, 0.5));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label2);
// Blue
auto label3 = Label::createWithTTF(ttfConfig,"Blue", TextHAlignment::CENTER, size.width);
label3->setPosition( Point(size.width/2, size.height/5 * 2.5) );
label3->setColor( Color3B::BLUE );
label3->setAnchorPoint(Point(0.5, 0.5));
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label3);
}
@ -1006,7 +1020,7 @@ LabelTTFDynamicAlignment::LabelTTFDynamicAlignment()
TTFConfig ttfConfig("fonts/arial.ttf", 45);
_label = Label::createWithTTF(ttfConfig,LongSentencesExample, TextHAlignment::CENTER, size.width);
_label->setPosition( Point(size.width/2, size.height/2) );
_label->setAnchorPoint(Point(0.5, 0.5));
_label->setAnchorPoint(Point::ANCHOR_MIDDLE);
auto menu = Menu::create(
MenuItemFont::create("Left", CC_CALLBACK_1(LabelTTFDynamicAlignment::setAlignmentLeft, this)),
@ -1078,13 +1092,13 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
// Spanish
auto label1 = Label::createWithTTF(ttfConfig,"Buen día, ¿cómo te llamas?", TextHAlignment::CENTER, size.width);
label1->setPosition( Point(size.width/2, vSize - (vStep * 4.5)) );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
// German
auto label2 = Label::createWithTTF(ttfConfig,"In welcher Straße haben Sie gelebt?", TextHAlignment::CENTER,size.width);
label2->setPosition( Point(size.width/2, vSize - (vStep * 5.5)) );
label2->setAnchorPoint(Point(0.5, 0.5));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label2);
// chinese
@ -1093,7 +1107,7 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
ttfConfig.customGlyphs = chinese.c_str();
auto label3 = Label::createWithTTF(ttfConfig,chinese, TextHAlignment::CENTER,size.width);
label3->setPosition( Point(size.width/2, vSize - (vStep * 6.5)) );
label3->setAnchorPoint(Point(0.5, 0.5));
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label3);
}
@ -1130,7 +1144,7 @@ LabelTTFFontsTestNew::LabelTTFFontsTestNew()
label->setPosition( Point(size.width/2, ((size.height * 0.6)/arraysize(ttfpaths) * i) + (size.height/5)));
addChild(label);
label->setAnchorPoint(Point(0.5, 0.5));
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
} else {
log("ERROR: Cannot load: %s", ttfpaths[i]);
}
@ -1153,7 +1167,7 @@ LabelBMFontTestNew::LabelBMFontTestNew()
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Hello World, this is testing the new Label using fnt file", TextHAlignment::CENTER, size.width);
label1->setPosition( Point(size.width/2, size.height/2) );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
}
@ -1173,9 +1187,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
auto label1 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
label1->setPosition( Point(size.width/2, size.height/2) );
label1->setPosition( Point(size.width/2, size.height * 0.6f) );
label1->setColor( Color3B::GREEN );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
auto action = Sequence::create(
@ -1186,9 +1200,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
label1->runAction(RepeatForever::create(action));
auto label2 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
label2->setPosition( Point(size.width/2, size.height/5) );
label2->setPosition( Point(size.width/2, size.height * 0.3f) );
label2->setColor( Color3B::RED );
label2->setAnchorPoint(Point(0.5, 0.5));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label2);
}
@ -1213,23 +1227,23 @@ LabelTTFDistanceFieldEffect::LabelTTFDistanceFieldEffect()
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
auto label1 = Label::createWithTTF(ttfConfig,"Glow", TextHAlignment::CENTER, size.width);
label1->setPosition( Point(size.width/2, size.height*0.5) );
label1->setPosition( Point(size.width/2, size.height*0.65) );
label1->setColor( Color3B::GREEN );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
label1->setLabelEffect(LabelEffect::GLOW,Color3B::YELLOW);
addChild(label1);
auto label2 = Label::createWithTTF(ttfConfig,"Outline", TextHAlignment::CENTER, size.width);
label2->setPosition( Point(size.width/2, size.height*0.375) );
label2->setPosition( Point(size.width/2, size.height*0.5) );
label2->setColor( Color3B::RED );
label2->setAnchorPoint(Point(0.5, 0.5));
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
label2->setLabelEffect(LabelEffect::OUTLINE,Color3B::BLUE);
addChild(label2);
auto label3 = Label::createWithTTF(ttfConfig,"Shadow", TextHAlignment::CENTER, size.width);
label3->setPosition( Point(size.width/2, size.height*0.25f) );
label3->setPosition( Point(size.width/2, size.height*0.35f) );
label3->setColor( Color3B::RED );
label3->setAnchorPoint(Point(0.5, 0.5));
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
label3->setLabelEffect(LabelEffect::SHADOW,Color3B::BLACK);
addChild(label3);
@ -1256,14 +1270,9 @@ LabelCharMapTest::LabelCharMapTest()
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.plist");
addChild(label2, 0, kTagSprite2);
label2->setPosition( Point(10,160) );
label2->setPosition( Point(10,200) );
label2->setOpacity( 32 );
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
label3->setString("123 Test");
addChild(label3, 0, kTagSprite3);
label3->setPosition( Point(10,220) );
schedule(schedule_selector(LabelCharMapTest::step));
}
@ -1291,6 +1300,63 @@ std::string LabelCharMapTest::subtitle() const
return "Updating label should be fast.";
}
//------------------------------------------------------------------
//
// LabelCharMapColorTest
//
//------------------------------------------------------------------
LabelCharMapColorTest::LabelCharMapColorTest()
{
auto label1 = Label::createWithCharMap( "fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
addChild(label1, 0, kTagSprite1);
label1->setPosition( Point(10,100) );
label1->setOpacity( 200 );
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
addChild(label2, 0, kTagSprite2);
label2->setPosition( Point(10,200) );
label2->setColor( Color3B::RED );
auto fade = FadeOut::create(1.0f);
auto fade_in = fade->reverse();
auto cb = CallFunc::create(CC_CALLBACK_0(LabelCharMapColorTest::actionFinishCallback, this));
auto seq = Sequence::create(fade, fade_in, cb, NULL);
auto repeat = RepeatForever::create( seq );
label2->runAction( repeat );
_time = 0;
schedule( schedule_selector(LabelCharMapColorTest::step) ); //:@selector(step:)];
}
void LabelCharMapColorTest::actionFinishCallback()
{
CCLOG("Action finished");
}
void LabelCharMapColorTest::step(float dt)
{
_time += dt;
char string[12] = {0};
sprintf(string, "%2.2f Test", _time);
auto label1 = (Label*)getChildByTag(kTagSprite1);
label1->setString(string);
auto label2 = (Label*)getChildByTag(kTagSprite2);
sprintf(string, "%d", (int)_time);
label2->setString( string );
}
std::string LabelCharMapColorTest::title() const
{
return "New Label + CharMap";
}
std::string LabelCharMapColorTest::subtitle() const
{
return "Opacity + Color should work at the same time";
}
LabelCrashTest::LabelCrashTest()
{
auto size = Director::getInstance()->getWinSize();
@ -1299,7 +1365,7 @@ LabelCrashTest::LabelCrashTest()
auto label1 = Label::createWithTTF(ttfConfig,"Test崩溃123", TextHAlignment::CENTER, size.width);
label1->setPosition( Point(size.width/2, size.height/2) );
label1->setAnchorPoint(Point(0.5, 0.5));
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
addChild(label1);
}
@ -1312,3 +1378,63 @@ std::string LabelCrashTest::subtitle() const
{
return "Not crash and show [Test123] when using unknown character.";
}
LabelTTFOldNew::LabelTTFOldNew()
{
auto s = Director::getInstance()->getWinSize();
float delta = s.height/4;
auto label1 = LabelTTF::create("Cocos2d-x Label Test", "arial", 24);
addChild(label1, 0, kTagBitmapAtlas1);
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
label1->setPosition(Point(s.width/2, delta * 2));
label1->setColor(Color3B::RED);
TTFConfig ttfConfig("fonts/arial.ttf", 48);
auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test");
addChild(label2, 0, kTagBitmapAtlas2);
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
label2->setPosition(Point(s.width/2, delta * 2));
}
void LabelTTFOldNew::onDraw()
{
kmMat4 oldMat;
kmGLGetMatrix(KM_GL_MODELVIEW, &oldMat);
kmGLLoadMatrix(&_modelViewTransform);
auto label1 = (Label*)getChildByTag(kTagBitmapAtlas2);
auto labelSize = label1->getContentSize();
auto origin = Director::getInstance()->getWinSize();
origin.width = origin.width / 2 - (labelSize.width / 2);
origin.height = origin.height / 2 - (labelSize.height / 2);
Point vertices[4]=
{
Point(origin.width, origin.height),
Point(labelSize.width + origin.width, origin.height),
Point(labelSize.width + origin.width, labelSize.height + origin.height),
Point(origin.width, labelSize.height + origin.height)
};
DrawPrimitives::drawPoly(vertices, 4, true);
kmGLLoadMatrix(&oldMat);
}
void LabelTTFOldNew::draw()
{
_renderCmd.init(_globalZOrder);
_renderCmd.func = CC_CALLBACK_0(LabelTTFOldNew::onDraw, this);
Director::getInstance()->getRenderer()->addCommand(&_renderCmd);
}
std::string LabelTTFOldNew::title() const
{
return "New / Old TTF";
}
std::string LabelTTFOldNew::subtitle() const
{
return "Comparison between old(red) and new(white) TTF label";
}

View File

@ -363,6 +363,23 @@ private:
float _time;
};
class LabelCharMapColorTest : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelCharMapColorTest);
LabelCharMapColorTest();
virtual std::string title() const override;
virtual std::string subtitle() const override;
void step(float dt);
void actionFinishCallback();
private:
float _time;
};
class LabelCrashTest : public AtlasDemoNew
{
public:
@ -374,6 +391,22 @@ public:
virtual std::string subtitle() const override;
};
class LabelTTFOldNew : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelTTFOldNew);
LabelTTFOldNew();
virtual void draw() override;
virtual std::string title() const override;
virtual std::string subtitle() const override;
protected:
CustomCommand _renderCmd;
void onDraw();
};
// we don't support linebreak mode
#endif

View File

@ -63,7 +63,9 @@ static std::function<Layer*()> createFunctions[] =
CL(NodeToWorld3D),
CL(SchedulerTest1),
CL(CameraOrbitTest),
CL(CameraZoomTest),
//Camera has been removed from CCNode
//todo add new feature to support it
//CL(CameraZoomTest),
CL(ConvertToNode),
CL(NodeOpaqueTest),
CL(NodeNonOpaqueTest),

View File

@ -292,6 +292,7 @@ void NodeDeallocTest::update(float dt)
for( int i=0; i<quantityOfNodes; ++i) {
nodes[i] = Node::create();
nodes[i]->retain();
}
CC_PROFILER_START(this->profilerName());

View File

@ -85,6 +85,8 @@ void TextureTest::performTestsPNG(const char* filename)
struct timeval now;
Texture2D *texture;
auto cache = Director::getInstance()->getTextureCache();
Texture2D::PixelFormat defaultFormat = Texture2D::getDefaultAlphaPixelFormat();
log("RGBA 8888");
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA8888);
@ -125,6 +127,8 @@ void TextureTest::performTestsPNG(const char* filename)
else
log(" ERROR");
cache->removeTexture(texture);
Texture2D::setDefaultAlphaPixelFormat(defaultFormat);
}
void TextureTest::performTests()

View File

@ -160,7 +160,7 @@ void SchedulerPauseResume::onEnter()
schedule(schedule_selector(SchedulerPauseResume::tick1), 0.5f);
schedule(schedule_selector(SchedulerPauseResume::tick2), 0.5f);
schedule(schedule_selector(SchedulerPauseResume::pause), 0.5f);
schedule(schedule_selector(SchedulerPauseResume::pause), 3.0f);
}
void SchedulerPauseResume::tick1(float dt)

View File

@ -0,0 +1,2 @@
#Do now ignore Marmalade icf files
!*.icf

View File

@ -0,0 +1 @@
aec1c0a8c8068377fddca5ddd32084d8c3c3c419

View File

@ -103,43 +103,39 @@ local function main()
-- handing touch events
local touchBeginPoint = nil
local function onTouchBegan(x, y)
cclog("onTouchBegan: %0.2f, %0.2f", x, y)
touchBeginPoint = {x = x, y = y}
local function onTouchBegan(touch, event)
local location = touch:getLocation()
cclog("onTouchBegan: %0.2f, %0.2f", location.x, location.y)
touchBeginPoint = {x = location.x, y = location.y}
spriteDog.isPaused = true
-- CCTOUCHBEGAN event must return true
return true
end
local function onTouchMoved(x, y)
cclog("onTouchMoved: %0.2f, %0.2f", x, y)
local function onTouchMoved(touch, event)
local location = touch:getLocation()
cclog("onTouchMoved: %0.2f, %0.2f", location.x, location.y)
if touchBeginPoint then
local cx, cy = layerFarm:getPosition()
layerFarm:setPosition(cx + x - touchBeginPoint.x,
cy + y - touchBeginPoint.y)
touchBeginPoint = {x = x, y = y}
layerFarm:setPosition(cx + location.x - touchBeginPoint.x,
cy + location.y - touchBeginPoint.y)
touchBeginPoint = {x = location.x, y = location.y}
end
end
local function onTouchEnded(x, y)
cclog("onTouchEnded: %0.2f, %0.2f", x, y)
local function onTouchEnded(touch, event)
local location = touch:getLocation()
cclog("onTouchEnded: %0.2f, %0.2f", location.x, location.y)
touchBeginPoint = nil
spriteDog.isPaused = false
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x, y)
elseif eventType == "moved" then
return onTouchMoved(x, y)
else
return onTouchEnded(x, y)
end
end
layerFarm:registerScriptTouchHandler(onTouch)
layerFarm:setTouchEnabled(true)
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
local eventDispatcher = layerFarm:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layerFarm)
return layerFarm
end

File diff suppressed because it is too large Load Diff

View File

@ -31,4 +31,5 @@
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -5,54 +5,60 @@ local function AccelerometerMainLayer()
end
local layer = cc.Layer:create()
layer:setAccelerometerEnabled(true)
local function onEnter()
layer:setAccelerometerEnabled(true)
local label = cc.LabelTTF:create(title(), "Arial", 32)
layer:addChild(label, 1)
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
local label = cc.LabelTTF:create(title(), "Arial", 32)
layer:addChild(label, 1)
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
local ball = cc.Sprite:create("Images/ball.png")
ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
layer:addChild(ball)
local ball = cc.Sprite:create("Images/ball.png")
ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
layer:addChild(ball)
ball:retain()
local function didAccelerate(x,y,z,timestamp)
local function accelerometerListener(event,x,y,z,timestamp)
local target = event:getCurrentTarget()
local ballSize = target:getContentSize()
local ptNowX,ptNowY = target:getPosition()
ptNowX = ptNowX + x * 9.81
ptNowY = ptNowY + y * 9.81
if nil == ball then
return
end
local director = cc.Director:getInstance()
local szBall = ball:getContentSize()
local ptNowX,ptNowY = ball:getPosition()
local ptTemp = director:convertToUI(cc.p(ptNowX,ptNowY))
ptTemp.x = ptTemp.x + x * 9.81
ptTemp.y = ptTemp.y - y * 9.81
local ptNext = director:convertToGL(cc.p(ptTemp.x,ptTemp.y))
local minX = math.floor(VisibleRect:left().x + szBall.width / 2.0)
local maxX = math.floor(VisibleRect:right().x - szBall.width / 2.0)
if ptNext.x < minX then
ptNext.x = minX
elseif ptNext.x > maxX then
ptNext.x = maxX
end
local minX = math.floor(VisibleRect:left().x + ballSize.width / 2.0)
local maxX = math.floor(VisibleRect:right().x - ballSize.width / 2.0)
if ptNowX < minX then
ptNowX = minX
elseif ptNowX > maxX then
ptNowX = maxX
end
local minY = math.floor(VisibleRect:bottom().y + szBall.height / 2.0)
local maxY = math.floor(VisibleRect:top().y - szBall.height / 2.0)
if ptNext.y < minY then
ptNext.y = minY
elseif ptNext.y > maxY then
ptNext.y = maxY
end
ball:setPosition(cc.p(ptNext.x , ptNext.y))
local minY = math.floor(VisibleRect:bottom().y + ballSize.height / 2.0)
local maxY = math.floor(VisibleRect:top().y - ballSize.height / 2.0)
if ptNowY < minY then
ptNowY = minY
elseif ptNowY > maxY then
ptNowY = maxY
end
target:setPosition(cc.p(ptNowX , ptNowY))
end
local listerner = cc.EventListenerAcceleration:create(accelerometerListener)
layer:getEventDispatcher():addEventListenerWithSceneGraphPriority(listerner,ball)
end
layer:registerScriptAccelerateHandler(didAccelerate)
local function onExit()
layer:setAccelerometerEnabled(false)
end
local function onNodeEvent(event)
if "enter" == event then
onEnter()
elseif "exit" == event then
onExit()
end
end
layer:registerScriptHandler(onNodeEvent)
return layer
end

View File

@ -1,8 +1,8 @@
local MAX_COUNT = 9;
local LINE_SPACE = 40;
local kItemTagBasic = 5432;
local MAX_COUNT = 9
local LINE_SPACE = 40
local kItemTagBasic = 5432
local Winsize = cc.Director:getInstance():getWinSize();
local Winsize = cc.Director:getInstance():getWinSize()
local testNames = {
"Bug-350",
@ -18,8 +18,8 @@ local testNames = {
local function CreateBugsTestBackMenuItem(pLayer)
cc.MenuItemFont:setFontName("Arial")
cc.MenuItemFont:setFontSize(24);
local pMenuItemFont = cc.MenuItemFont:create("Back");
cc.MenuItemFont:setFontSize(24)
local pMenuItemFont = cc.MenuItemFont:create("Back")
pMenuItemFont:setPosition(cc.p(VisibleRect:rightBottom().x - 50, VisibleRect:rightBottom().y + 25))
local function menuCallback()
local pScene = BugsTestMain()
@ -37,9 +37,9 @@ end
--BugTest350
local function BugTest350()
local pLayer = cc.Layer:create()
local pBackground = cc.Sprite:create("Hello.png");
pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2));
pLayer:addChild(pBackground);
local pBackground = cc.Sprite:create("Hello.png")
pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
pLayer:addChild(pBackground)
return pLayer
end
@ -55,7 +55,7 @@ local function BugTest422()
print(strLog)
end
pResetLayer:removeChild(pNode, false);
pResetLayer:removeChild(pNode, false)
local function menuCallback(tag,pMenuItem)
if nil ~= pMenuItem then
@ -64,7 +64,7 @@ local function BugTest422()
end
end
cc.MenuItemFont:setFontName("Arial")
cc.MenuItemFont:setFontSize(24);
cc.MenuItemFont:setFontSize(24)
local pMenuItem1 = cc.MenuItemFont:create("One")
pMenuItem1:registerScriptTapHandler(menuCallback)
local pMenuItem2 = cc.MenuItemFont:create("Two")
@ -90,15 +90,15 @@ local function BugTest458()
local function InitQuestionContainerSprite(pSprite)
--Add label
local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12);
pLabel:setTag(100);
local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12)
pLabel:setTag(100)
--Add the background
local pCorner = cc.Sprite:create("Images/bugs/corner.png");
local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2);
local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2);
local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight);
pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2));
local pCorner = cc.Sprite:create("Images/bugs/corner.png")
local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2)
local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2)
local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight)
pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2))
--First button is blue,Second is red,Used for testing - change later
if (0 == nColorFlag) then
pLabel:setColor(cc.c3b(0,0,255))
@ -106,53 +106,53 @@ local function BugTest458()
print("Color changed")
pLabel:setColor(cc.c3b(255,0,0))
end
nColorFlag = nColorFlag + 1;
pSprite:addChild(pColorLayer);
nColorFlag = nColorFlag + 1
pSprite:addChild(pColorLayer)
pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2)));
pSprite:addChild(pCorner);
pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2)))
pSprite:addChild(pCorner)
local nX,nY = pCorner:getPosition()
local pCorner2 = cc.Sprite:create("Images/bugs/corner.png");
pCorner2:setPosition(cc.p(-nX, nY));
pCorner2:setFlipX(true);
pSprite:addChild(pCorner2);
local pCorner2 = cc.Sprite:create("Images/bugs/corner.png")
pCorner2:setPosition(cc.p(-nX, nY))
pCorner2:setFlipX(true)
pSprite:addChild(pCorner2)
local pCorner3 = cc.Sprite:create("Images/bugs/corner.png");
pCorner3:setPosition(cc.p(nX, -nY));
pCorner3:setFlipY(true);
pSprite:addChild(pCorner3);
local pCorner3 = cc.Sprite:create("Images/bugs/corner.png")
pCorner3:setPosition(cc.p(nX, -nY))
pCorner3:setFlipY(true)
pSprite:addChild(pCorner3)
local pCorner4 = cc.Sprite:create("Images/bugs/corner.png");
pCorner4:setPosition(cc.p(-nX, -nY));
pCorner4:setFlipX(true);
pCorner4:setFlipY(true);
pSprite:addChild(pCorner4);
local pCorner4 = cc.Sprite:create("Images/bugs/corner.png")
pCorner4:setPosition(cc.p(-nX, -nY))
pCorner4:setFlipX(true)
pCorner4:setFlipY(true)
pSprite:addChild(pCorner4)
local pEdge = cc.Sprite:create("Images/bugs/edge.png");
pEdge:setScaleX(nWidth);
pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY));
pSprite:addChild(pEdge);
local pEdge = cc.Sprite:create("Images/bugs/edge.png")
pEdge:setScaleX(nWidth)
pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY))
pSprite:addChild(pEdge)
local pEdge2 = cc.Sprite:create("Images/bugs/edge.png");
pEdge2:setScaleX(nWidth);
pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY));
pEdge2:setFlipY(true);
pSprite:addChild(pEdge2);
local pEdge2 = cc.Sprite:create("Images/bugs/edge.png")
pEdge2:setScaleX(nWidth)
pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY))
pEdge2:setFlipY(true)
pSprite:addChild(pEdge2)
local pEdge3 = cc.Sprite:create("Images/bugs/edge.png");
pEdge3:setRotation(90);
pEdge3:setScaleX(nHeight);
pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)));
pSprite:addChild(pEdge3);
local pEdge3 = cc.Sprite:create("Images/bugs/edge.png")
pEdge3:setRotation(90)
pEdge3:setScaleX(nHeight)
pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)))
pSprite:addChild(pEdge3)
local pEdge4 = cc.Sprite:create("Images/bugs/edge.png");
pEdge4:setRotation(270);
pEdge4:setScaleX(nHeight);
pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)));
pSprite:addChild(pEdge4);
local pEdge4 = cc.Sprite:create("Images/bugs/edge.png")
pEdge4:setRotation(270)
pEdge4:setScaleX(nHeight)
pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)))
pSprite:addChild(pEdge4)
pSprite:addChild(pLabel);
pSprite:addChild(pLabel)
end
local pQuestion1 = cc.Sprite:create()
@ -165,19 +165,19 @@ local function BugTest458()
end
local pMenuItemSprite = cc.MenuItemSprite:create(pQuestion1,pQuestion2)
pMenuItemSprite:registerScriptTapHandler(menuCallback)
local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100);
-- question->release();
-- question2->release();
local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100)
-- question->release()
-- question2->release()
local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100);
local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2);
local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100)
local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2)
pMenuItemSprite2:registerScriptTapHandler(menuCallback)
local pMenu = cc.Menu:create(pMenuItemSprite, pMenuItemSprite2)
pMenu:alignItemsVerticallyWithPadding(100);
pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
pMenu:alignItemsVerticallyWithPadding(100)
pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
-- add the label as a child to this Layer
pLayer:addChild(pMenu);
pLayer:addChild(pMenu)
return pLayer
end
@ -189,21 +189,21 @@ local BugTest624_2_entry = nil
local function BugTest624()
local pLayer = cc.Layer:create()
local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36);
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
pLayer:addChild(pLabel);
pLayer:setAccelerometerEnabled(true);
-- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f);
local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36)
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
pLayer:addChild(pLabel)
pLayer:setAccelerometerEnabled(true)
-- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f)
local function BugTest624_SwitchLayer()
local scheduler = cc.Director:getInstance():getScheduler()
scheduler:unscheduleScriptEntry(BugTest624_entry)
local pScene = cc.Scene:create();
local pScene = cc.Scene:create()
local pNewPlayer = BugTest624_2()
CreateBugsTestBackMenuItem(pNewPlayer)
pScene:addChild(pNewPlayer);
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255)));
pScene:addChild(pNewPlayer)
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255)))
end
@ -228,20 +228,20 @@ end
function BugTest624_2()
local pLayer = cc.Layer:create()
local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36);
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
pLayer:addChild(pLabel);
pLayer:setAccelerometerEnabled(true);
local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36)
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
pLayer:addChild(pLabel)
pLayer:setAccelerometerEnabled(true)
local function BugTest624_2_SwitchLayer()
local scheduler = cc.Director:getInstance():getScheduler()
scheduler:unscheduleScriptEntry(BugTest624_2_entry)
local pScene = cc.Scene:create();
local pScene = cc.Scene:create()
local pNewPlayer = BugTest624()
CreateBugsTestBackMenuItem(pNewPlayer)
pScene:addChild(pNewPlayer);
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0)));
pScene:addChild(pNewPlayer)
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0)))
end
local function BugTest624_2_OnEnterOrExit(tag)
@ -294,65 +294,58 @@ end
--BugTest914
local function BugTest914()
local pLayer = cc.Layer:create()
local layer = cc.Layer:create()
pLayer:setTouchEnabled(true);
local pLayerColor = nil
local layerColor = nil
for i = 0, 4 do
pLayerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255))
pLayerColor:setContentSize(cc.size(i*100, i*100));
pLayerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
pLayerColor:setAnchorPoint(cc.p(0.5, 0.5));
pLayerColor:ignoreAnchorPointForPosition(false);
pLayer:addChild(pLayerColor, -1-i);
layerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255))
layerColor:setContentSize(cc.size(i*100, i*100))
layerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
layerColor:setAnchorPoint(cc.p(0.5, 0.5))
layerColor:ignoreAnchorPointForPosition(false)
layer:addChild(layerColor, -1-i)
end
--create and initialize a Label
local function restart()
local pScene = cc.Scene:create()
local pLayer = BugTest914()
CreateBugsTestBackMenuItem(pLayer)
pScene:addChild(pLayer);
cc.Director:getInstance():replaceScene(pScene)
local scene = cc.Scene:create()
local newLayer = BugTest914()
CreateBugsTestBackMenuItem(newLayer)
scene:addChild(newLayer)
cc.Director:getInstance():replaceScene(scene)
end
local label = cc.LabelTTF:create("Hello World", "Marker Felt", 64)
--position the label on the center of the screen
label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 ));
pLayer:addChild(label);
label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 ))
layer:addChild(label)
local item1 = cc.MenuItemFont:create("restart")
item1:registerScriptTapHandler(restart)
--Bug914Layer::restart));
local menu = cc.Menu:create()
menu:addChild(item1)
menu:alignItemsVertically()
menu:setPosition(cc.p(Winsize.width/2, 100))
pLayer:addChild(menu)
layer:addChild(menu)
-- handling touch events
local function onTouchMoved(tableArray)
local nCount = table.getn(tableArray)
nCount = math.floor(nCount / 3)
print(nCount)
local function onTouchMoved(touches, event)
local count = table.getn(touches)
print("Number of touches: ",count)
end
local function onTouchBegan(tableArray)
onTouchMoved(tableArray)
local function onTouchBegan(touches, event)
onTouchMoved(touches, event)
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local function onTouch(eventType,tableArray)
if eventType == "began" then
return onTouchBegan(tableArray)
elseif eventType == "moved" then
return onTouchMoved(tableArray)
end
end
pLayer:registerScriptTouchHandler(onTouch,true)
return pLayer
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end
--BugTest1159
@ -372,25 +365,25 @@ local function BugTest1159()
local seq = cc.Sequence:create(cc.MoveTo:create(1.0, cc.p(1024.0, 384.0)), cc.MoveTo:create(1.0, cc.p(0.0, 384.0)))
sprite_a:runAction(cc.RepeatForever:create(seq))
local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400);
local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400)
sprite_b:setAnchorPoint(cc.p(0.5, 0.5))
sprite_b:ignoreAnchorPointForPosition(false);
sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2));
pLayer:addChild(sprite_b);
sprite_b:ignoreAnchorPointForPosition(false)
sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
pLayer:addChild(sprite_b)
local function menuCallback()
local pScene = cc.Scene:create()
local pLayer = BugTest1159()
CreateBugsTestBackMenuItem(pLayer)
pScene:addChild(pLayer);
pScene:addChild(pLayer)
cc.Director:getInstance():replaceScene(cc.TransitionPageTurn:create(1.0, pScene, false))
end
local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24));
local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24))
label:registerScriptTapHandler(menuCallback)
local menu = cc.Menu:create();
local menu = cc.Menu:create()
menu:addChild(label)
menu:setPosition(cc.p(Winsize.width - 200.0, 50.0));
pLayer:addChild(menu);
menu:setPosition(cc.p(Winsize.width - 200.0, 50.0))
pLayer:addChild(menu)
local function onNodeEvent(event)
if event == "exit" then
@ -436,7 +429,7 @@ local function BugTest1174()
local bRet = false
print("Test1 - Start")
local i = 0;
local i = 0
for i = 0, 9999 do
--[[
A|b
@ -490,12 +483,12 @@ local function BugTest1174()
--------
print("Test2 - Start")
p1 = cc.p(220,480);
p2 = cc.p(304,325);
p3 = cc.p(264,416);
p4 = cc.p(186,416);
s = 0.0;
t = 0.0;
p1 = cc.p(220,480)
p2 = cc.p(304,325)
p3 = cc.p(264,416)
p4 = cc.p(186,416)
s = 0.0
t = 0.0
bRet,s,t = cc.pIsLineIntersect( p1, p2, p3, p4, s, t)
if true == bRet then
check_for_error(p1, p2, p3, p4, s, t)
@ -515,7 +508,7 @@ local function BugTest1174()
-- c | d
local ax = math.random() * -500
local ay = math.random() * 500
p1 = cc.p(ax,ay);
p1 = cc.p(ax,ay)
-- a | b
-- -----
-- c | D
@ -579,7 +572,7 @@ end
local function BugsTestMainLayer()
local ret = cc.Layer:create();
local ret = cc.Layer:create()
--menu callback
local function menuCallback(tag, pMenuItem)
@ -591,8 +584,8 @@ local function BugsTestMainLayer()
end
-- add menu items for tests
local pItemMenu = cc.Menu:create();
local nTestCount = table.getn(testNames);
local pItemMenu = cc.Menu:create()
local nTestCount = table.getn(testNames)
local i = 1
for i = 1, nTestCount do
@ -605,19 +598,15 @@ local function BugsTestMainLayer()
pItemMenu:setPosition(cc.p(0, 0))
ret:addChild(pItemMenu)
ret:setTouchEnabled(true)
-- handling touch events
local ptBeginPos = {x = 0, y = 0}
local ptCurPos = {x = 0, y = 0}
local function onTouchBegan(x, y)
ptBeginPos = {x = x, y = y}
-- cc.TOUCHBEGAN event must return true
return true
end
local function onTouchMoved(x, y)
local nMoveY = y - ptBeginPos.y
-- handling touch events
local function onTouchMoved(touches, event)
local touchLocation = touches[1]:getLocation()
local nMoveY = touchLocation.y - ptBeginPos.y
local curPosx, curPosy = pItemMenu:getPosition()
local nextPosy = curPosy + nMoveY
if nextPosy < 0 then
@ -631,26 +620,25 @@ local function BugsTestMainLayer()
end
pItemMenu:setPosition(curPosx, nextPosy)
ptBeginPos = {x = x, y = y}
ptBeginPos = touchLocation
ptCurPos = {x = curPosx, y = nextPosy}
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x, y)
elseif eventType == "moved" then
return onTouchMoved(x, y)
end
local function onTouchBegan(touches, event)
ptBeginPos = touches[1]:getLocation()
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED )
ret:registerScriptTouchHandler(onTouch)
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
return ret
end
function BugsTestMain()
cclog("BugsTestMain");
local scene = cc.Scene:create();
scene:addChild(BugsTestMainLayer());
scene:addChild(CreateBackMenuItem());
return scene;
cclog("BugsTestMain")
local scene = cc.Scene:create()
scene:addChild(BugsTestMainLayer())
scene:addChild(CreateBackMenuItem())
return scene
end

View File

@ -17,13 +17,20 @@ local function initWithLayer()
cc.FadeIn:create(1),
cc.FadeOut:create(1))))
local function onTouchEnded(x, y)
local function onTouchBegan(touch, event)
return true
end
local function onTouchEnded(touch, event)
local location = touch:getLocation()
local s = layer:getChildByTag(kTagSprite)
s:stopAllActions()
s:runAction(cc.MoveTo:create(1, cc.p(x, y)))
s:runAction(cc.MoveTo:create(1, cc.p(location.x, location.y)))
local posX, posY = s:getPosition()
local o = x - posX
local a = y - posY
local o = location.x - posX
local a = location.y - posY
local at = math.atan(o / a) / math.pi * 180.0
if a < 0 then
@ -36,16 +43,11 @@ local function initWithLayer()
s:runAction(cc.RotateTo:create(1, at))
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return true
elseif eventType == "ended" then
return onTouchEnded(x, y)
end
end
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(onTouch)
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end

View File

@ -812,7 +812,6 @@ function TestParticleDisplay.extend(target)
end
function TestParticleDisplay:onEnter()
self:setTouchEnabled(true)
self.animationID = 0
self.armature = ccs.Armature:create("robot")
@ -840,19 +839,17 @@ function TestParticleDisplay:onEnter()
bone:setScale(1.2)
self.armature:addBone(bone, "bady-a30")
local function onTouchBegan(x, y)
-- handling touch events
local function onTouchEnded(touches, event)
self.animationID = (self.animationID + 1) % self.armature:getAnimation():getMovementCount()
self.armature:getAnimation():playWithIndex(self.animationID)
return false
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x,y)
end
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
self:registerScriptTouchHandler(onTouch)
local eventDispatcher = self:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
end
function TestParticleDisplay.create()
@ -889,7 +886,6 @@ function TestUseMutiplePicture.extend(target)
end
function TestUseMutiplePicture:onEnter()
self:setTouchEnabled(true)
self.displayIndex = 1
self.armature = ccs.Armature:create("Knight_f/Knight")
@ -915,19 +911,17 @@ function TestUseMutiplePicture:onEnter()
self.armature:getBone("weapon"):addDisplay(skin, i - 1)
end
local function onTouchBegan(x, y)
-- handling touch events
local function onTouchEnded(touches, event)
self.displayIndex = (self.displayIndex + 1) % (table.getn(weapon) - 1)
self.armature:getBone("weapon"):changeDisplayWithIndex(self.displayIndex, true)
return false
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x,y)
end
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
self:registerScriptTouchHandler(onTouch)
local eventDispatcher = self:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
end
function TestUseMutiplePicture.create()
@ -1012,7 +1006,6 @@ function TestArmatureNesting.extend(target)
end
function TestArmatureNesting:onEnter()
self:setTouchEnabled(true)
self.weaponIndex = 0
self.armature = ccs.Armature:create("cyborg")
@ -1022,20 +1015,18 @@ function TestArmatureNesting:onEnter()
self.armature:getAnimation():setSpeedScale(0.4)
self:addChild(self.armature)
local function onTouchBegan(x, y)
-- handling touch events
local function onTouchEnded(touches, event)
self.weaponIndex = (self.weaponIndex + 1) % 4
self.armature:getBone("armInside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex)
self.armature:getBone("armOutside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex)
return false
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x,y)
end
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
self:registerScriptTouchHandler(onTouch)
local eventDispatcher = self:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
end
function TestArmatureNesting.create()
@ -1131,30 +1122,26 @@ function TestArmatureNesting2.extend(target)
end
function TestArmatureNesting2:onEnter()
self:setTouchEnabled(true)
local function onTouchesEnded(tableArray)
local x,y = tableArray[1],tableArray[2]
-- handling touch events
local function onTouchEnded(touches, event)
local location = touches[1]:getLocation()
local armature = self._hero._mount and self._hero._mount or self._hero
if x < armature:getPositionX() then
if location.x < armature:getPositionX() then
armature:setScaleX(-1)
else
armature:setScaleX(1)
end
local move = cc.MoveTo:create(2, cc.p(x,y))
local move = cc.MoveTo:create(2, location)
armature:stopAllActions()
armature:runAction(cc.Sequence:create(move))
end
local function onTouch(eventType, tableArray)
if eventType == "ended" then
return onTouchesEnded(tableArray)
end
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
self:registerScriptTouchHandler(onTouch,true)
local eventDispatcher = self:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
local function changeMountCallback(sender)
self._hero:stopAllActions()

View File

@ -108,7 +108,6 @@ local function CocosDenshionTest()
m_pItmeMenu:setContentSize(cc.size(VisibleRect:getVisibleRect().width, (m_nTestCount + 1) * LINE_SPACE))
m_pItmeMenu:setPosition(cc.p(0, 0))
ret:addChild(m_pItmeMenu)
ret:setTouchEnabled(true)
-- preload background music and effect
AudioEngine.preloadMusic( MUSIC_FILE )
@ -159,7 +158,46 @@ local function CocosDenshionTest()
end
end
ret:registerScriptTouchHandler(onTouchEvent)
local function onTouchBegan(touch, event)
local location = touch:getLocation()
prev.x = location.x
prev.y = location.y
m_tBeginPos = location
return true
end
local function onTouchMoved(touch, event)
local location = touch:getLocation()
local touchLocation = location
local nMoveY = touchLocation.y - m_tBeginPos.y
local curPosX, curPosY = m_pItmeMenu:getPosition()
local curPos = cc.p(curPosX, curPosY)
local nextPos = cc.p(curPos.x, curPos.y + nMoveY)
if nextPos.y < 0.0 then
m_pItmeMenu:setPosition(cc.p(0, 0))
end
if nextPos.y > ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height) then
m_pItmeMenu:setPosition(cc.p(0, ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height)))
end
m_pItmeMenu:setPosition(nextPos)
m_tBeginPos.x = touchLocation.x
m_tBeginPos.y = touchLocation.y
prev.x = location.x
prev.y = location.y
end
local listener = cc.EventListenerTouchOneByOne:create()
listener:setSwallowTouches(true)
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
return ret
end

View File

@ -1239,14 +1239,15 @@ local function ExtensionsMainLayer()
layer:addChild(menu)
-- handling touch events
local beginPos = {x = 0, y = 0}
local function onTouchBegan(x, y)
beginPos = {x = x, y = y}
return true
local beginPos = {x = 0, y = 0}
local function onTouchesBegan(touches, event)
beginPos = touches[1]:getLocation()
end
local function onTouchMoved(x, y)
local nMoveY = y - beginPos.y
local function onTouchesMoved(touches, event)
local location = touches[1]:getLocation()
local nMoveY = location.y - beginPos.y
local curPosx, curPosy = menu:getPosition()
local nextPosy = curPosy + nMoveY
local winSize = cc.Director:getInstance():getWinSize()
@ -1261,20 +1262,15 @@ local function ExtensionsMainLayer()
end
menu:setPosition(curPosx, nextPosy)
beginPos = {x = x, y = y}
beginPos = {x = location.x, y = location.y}
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x, y)
elseif eventType == "moved" then
return onTouchMoved(x, y)
end
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCH_MOVED )
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(onTouch)
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end

View File

@ -1,31 +1,42 @@
local function KeypadMainLayer()
local pLayer = cc.Layer:create()
local s = cc.Director:getInstance():getWinSize()
local label = cc.LabelTTF:create("Keypad Test", "Arial", 28)
pLayer:addChild(label, 0)
label:setPosition( cc.p(s.width/2, s.height-50) )
local layer = cc.Layer:create()
pLayer:setKeypadEnabled(true)
local function onEnter()
print("come in")
local s = cc.Director:getInstance():getWinSize()
local label = cc.LabelTTF:create("Keypad Test", "Arial", 28)
layer:addChild(label, 0)
label:setPosition(cc.p(s.width/2, s.height-50))
-- create a label to display the tip string
local pLabelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22)
pLabelTip:setPosition(cc.p(s.width / 2, s.height / 2))
pLayer:addChild(pLabelTip, 0)
pLabelTip:retain()
local function KeypadHandler(strEvent)
if "backClicked" == strEvent then
pLabelTip:setString("BACK clicked!");
elseif "menuClicked" == strEvent then
pLabelTip:setString("MENU clicked!");
end
local labelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22)
labelTip:setPosition(cc.p(s.width / 2, s.height / 2))
layer:addChild(labelTip, 0)
local function onKeyReleased(keyCode, event)
local label = event:getCurrentTarget()
if keyCode == cc.KeyCode.KEY_BACKSPACE then
label:setString("BACK clicked!")
elseif keyCode == cc.KeyCode.KEY_MENU then
label:setString("MENU clicked!")
end
end
local listener = cc.EventListenerKeyboard:create()
listener:registerScriptHandler(onKeyReleased, cc.Handler.EVENT_KEYBOARD_RELEASED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, labelTip)
end
pLayer:registerScriptKeypadHandler(KeypadHandler)
return pLayer
local function onNodeEvent(event)
if event == "enter" then
onEnter()
end
end
layer:registerScriptHandler(onNodeEvent)
return layer
end

View File

@ -992,8 +992,6 @@ function BitmapFontMultiLineAlignment.create()
local layer = cc.Layer:create()
Helper.initWithLayer(layer)
layer:setTouchEnabled(true)
-- ask director the the window size
local size = cc.Director:getInstance():getWinSize()
@ -1068,7 +1066,44 @@ function BitmapFontMultiLineAlignment.create()
layer:addChild(stringMenu)
layer:addChild(alignmentMenu)
layer:registerScriptHandler(BitmapFontMultiLineAlignment.onNodeEvent)
layer:registerScriptTouchHandler(BitmapFontMultiLineAlignment.onTouchEvent)
local function onTouchesBegan(touches, event)
local location = touches[1]:getLocationInView()
if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), location) then
BitmapFontMultiLineAlignment._drag = true
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
end
end
local function onTouchesMoved(touches, event)
if BitmapFontMultiLine._drag == false then
return
end
local location = touches[1]:getLocationInView()
local winSize = cc.Director:getInstance():getWinSize()
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY())
local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
end
local function onTouchesEnded(touch, event)
BitmapFontMultiLineAlignment._drag = false
BitmapFontMultiLineAlignment.snapArrowsToEdge()
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end
@ -1118,35 +1153,6 @@ function BitmapFontMultiLineAlignment.alignmentChanged(tag, sender)
BitmapFontMultiLineAlignment.snapArrowsToEdge()
end
function BitmapFontMultiLineAlignment.onTouchEvent(eventType, x, y)
-- cclog("type:"..eventType.."["..x..","..y.."]")
if eventType == "began" then
if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then
BitmapFontMultiLineAlignment._drag = true
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
return true
end
elseif eventType == "ended" then
BitmapFontMultiLineAlignment._drag = false
BitmapFontMultiLineAlignment.snapArrowsToEdge()
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
elseif eventType == "moved" then
if BitmapFontMultiLine._drag == false then
return
end
local winSize = cc.Director:getInstance():getWinSize()
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY())
local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
end
end
function BitmapFontMultiLineAlignment.snapArrowsToEdge()
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX() + BitmapFontMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionY()

View File

@ -596,9 +596,6 @@ local LabelFNTMultiLineAlignment = {
function LabelFNTMultiLineAlignment.create()
local layer = cc.Layer:create()
Helper.initWithLayer(layer)
layer:setTouchEnabled(true)
-- ask director the the window size
local size = cc.Director:getInstance():getWinSize()
@ -674,7 +671,46 @@ function LabelFNTMultiLineAlignment.create()
layer:addChild(stringMenu)
layer:addChild(alignmentMenu)
layer:registerScriptHandler(LabelFNTMultiLineAlignment.onNodeEvent)
layer:registerScriptTouchHandler(LabelFNTMultiLineAlignment.onTouchEvent)
local function onTouchesBegan(touches, event)
local location = touches[1]:getLocationInView()
if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(location.x, location.y)) then
LabelFNTMultiLineAlignment._drag = true
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
end
end
local function onTouchesMoved(touches, event)
if LabelFNTMultiLineAlignment._drag == false then
return
end
local winSize = cc.Director:getInstance():getWinSize()
local location = touches[1]:getLocationInView()
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY())
local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
end
local function onTouchesEnded(touch, event)
LabelFNTMultiLineAlignment._drag = false
LabelFNTMultiLineAlignment.snapArrowsToEdge()
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end
@ -724,35 +760,6 @@ function LabelFNTMultiLineAlignment.alignmentChanged(tag, sender)
LabelFNTMultiLineAlignment.snapArrowsToEdge()
end
function LabelFNTMultiLineAlignment.onTouchEvent(eventType, x, y)
-- cclog("type:"..eventType.."["..x..","..y.."]")
if eventType == "began" then
if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then
LabelFNTMultiLineAlignment._drag = true
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
return true
end
elseif eventType == "ended" then
LabelFNTMultiLineAlignment._drag = false
LabelFNTMultiLineAlignment.snapArrowsToEdge()
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
elseif eventType == "moved" then
if LabelFNTMultiLineAlignment._drag == false then
return
end
local winSize = cc.Director:getInstance():getWinSize()
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY())
local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
end
end
function LabelFNTMultiLineAlignment.snapArrowsToEdge()
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX() + LabelFNTMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionY()

View File

@ -302,8 +302,6 @@ end
local function LayerTest1()
local ret = createLayerDemoLayer("ColorLayer resize (tap & move)")
ret:setTouchEnabled(true)
local s = cc.Director:getInstance():getWinSize()
local layer = cc.LayerColor:create( cc.c4b(0xFF, 0x00, 0x00, 0x80), 200, 200)
@ -321,15 +319,23 @@ local function LayerTest1()
l:setContentSize( newSize )
end
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
updateSize(x, y)
return true
else
updateSize(x, y)
end
local function onTouchesMoved(touches, event)
local touchLocation = touches[1]:getLocation()
updateSize(touchLocation.x, touchLocation.y)
end
ret:registerScriptTouchHandler(onTouchEvent)
local function onTouchesBegan(touches, event)
onTouchesMoved(touches, event)
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
return ret
end
@ -430,8 +436,6 @@ local function LayerGradient()
local layer1 = cc.LayerGradient:create(cc.c4b(255,0,0,255), cc.c4b(0,255,0,255), cc.p(0.9, 0.9))
ret:addChild(layer1, 0, kTagLayer)
ret:setTouchEnabled(true)
local label1 = cc.LabelTTF:create("Compressed Interpolation: Enabled", "Marker Felt", 26)
local label2 = cc.LabelTTF:create("Compressed Interpolation: Disabled", "Marker Felt", 26)
local item1 = cc.MenuItemLabel:create(label1)
@ -452,22 +456,23 @@ local function LayerGradient()
local s = cc.Director:getInstance():getWinSize()
menu:setPosition(cc.p(s.width / 2, 100))
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
return true
elseif eventType == "moved" then
local s = cc.Director:getInstance():getWinSize()
local start = cc.p(x, y)
local movingPos = cc.p(s.width/2,s.height/2)
local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y)
diff = cc.pNormalize(diff)
local function onTouchesMoved(touches, event)
local s = cc.Director:getInstance():getWinSize()
local start = touches[1]:getLocation()
local movingPos = cc.p(s.width/2,s.height/2)
local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y)
diff = cc.pNormalize(diff)
local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient")
gradient:setVector(diff)
end
local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient")
gradient:setVector(diff)
end
ret:registerScriptTouchHandler(onTouchEvent)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
return ret
end

View File

@ -22,8 +22,6 @@ local function MenuLayerMainMenu()
local m_disabledItem = nil
local ret = cc.Layer:create()
ret:setTouchEnabled(true)
ret:setTouchMode(cc.TOUCHES_ONE_BY_ONE )
-- Font Item
local spriteNormal = cc.Sprite:create(s_MenuItem, cc.rect(0,23*2,115,23))
@ -542,32 +540,32 @@ local function RemoveMenuItemWhenMove()
menu:setPosition(cc.p(s.width/2, s.height/2))
ret:setTouchEnabled(true)
--[[
local function onTouchBegan(touch, event)
return true
end
local function onTouchMoved(touch, event)
if item ~= nil then
item:removeFromParent(true)
--item:release()
--item = nil
end
end
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithFixedPriority(listener, -129)
local function onNodeEvent(event)
if event == "enter" then
cc.Director:getInstance():getTouchDispatcher():addTargetedDelegate(ret, -129, false)
elseif event == "exit" then
-- item:release()
if event == "exit" then
ret:getEventDispatcher():removeEventListener(listener)
end
end
ret:registerScriptHandler(onNodeEvent)
]]--
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
return true
elseif eventType == "moved" then
if item ~= nil then
item:removeFromParent(true)
--item:release()
--item = nil
end
end
end
ret:registerScriptTouchHandler(onTouchEvent,false,-129,false)
return ret
end

View File

@ -106,28 +106,17 @@ local function MotionStreakTest2()
streak:setPosition(cc.p(s.width / 2, s.height / 2))
local function onTouchMoved(x, y)
if firstTick == true then
firstTick = false
return
end
streak:setPosition(cc.p(x, y))
local function onTouchesMoved(touches, event)
streak:setPosition( touches[1]:getLocation() )
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return true
elseif eventType == "moved" then
return onTouchMoved(x, y)
end
end
firstTick = true
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(onTouch)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
Helper.titleLabel:setString("MotionStreak test")
return layer
end

View File

@ -569,27 +569,25 @@ local function ConvertToNode()
ConvertToNode_layer:addChild(sprite, i)
end
local function onTouchEnded(x, y)
for i = 0, 2 do
local node = ConvertToNode_layer:getChildByTag(100 + i)
local p1, p2
p1 = node:convertToNodeSpaceAR(cc.p(x, y))
p2 = node:convertToNodeSpace(cc.p(x, y))
local function onTouchesEnded(touches, event)
local count = table.getn(touches)
for i = 1, count do
local location = touches[i]:getLocation()
for j = 1,3 do
local node = ConvertToNode_layer:getChildByTag(100 + i - 1)
local p1, p2
p1 = node:convertToNodeSpaceAR(location)
p2 = node:convertToNodeSpace(location)
cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y)
cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y)
end
end
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return true
elseif eventType == "ended" then
return onTouchEnded(x, y)
end
end
ConvertToNode_layer:setTouchEnabled(true)
ConvertToNode_layer:registerScriptTouchHandler(onTouch)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = ConvertToNode_layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ConvertToNode_layer)
Helper.titleLabel:setString("Convert To Node Space")
Helper.subtitleLabel:setString("testing convertToNodeSpace / AR. Touch and see console")

View File

@ -83,7 +83,6 @@ end
local function Parallax2()
local ret = createParallaxLayer("Parallax: drag screen")
ret:setTouchEnabled( true )
-- Top Layer, a simple image
local cocosImage = cc.Sprite:create(s_Power)
@ -126,25 +125,19 @@ local function Parallax2()
-- top image is moved at a ratio of 3.0x, 2.5y
voidNode:addChild( cocosImage, 2, cc.p(3.0,2.5), cc.p(200,1000) )
ret:addChild(voidNode, 0, kTagNode)
local prev = {x = 0, y = 0}
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
prev.x = x
prev.y = y
return true
elseif eventType == "moved" then
local node = ret:getChildByTag(kTagNode)
local newX = node:getPositionX()
local newY = node:getPositionY()
local diffX = x - prev.x
local diffY = y - prev.y
node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) )
prev.x = x
prev.y = y
end
local function onTouchesMoved(touches, event)
local diff = touches[1]:getDelta()
local node = ret:getChildByTag(kTagNode)
local currentPosX, currentPosY = node:getPosition()
node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y))
end
ret:registerScriptTouchHandler(onTouchEvent)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
return ret
end

View File

@ -147,28 +147,34 @@ local function getBaseLayer()
local seq = cc.Sequence:create(move, move_back)
background:runAction(cc.RepeatForever:create(seq))
local function onTouchEnded(x, y)
local pos = cc.p(0, 0)
if background ~= nil then
pos = background:convertToWorldSpace(cc.p(0, 0))
end
local function onTouchesEnded(touches, event)
local location = touches[1]:getLocation()
local pos = cc.p(0, 0)
if background ~= nil then
pos = background:convertToWorldSpace(cc.p(0, 0))
end
if emitter ~= nil then
local newPos = cc.pSub(cc.p(x, y), pos)
emitter:setPosition(newPos.x, newPos.y)
end
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return true
else
return onTouchEnded(x, y)
if emitter ~= nil then
local newPos = cc.pSub(location, pos)
emitter:setPosition(newPos.x, newPos.y)
end
end
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(onTouch)
local function onTouchesBegan(touches, event)
onTouchesEnded(touches, event);
end
local function onTouchesMoved(touches, event)
onTouchesEnded(touches, event);
end
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
layer:registerScriptHandler(baseLayer_onEnterOrExit)
return layer

View File

@ -1353,6 +1353,9 @@ local function runTextureTest()
local time
local pTexture = nil
local pCache = cc.Director:getInstance():getTextureCache()
local pDefaultFormat = cc.Texture2D:getDefaultAlphaPixelFormat();
print("RGBA 8888")
cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
pTexture = pCache:addImage(strFileName)
@ -1397,6 +1400,8 @@ local function runTextureTest()
print(" ERROR")
end
pCache:removeTexture(pTexture)
cc.Texture2D:setDefaultAlphaPixelFormat(pDefaultFormat)
end
local function PerformTests()
print("--------")
@ -1548,48 +1553,37 @@ local function runTouchesTest()
end
-- handling touch events
local function onTouchBegan(tableArray)
if 0 == nCurCase then
nNumberOfTouchesB = nNumberOfTouchesB + 1
elseif 1 == nCurCase then
nNumberOfTouchesB = nNumberOfTouchesB + table.getn(tableArray)
end
end
local function onTouchMoved(tableArray)
if 0 == nCurCase then
nNumberOfTouchesM = nNumberOfTouchesM + 1
elseif 1 == nCurCase then
nNumberOfTouchesM = nNumberOfTouchesM + table.getn(tableArray)
end
end
local function onTouchEnded(tableArray)
if 0 == nCurCase then
nNumberOfTouchesE = nNumberOfTouchesE + 1
elseif 1 == nCurCase then
nNumberOfTouchesE = nNumberOfTouchesE + table.getn(tableArray)
end
end
local function onTouchCancelled(tableArray)
if 0 == nCurCase then
nNumberOfTouchesC = nNumberOfTouchesC + 1
elseif 1 == nCurCase then
nNumberOfTouchesC = nNumberOfTouchesC + table.getn(tableArray)
end
local function onTouchEnded(touch, event)
nNumberOfTouchesE = nNumberOfTouchesE + 1
end
local function onTouch(eventType,tableArray)
if eventType == "began" then
return onTouchBegan(tableArray)
elseif eventType == "moved" then
return onTouchMoved(tableArray)
elseif eventType == "ended" then
return onTouchEnded(tableArray)
elseif eventType == "cancelled" then
return onTouchCancelled(tableArray)
end
local function onTouchBegan(touch, event)
nNumberOfTouchesB = nNumberOfTouchesB + 1
end
local function onTouchMoved(touch, event)
nNumberOfTouchesM = nNumberOfTouchesM + 1
end
local function onTouchCancelled(touch, event)
nNumberOfTouchesC = nNumberOfTouchesC + 1
end
local function onTouchesEnded(touches, event)
nNumberOfTouchesE = nNumberOfTouchesE + table.getn(touches)
end
local function onTouchesBegan(touches, event)
nNumberOfTouchesB = nNumberOfTouchesB + table.getn(touches)
end
local function onTouchesMoved(touches, event)
nNumberOfTouchesM = nNumberOfTouchesM + table.getn(touches)
end
local function onTouchesCancelled(touches, event)
nNumberOfTouchesC= nNumberOfTouchesC + table.getn(touches)
end
local function InitLayer()
@ -1617,9 +1611,24 @@ local function runTouchesTest()
nNumberOfTouchesM = 0
nNumberOfTouchesE = 0
nNumberOfTouchesC = 0
pLayer:setTouchEnabled(true)
pLayer:registerScriptTouchHandler(onTouch,true)
if 0 == nCurCase then
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
listener:registerScriptHandler(onTouchCancelled,cc.Handler.EVENT_TOUCH_CANCELLED )
local eventDispatcher = pLayer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer)
elseif 1 == nCurCase then
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
listener:registerScriptHandler(onTouchesCancelled,cc.Handler.EVENT_TOUCHES_CANCELLED )
local eventDispatcher = pLayer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer)
end
end
function ShowCurrentTest()

View File

@ -8,22 +8,21 @@ local function RenderTextureSave()
local ret = createTestLayer("Touch the screen",
"Press 'Save Image' to create an snapshot of the render texture")
local s = cc.Director:getInstance():getWinSize()
local m_pTarget = nil
local m_pBrush = nil
local m_pTarget = nil
local target = nil
local counter = 0
local brushes = {}
local function clearImage(tag, pSender)
m_pTarget:clear(math.random(), math.random(), math.random(), math.random())
target:clear(math.random(), math.random(), math.random(), math.random())
end
local function saveImage(tag, pSender)
local png = string.format("image-%d.png", counter)
local jpg = string.format("image-%d.jpg", counter)
m_pTarget:saveToFile(png, cc.IMAGE_FORMAT_PNG)
m_pTarget:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG)
target:saveToFile(png, cc.IMAGE_FORMAT_PNG)
target:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG)
local pImage = m_pTarget:newImage()
local pImage = target:newImage()
local tex = cc.Director:getInstance():getTextureCache():addUIImage(pImage, png)
@ -42,8 +41,7 @@ local function RenderTextureSave()
local function onNodeEvent(event)
if event == "exit" then
m_pBrush:release()
m_pTarget:release()
target:release()
cc.Director:getInstance():getTextureCache():removeUnusedTextures()
end
end
@ -51,69 +49,58 @@ local function RenderTextureSave()
ret:registerScriptHandler(onNodeEvent)
-- create a render texture, this is what we are going to draw into
m_pTarget = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
m_pTarget:retain()
m_pTarget:setPosition(cc.p(s.width / 2, s.height / 2))
target = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
target:retain()
target:setPosition(cc.p(s.width / 2, s.height / 2))
-- note that the render texture is a cc.Node, and contains a sprite of its texture for convience,
-- so we can just parent it to the scene like any other cc.Node
ret:addChild(m_pTarget, -1)
ret:addChild(target, -1)
-- create a brush image to draw into the texture with
m_pBrush = cc.Sprite:create("Images/fire.png")
m_pBrush:retain()
m_pBrush:setColor(cc.c3b(255, 0, 0))
m_pBrush:setOpacity(20)
local function onTouchesMoved(touches, event)
local start = touches[1]:getLocation()
local ended = touches[1]:getPreviousLocation()
target:begin()
local prev = {x = 0, y = 0}
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
prev.x = x
prev.y = y
return true
elseif eventType == "moved" then
local diffX = x - prev.x
local diffY = y - prev.y
local distance = cc.pGetDistance(start, ended)
if distance > 1 then
brushes = {}
local d = distance
local i = 0
local startP = cc.p(x, y)
local endP = cc.p(prev.x, prev.y)
-- begin drawing to the render texture
m_pTarget:begin()
-- for extra points, we'll draw this smoothly from the last position and vary the sprite's
-- scale/rotation/offset
local distance = cc.pGetDistance(startP, endP)
if distance > 1 then
local d = distance
local i = 0
for i = 0, d-1 do
local difx = endP.x - startP.x
local dify = endP.y - startP.y
local delta = i / distance
m_pBrush:setPosition(cc.p(startP.x + (difx * delta), startP.y + (dify * delta)))
m_pBrush:setRotation(math.random(0, 359))
local r = math.random(0, 49) / 50.0 + 0.25
m_pBrush:setScale(r)
-- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why.
m_pBrush:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255))
-- Call visit to draw the brush, don't call draw..
m_pBrush:visit()
end
for i = 0,d -1 do
-- create a brush image to draw into the texture with
local sprite = cc.Sprite:create("Images/fire.png")
sprite:setColor(cc.c3b(255, 0, 0))
sprite:setOpacity(20)
brushes[i + 1] = sprite
end
-- finish drawing and return context back to the screen
m_pTarget:endToLua()
for i = 0,d -1 do
local difx = ended.x - start.x
local dify = ended.y - start.y
local delta = i / distance
brushes[i + 1]:setPosition(cc.p(start.x + (difx * delta), start.y + (dify * delta)))
brushes[i + 1]:setRotation(math.random(0, 359))
local r = math.random(0, 49) / 50.0 + 0.25
brushes[i + 1]:setScale(r)
-- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why.
brushes[i + 1]:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255))
-- Call visit to draw the brush, don't call draw..
brushes[i + 1]:visit()
end
end
prev.x = x
prev.y = y
-- finish drawing and return context back to the screen
target:endToLua()
end
ret:setTouchEnabled(true)
ret:registerScriptTouchHandler(onTouchEvent)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = ret:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
-- Save Image menu
cc.MenuItemFont:setFontSize(16)
local item1 = cc.MenuItemFont:create("Save Image")

View File

@ -55,12 +55,10 @@ function Sprite1.addNewSpriteWithCoords(layer, point)
sprite:runAction( cc.RepeatForever:create(seq) )
end
function Sprite1.onTouch(event, x, y)
if event == "began" then
return true
elseif event == "ended" then
Sprite1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y))
return true
function Sprite1.onTouchesEnd(touches, event)
for i = 1,table.getn(touches) do
local location = touches[i]:getLocation()
Sprite1.addNewSpriteWithCoords(Helper.currentLayer, location)
end
end
@ -69,8 +67,11 @@ function Sprite1.create()
local layer = cc.Layer:create()
Helper.initWithLayer(layer)
Sprite1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2))
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(Sprite1.onTouch)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
Helper.titleLabel:setString("Sprite (tap screen)")
@ -115,12 +116,10 @@ function SpriteBatchNode1.addNewSpriteWithCoords(layer, point)
sprite:runAction( cc.RepeatForever:create(seq) )
end
function SpriteBatchNode1.onTouch(event, x, y)
if event == "began" then
return true
elseif event == "ended" then
SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y))
return true
function SpriteBatchNode1.onTouchesEnd(touches,event)
for i = 1,table.getn(touches) do
local location = touches[i]:getLocation()
SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, location)
end
end
@ -132,8 +131,10 @@ function SpriteBatchNode1.create()
SpriteBatchNode1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2))
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(SpriteBatchNode1.onTouch)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
Helper.titleLabel:setString("SpriteBatchNode (tap screen)")

View File

@ -12,26 +12,18 @@ local function createTileDemoLayer(title, subtitle)
Helper.titleLabel:setString(titleStr)
Helper.subtitleLabel:setString(subTitleStr)
local prev = {x = 0, y = 0}
local function onTouchEvent(eventType, x, y)
if eventType == "began" then
prev.x = x
prev.y = y
return true
elseif eventType == "moved" then
local node = layer:getChildByTag(kTagTileMap)
local newX = node:getPositionX()
local newY = node:getPositionY()
local diffX = x - prev.x
local diffY = y - prev.y
node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) )
prev.x = x
prev.y = y
end
local function onTouchesMoved(touches, event )
local diff = touches[1]:getDelta()
local node = layer:getChildByTag(kTagTileMap)
local currentPosX, currentPosY= node:getPosition()
node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y))
end
layer:setTouchEnabled(true)
layer:registerScriptTouchHandler(onTouchEvent)
local listener = cc.EventListenerTouchAllAtOnce:create()
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
local eventDispatcher = layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
return layer
end
--------------------------------------------------------------------

View File

@ -170,14 +170,15 @@ function CreateTestMenu()
menuLayer:addChild(MainMenu)
-- handling touch events
local function onTouchBegan(x, y)
BeginPos = {x = x, y = y}
local function onTouchBegan(touch, event)
BeginPos = touch:getLocation()
-- CCTOUCHBEGAN event must return true
return true
end
local function onTouchMoved(x, y)
local nMoveY = y - BeginPos.y
local function onTouchMoved(touch, event)
local location = touch:getLocation()
local nMoveY = location.y - BeginPos.y
local curPosx, curPosy = MainMenu:getPosition()
local nextPosy = curPosy + nMoveY
local winSize = cc.Director:getInstance():getWinSize()
@ -192,20 +193,15 @@ function CreateTestMenu()
end
MainMenu:setPosition(curPosx, nextPosy)
BeginPos = {x = x, y = y}
BeginPos = {x = location.x, y = location.y}
CurPos = {x = curPosx, y = nextPosy}
end
local function onTouch(eventType, x, y)
if eventType == "began" then
return onTouchBegan(x, y)
elseif eventType == "moved" then
return onTouchMoved(x, y)
end
end
menuLayer:setTouchEnabled(true)
menuLayer:registerScriptTouchHandler(onTouch)
local listener = cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
local eventDispatcher = menuLayer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, menuLayer)
return menuLayer
end

View File

@ -53,26 +53,6 @@ bool AppDelegate::applicationDidFinishLaunching()
return true;
}
void handle_signal(int signal) {
static int internal_state = 0;
ScriptingCore* sc = ScriptingCore::getInstance();
// should start everything back
Director* director = Director::getInstance();
if (director->getRunningScene()) {
director->popToRootScene();
} else {
PoolManager::sharedPoolManager()->finalize();
if (internal_state == 0) {
//sc->dumpRoot(NULL, 0, NULL);
sc->start();
internal_state = 1;
} else {
sc->runScript("hello.js");
internal_state = 0;
}
}
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground()
{

View File

@ -9,7 +9,7 @@
#ifndef _APP_DELEGATE_H_
#define _APP_DELEGATE_H_
#include "CCApplication.h"
#include "cocos2d.h"
/**
@brief The cocos2d Application.

View File

@ -10,6 +10,7 @@ import requests
import sys
import traceback
import platform
import subprocess
#set Jenkins build description using submitDescription to mock browser behavior
#TODO: need to set parent build description
@ -58,7 +59,7 @@ def main():
jenkins_url = os.environ['JENKINS_URL']
job_name = os.environ['JOB_NAME'].split('/')[0]
build_number = os.environ['BUILD_NUMBER']
target_url = jenkins_url + 'job/' + job_name + '/' + build_number
target_url = jenkins_url + 'job/' + job_name + '/' + build_number + '/'
set_description(pr_desc, target_url)
@ -113,7 +114,7 @@ def main():
elif(platform.system() == 'Windows'):
os.chdir("tools/jenkins-scripts")
os.system("gen_jsb_win32.bat")
os.chdir("../..)
os.chdir("../..")
#make temp dir
print "current dir is" + os.environ['WORKSPACE']
@ -142,8 +143,12 @@ def main():
#TODO: add ios build
#TODO: add mac build
#TODO: add win32 build
node_name = os.environ['NODE_NAME']
if(branch == 'develop'):
ret = os.system("python build/android-build.py -n -j10 all")
if(node_name == 'android_mac') or (node_name == 'android_win7'):
ret = os.system("python build/android-build.py -n -j10 all")
elif(node_name == 'win32_win7'):
ret = subprocess.call('"%VS110COMNTOOLS%..\IDE\devenv.com" "build\cocos2d-win32.vc2012.sln" /Build "Debug|Win32"', shell=True)
elif(branch == 'master'):
ret = os.system("samples/Cpp/TestCpp/proj.android/build_native.sh")

View File

@ -119,7 +119,7 @@ rename_functions = SpriteFrameCache::[addSpriteFramesWithFile=addSpriteFrames ge
LayerGradient::[initWithColor=init],
LayerColor::[initWithColor=init],
GLProgram::[initWithVertexShaderByteArray=initWithString initWithVertexShaderFilename=init programLog=getProgramLog setUniformLocationWith1i=setUniformLocationI32],
Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder],
Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder setLocalZOrder=setZOrder],
LabelAtlas::[create=_create],
Sprite::[initWithFile=init],
SpriteBatchNode::[initWithFile=init removeAllChildrenWithCleanup=removeAllChildren],