2013년 1월 24일 목요일

Visual Studio 2012 Update 1 이후 Help Viewer 2.0 실행 안되는 버그 해결하기.

Visual Studio 2012 를 쓰다가 얼마전에 Update 1 을 받아서 처리 하고 난후에 Viewer 2.0 이 실행이 안되었다.

열심히 구글링 해서 답을 찾았는데 모두 영문이라 여기에 해결 방법을 적어 놔요..

일단.

제 컴퓨터가 윈도우 7 이 기준이므로 윈도우 7 기준으로 설명합니다.

아래 폴더로 이동합니다.

C:\ProgramData\Microsoft\HelpLibrary2\Catalogs\VisualStudio11

해당 폴더에 "CatalogType.xml" 파일이 없을겁니다.

해당 파일을 생성 해주시고요 안에 내용은 아래 내용으로 채워서 저장하시고 다시 Help Viewer 2.0을 실행 하시면 됩니다.

"<?xml version="1.0" encoding="utf-8"?><catalogType>UserManaged</catalogType>"

그럼.. ^^

2013년 1월 9일 수요일

Lua C API 정리

1. States
루아 스테이트를 열고 다는 것. 루아 스테이트르 열어야만 루아 API 와 스크립트가 동작한다.

lua_State* lua_open( void );

로 열고,

void lua_close( lua_State* L );

로 닫는다.

꼭 루아 스테이트를 닫진 않아도 된다고 하지만, 프로그램 종료시엔 꼭 닫아주는 것이 좋을듯. 하지만 웹 서버나 대몬이나 기타 등등의 길게 돌아가는 프로그램에서는 필요 없어지면 닫아주는 것이 예의랜다. -_- 스택이 계속 커지기 전에,

2. The Stack and Indices
루아는 가상 스택(virtual stack)이란 놈을 사용해서 C 와 인터페이스 하는데, 스택에는 루아에서 사용하는 값들이 들어가 있다. (nil, number, string, etc.)

스 택에서 인덱스를 조회해서 값을 얻어올 수 있는데, (스택의 맨 밑 바닥이 1이다. 1부터 시작한다) 양수는 스택의 절대 인덱스, 음수는 스택의 top index 에서부터 시작하는 상대 인덱스로 표현한다. 그러므로 인덱스의 범위는

1 <= abs(index) <= top

가 된다.

int lua_gettop( lua_State* L); // 스택의 맨 꼭대기 인덱스 0 이면 스택이 비어있음.

루아 C API 인 스택을 사용하면 스택의 오버플로우를 직접 관리해줘야 한덴다.

int lua_checkstack( lua_State* L, int extra ); // 스택 사이즈를 top+extra 로 늘린다. 늘어난 스택을 줄일 수는 없음.

기본 스택 사이즈는 lua.h 에 LUA_MINSTACK 매크로로 20으로 정의되어 있으나 스택을 건드리지 않는 한 사이즈에 대해서 신경 쓸 필요 없음.

