사실 그당시 오픈소스(무한대전/Mordor)를 가져다가 짜깁기 한 정도에 지나지 않지만 그래도 아직까지 일부 유저들이 플레이를 해주고 있기에 해당 서버를 닫지 못하고 그 명맥을 유지해오고 있는 셈인데....
게임을 플레이하는 유저들이 업데이트를 해달라는 성화가 있음에도 불구하고, 눈에 보이는 업데이트는 많이 이뤄지지 못하고 있는게 현실.....
머드 퀘스트를 위한 "LUA" 스크립트 적용과 더불어 무한대전 소스에서 쉽게 볼 수 있는 아래와 같은 형태의 함수를 가변 인자로 바꾸기 위한 작업을 진행하고 있다.
void function_name(fmt, i1, i2, i3, i4, i5, i6) char *fmt; int i1,i2,i3,i4,i5,i6; {
위와 같은 함수 형태를 아래와 같이 적용하려는 계획.....
void function_name(char *format, ....){ ... }
단순하게 함수를 Wrapping하는 역할만이라면 아래와 같이 간단하게 처리가 가능하겠으나...
int custom_printf(const char *fmt, ...) { va_list argptr; int ret; va_start(argptr, fmt); ret = vprintf(fmt, argptr); va_end(argptr); return ret; }
사용자 정의 Format까지 추가해주어야 하기 때문에 처음에 잠깐.. (아니 많이..) 당황했다.
추가하려는 사용자 정의 포맷은
'M' - creature* 형태의 인자를 넘겨받아 멤버변수 name의 값을 출력해준다.
'A' - 무한대전의 특징인 안시처리 문자를 넘겨받아 처리 한다. ({빨/{노/{파/{하... 등)
'I' - object* 형태의 인자를 넘겨받아 멤버변수 name의 값을 출력한다.
'J' - 한글 조사를 출력한다. ("은"/"는", "이"/"가"....등)
'C' - 지정 숫자에 해당하는 안시 코드를 처리하는 인자
'D' - 지정 숫자에 해당하는 안시 코드를 처리하는 인자
'A' - 무한대전의 특징인 안시처리 문자를 넘겨받아 처리 한다. ({빨/{노/{파/{하... 등)
'I' - object* 형태의 인자를 넘겨받아 멤버변수 name의 값을 출력한다.
'J' - 한글 조사를 출력한다. ("은"/"는", "이"/"가"....등)
'C' - 지정 숫자에 해당하는 안시 코드를 처리하는 인자
'D' - 지정 숫자에 해당하는 안시 코드를 처리하는 인자
넘겨받은 포맷 스트링에서 위에 해당하는 포맷이 있는지 확인하고 해당 포맷을 처리한후 문자열 형태로 다시 넘겨줘 처리해주는 형태로 작업을 하고 있다.
현재 테스트 작업을 진행하고 있고, 조만간 실제 운영서버에도 적용할 수 있을것 같다. 그냥 혼자서 흐뭇 -_-;
■ 가변인자를 이용한 Log 남기기 함수의 예
#include <stdarg> static int Log(LogLevel aLogLevel, const char* aFormat, ...) { va_list argptr; int rv = OK; va_start(argptr, aFormat); FILE* f = fopen("c:/xxx.txt", "a+"); if(!f) { rv = ERROR_FAILURE; } else { if(rv = vfprintf(f, aFormat, argptr) < 0){ rv = ERROR_FAILURE; } fclose(f); } va_end(argptr); return rv; }
그리고 웹 서핑중 누군가 올려놓은 custom printf 소스 (가져온곳 : http://kldp.org/node/2799#comment-7211)
#include // for i/o library #include // for variable argument library #define my_va_start(VA_LIST,LAST_NAMED_ARG) \ ((VA_LIST) = ( (char *)(&(LAST_NAMED_ARG)) + sizeof (LAST_NAMED_ARG) )) #define my_va_arg(VA_LIST, SOME_TYPE) \ ((VA_LIST) = (char *)(VA_LIST) + sizeof(SOME_TYPE), \ *(SOME_TYPE*)((char *)(VA_LIST) - sizeof(SOME_TYPE))) #define my_va_end(VA_LIST) () void my_printf(char *fmt, ...); void my_printf_and_va(char *fmt, ...); // same as my_printf(), // except uses my va_arg stuff int main(int argc, char *argv[]) { const double x = 3.4; const int q = 4; char a[] = "hey guy!"; printf("Here's version with standard va_arg\n"); my_printf("%f %d %s\n", x, q, a); printf("Here's version with my_va_arg\n"); my_printf_and_va("%f %d %s\n", x, q, a); return 0; } void my_printf(char *fmt, ...) { // initialize pass over arguments va_list argl; va_start(argl, fmt); // beginning after last named argument fmt for (char *p = fmt; *p; ++p) // format string controls parsing of args { if (*p == '%') { switch (*++p) { case 'f' : double fval=va_arg(argl,double); // get arg as double cout << fval; break; case 'd' : int ival=va_arg(argl,int); cout << ival; break; case 's' : char *sval = va_arg(argl,char *); cout << sval; break; default : cout << *p; break; } } else cout << *p; } va_end(argl); } void my_printf_and_va(char *fmt, ...) { // initialize pass over arguments my_va_list argl; my_va_start(argl, fmt); // beginning after last named argument fmt // this loop is identical to that in my_printf() except // that it uses non-portable version of va_start(),va_arg(),va_end for (char *p = fmt; *p; ++p) // format string controls parsing of args { if (*p == '%') { switch (*++p) { case 'f' : double fval= my_va_arg(argl,double); // get arg as double cout << fval; break; case 'd' : int ival=my_va_arg(argl,int); cout << ival; break; case 's' : char *sval = my_va_arg(argl,char *); cout << sval; break; default : cout << *p; break; } } else cout << *p; } va_end(argl); }