이상, 루아 스택에서 받아들일 수 있는 유요한 스택 인덱스의 범위는 다음과 같다.
(index < 0 && abs(index) <= top || (index > 0 && index <= statckspace)

3. Stack Manipulation
루아에서 스택 건드리는 함수.

void lua_settop(Lua_State* L, int index )
void lua_pushvalue(Lua_State* L, int index )
void lua_remove(Lua_State* L, int index )
void lua_insert(Lua_State* L, int index )
void lua_replace(Lua_State* L, int index )

lua_settop 함수는 들어간 index 까지 스택을 늘리고 nil 로 채우는 효과가 있는데 index가 0 이면 스택의 모든 값들이 제거된다.
n 개의 데이터를 스택에서 pop 하는 요런 매크로가 lua.h 에 정의되어있음.
#define lua_pop(L, n) lua_settop(L, -(n)-1 )

위의 스택 API를 사용한 간단한 예제. (10 20 30 40 50* 으로 시작한다. * 는 스택의 최상위를 의미)
lua_pushvalue( L, 3 ) // 10 20 30 40 50 30*
lua_pushvalue( L, -1) // 10 20 30 40 50 30 30*
lua_remove(L, -3) // 10 20 30 40 30 30*
lua_remove(L, 6) // 10 20 30 40 30*
lua_insert(L, 1) // 30 10 20 30 40*
lua_insert(L, -1) // 30 10 20 30 40* (효과 없음)
lua_replace(L, 2) // 30 40 20 30*
lua_settop(L, -3) // 30, 40*
lua_settop(L, 6) // 30 40 nil nil nil nill*

기본적으로 요놈들은 statck 의 최상위 값을 갖고 노는듯.

4. Querying the Stack
스택의 타입을 조회하는 함수
int lua_type( lua_State* L, int index );
int lua_isnill( lua_State* L, int index );
int lua_isboolean( lua_State* L, int index );
int lua_isnumber( lua_State* L, int index );
int lua_isstring( lua_State* L, int index );
int lua_istable( lua_State* L, int index );
int lua_isfunction( lua_State* L, int index );
int lua_iscfunction( lua_State* L, int index );
int lua_isuserdata( lua_State* L, int index );
int lua_islightuserdata( lua_State* L, int index );

is* 이 함수들은 맞으면 1, 아니면 0 을 리턴하는데 isboolean 은 예외라고 하는데 뭐라고 하는 건지 잘 모르겄다. (lua_isboolean is an exception to this rule: It succeeds only for boolean values (otherwise it would be useless, as any value has a boolean value))

유효한 스택 인덱스가 아닌 경우 LUA_TNONE 을 리턴.

lua_type() 함수는 요놈들을 리턴
LUA_TNILL
LUA_TNUMBER
LUA_TBOOLEAN
LUA_TSTRING
LUA_TTABLE,
LUA_TFUNCTION
LUA_TUSERDATA,
LUA_TTHREAD
LUA_TLIGHTUSERDATA

요놈들이 타입을 정의한 매크로인데
const char* lua_typename( lua_State* L, int type );
함수로 매칭되는 타입 이름 문자열을 얻을 수 있다.

스택의 값을 비교하는 API 도 있다.
int lua_equal (lua_State* L, int index1, int index2 )
int lua_rawequal(lua_State* L, int index1, int index2 )
int lua_lessthan(lua_State* L, int index1, int index2 )

lua_rawequal은 메타메서드 호출없이 primitive equality를 수행한다.(는데 primitive equality 이게 뭔 말일까? 메타메서드 호출 없이 순수하게 비교만 수행한다는 뜻인지..)

5. Getting Values from the Stackint lua_toboolean (lua_State *L, int index);
lua_Number lua_tonumber (lua_State *L, int index);
const char *lua_tostring (lua_State *L, int index);
size_t lua_strlen (lua_State *L, int index);
lua_CFunction lua_tocfunction (lua_State *L, int index);
void *lua_touserdata (lua_State *L, int index);
lua_State *lua_tothread (lua_State *L, int index);
void *lua_topointer (lua_State *L, int index);

to* 함수는 C 의 타입으로 스택의 해당 인덱스 값을 얻어오는 함수이다. 타입이 맞지 않거나 잘못된 인덱스로 호출 했을 경우엔 0 이 리턴된다.

루아에서는 number 가 string 이 될 수도 있고 string 이 number 가 될 수도 있는데, 레퍼런스 문서의 2.2.1 항목을 참조할 것,

그 리고, lua_tostring 으로 number 에서 string 으로 변환될 경우 실제 스택 내부에서도 string 타입으로 바뀌어버리므로 주의! 그리고 얻은 문자열은 언제 garbage collection 될지 모르므로 나중에 쓸거면 registry 에 복사해두도록 한다. (registry 는 레퍼런스 문서 3.18 참고)

lua_tocfunction 함수는 스택의 값을 C 함수로 바꿔서 리턴해주는데 함수 타입이 아닐경우엔 NULL 리턴, lua_CFunction 타입에 관해서는 레퍼런스 문서 3.16에 참조.

lua_tothread 는 스택의 값을 Lua Thread(lua_State*) 로 리턴해준다. 타입이 맞지 않으면 NULL 리턴.

lua_topointer 는 스택의 값을 C 포인터로 리턴해 주는데, (값의 포인터가 아니라 값 자체가 포인터) userdata, table, thread, function 등등이 될 수 있으나 곧바로 원래 값의 포인터로 쓸 수는 없고 대부분 디버깅 목적으로 사용된다고 한다.

lua_touserdata 함수는 레퍼런스 문서 3.8 참조

6. Pushing Values onto the Stackvoid lua_pushboolean (lua_State *L, int b);
void lua_pushnumber (lua_State *L, lua_Number n);
void lua_pushlstring (lua_State *L, const char *s, size_t len);
void lua_pushstring (lua_State *L, const char *s);
void lua_pushnil (lua_State *L);
void lua_pushcfunction (lua_State *L, lua_CFunction f);
void lua_pushlightuserdata (lua_State *L, void *p);

lua_pushstring 과 lua_pushlstring 은 딥 카피로 스트링을 복사해서 스택에 담는다. 또한,

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);

함 수도 있는데 sprintf 나 vsprintf 와 같은 효과로 스택에 문자열을 집어넣는다. 리턴 값은 스택에 들어가는 문자열의 포인터. 이 문자열의 포인터는 루아에서 관리되는 문자열을 가리키고 있기 때문에 함부로 건드리지 않는게 좋다.

void lua_concat (lua_State *L, int n);

함 수는 스택의 탑에서부터 n 개의 값을 concatenate 하고 모두 pop 한 후에, 결과 값을 탑에 놓는다. n 이 1이면 아무 것도 하지 않고 0 이면 빈 문자열이 쌓인다. Concatenation 에 관해선 2.5.4 를 참조

7. Controlling Garbage Collection
가비지 콜렉션에 대해선 2.9 를 참조한다.
int lua_getgccount(lua_State* L);
int lua_getgcthreshold(lua_State* L);
함수로 가비지 콜렉션에 사용되는 두 개의 값을 조회할 수 있으며,
void lua_setgcthreshold( lua_State* L, int newthreshold );
함수로 threshold 값을 직접 건드릴 수 있다. threshold를 0으로 해주면 그 즉시 강제로 가비지 콜렉션을 실행하며 그 다음부턴 루아가 하던대로 알아서 한다.

- 개인적인 견해로는.. 루아의 가비지 콜렉션을 별로 건드릴 일이 없을 듯.

8. Userdata
Userdata 란 루아에서 표현되는 C 데이터 값인데, 루아에서 지원하는 Userdata 는 full userdata(전체 메모리) 와 light userdata(포인터) 가 있다. light userdata 인 경우에는 metatable을 가질 수가 없으며 C 에서 사용하는 주소값일 뿐이다.(숫자)

루아코드에서는 이놈이 full userdata 인지 light userdata 인지 알아낼 수 없으며 C 코드에서는 lua_type 함수로 구분 할 수 있다.

void* lua_newuserdata( lua_State* L, size_t size );
함수로 full userdata를 생성할 수 있으며 lua_pushlightuserdata 함수로 light userdata 를 생성할 수 있다. (3.6 참조)

lua_touserdata 로 userdata 의 포인터를을 얻을 수 있다. (3.5 참조)

루아의 garbage collector 가 full userdata 를 회수 할 때 userdata의 gc 메타 메서드가 호출된다. 그리고 메모리에서 해제.

9. Metatables
다음 함수로 Metatable(2.6 참조) 조작 가능
int lua_getmetatable( lua_State* L, int index);
lnt lua_setmetatable( lua_State* L, int index);
lua_getmetatable 함수는 주어진 오브젝트의 메타테이블을 스택에 올려놓는다. (주어진 오브젝트란 스택의 index에 들어있는 값이 가리키는 것을 얘기하는 듯. 테이블이나 userdata 가 되겠지.) 해당 오브젝트가 메타테이블을 가질 수 없으면 0을 리턴하고 스택엔 아무것도 쌓지 않는다.

setmetatable 함수는 스택에서 테이블에서 테이블을 pop 하고 그 테이블에 인덱스로 주어진 새로운 메타테이블을 set 한다. 메타테이블이 셋팅될 수 없다면 0을 리턴한다. (that is, when the object is neither a userdata nor a table)

10. Loading Lua Chunks
typedef const char* (*lua_Chunkreader)
(lua_State* L, void* data, size_t *size);
int lua_load( lua_State* L, lua_Chunkreader reader, void* data, const char* chunkname);
함수로 루아 chunk를 로드 할 수 있다.
0 이면 정상, LUA_ERRSYNTAX 면 문법 에러, LUA_ERRMEM 이면 메모리 할당 실패 이다.

lua_load 가 성공하면 chunk 를 루아 함수로 간주하여 스택에 푸시.
lua 파일이 텍스트던 바이너리던 상관 없음, 알아서 로드.
뒷 내용은 아직 잘 모르겠으므로 생략.

11. Manipulatiing Tables
void lua_newtable( lua_State* L );
함수로 루아 테이블 생성, 빈 테이블이 생성되고 스택에 푸시된다.

void lua_gettable( lua_State* L, int index );
index 는 테이블을 가리키고 lua_gettable이 호출되면, 스택에 있는(맨 꼭대기) key 가 pop 되고 key 에 해당하는 내용이 스택에 리턴된다. 이 때 테이블은 그대로 남아있음. 이 함수를 사용하면 index 이벤트가 일어나서 metatable에 있는 __index metamethod가 호출되는데 이걸 피하고 싶으면 raw 버전인
void lua_rawget( lua_State* L, int index);
함수를 사용하면 된다.

테이블에 어떤 요소를 저장하고 싶다면
void lua_settable( lua_State* L, int index );
함 수를 사용하는데, index는 스택에서 테이블의 인덱스를 가리키고, key와 들어갈 내용, 즉 2개의 값을 스택에서 pop 하고 테이블에 집어넣게 된다. 이때, settable 이나 newindex 메타 메서드가 호출될 수가 있는데 그게 싫으면 raw 버전인
void lua_rawset( lua_State* L, int index );
함수를 사용하면 된다.

int lua_next( lua_State* L, int index );
함 수를 사용하여 테이블을 조회할 수 있는데, index는 조회할 테이블을 가리키고, 스택에서 key 값이 pop 된다. 그리고 주어진 다음 key에 해당하는 key-value pair(key가 먼저 value가 나중에 푸시된다. 즉, 스택의 top엔 value가 푸시되어있음) 가 푸시된다. 더 이상 조회할 것이 없으면 0을 리턴. 전형적인 조회 코드는 다음과 같다.

// table is in the stack at index 't'
lua_pushnil( L ); // first key
while( lua_next(L, t) != 0
{
// 'key' is at index -2 and 'value' at index -1
printf( "%s - %s\n", lua_typename( L, lua_type(L, -2) ), lua_typename(L, lua_type(L, -1)) );
lua_pop(L, 1); // removes 'value'; keeps 'key' for next iteration
}

주 의할 점은 key 값에 직접 lua_tostring 을 호출하지 말라는 것. key 값이 number 타입이라면 lua_tostring 은 스택 내부의 key 값을 string 타입으로 바꿔버리기 때문에 다음에 lua_next 함수를 호출할 경우 무슨 일이 일어날지 모른다.

출처 : 
http://www.hankiya.com/tc/153

2013년 1월 4일 금요일

Mac 에 Lua Script Bin 설치 하기.

Mac 에 Lua Script 설치 하는 방법입니다.

1. www.lua.org 에서 Lua 최신 소스 tar 파일을 받습니다.
2. 적절한 위치에 파일을 옮겨 놓고 Console 창을 연다음에  아래 명령어로 압축을 풉니다.
    tar -xvzf lua-5.2.1.tar.gz
3. 압축이 풀린 소스 폴더로 이동을 한후 아래 명령어를 실행 하여 소스를 컴파일 한다.
    make macosx
4. 컴파일이 완료 되고 나면 아래 명령어로 설치를 진행한다.
    sudo make install
5. 설치가 완료 되고 나면 테스트 lua 파일을 생성해서 저장하고
    Console 창에서 "lua test.lua" 라고 실행을 하면 스크립트가 실행 되는게 보일겁니다.