2008년 9월 8일 월요일

hunchentoot 한글(유니코드) 출력하기

전에도 고민했던 문제였는데 다시 만나게 되서 삽질을 또 해봤는데

이번에 한 삽질 보기


헐 시바 그런데 존내 간단한 해결방법이 있었네
http://osdir.com/ml/lisp.html-template.general/2007-05/msg00004.html
예전엔 왜 못봤지?


그래서 위 코드를 적용하고 나니 위의 foo 와 baz 가 이렇게 간단히 변했다.

(setf hunchentoot:*hunchentoot-default-external-format* :UTF-8)

(defun foo ()
"한글")
(defun baz ()
(let ((s (send-headers)))
(fill-and-print-template (create-template-printer "안녕 <!-- TMPL_VAR world -->")
'(:world "세상")
:stream s)))


아 쉬바...



2008년 9월 3일 수요일

rtmp client 몇가지 찾아봤으나 결국 실패.

위키에 적어두긴 뭐하니 그냥 여기 적는다.
디버깅 목적으로 rtmp client 가 필요하다고 해서 잠깐 찾아보고
겪은 일들.

  1. 가장 처음에 접근한것은 물론 gnash 그런데 잘 안되네 rtmpget 이랑 유틸리티가 있다는데 내가 받은 소스에는 Makefile 에서 주석처리가 되어있더라. 별 고민 안해보고 그냥 접었다.
  2. 좀 검색해보니 rtmpy 가 걸렸는데 client 쪽은 TODO 로 남아있더라. 아웃
  3. 결국 빌어먹을 자바로 만들어진 red5 를 가져다 해결. 문서와 내가 받은 소스가 버전이 달라 약간의 삽질이 있었다.

그런데 결국 red5 의 rtmp client 도 도움이 안됐다. 서버쪽에서 잘못주는게 분명했는데 그 에러를 못잡고 그냥 잘 받는것처럼 돌아가더군.

지금은 문제가 해결된 상황이라 하니 더 삽질 안하고 그냥 여기서 접고 메모만 남겨둔다.

common lisp 파일을 바이트 배열 꼴로 조금씩 끝까지 읽어주는 매크로.

lisp 은 역시 뭔가 좀 어렵군?
남이 만든 코드는 아주 이뻐 보이는데 내가 짜려고 하면 시궁창.
특히 매크로 만들거나 loop 를 쓰거나 하는 부분에선 손이 꼬이네?

어쩌다 보니 목적잃은 코드를 만들게 됐는데 그냥 버려두자니 좀 그래서 여기 적어둔다.
displaced array 를 배운건 큰 수확이었다.

;;;
;;; loop-with-file-contents
;;; buf : body 안에서 쓸, 파일의 일부가 담긴 배열
;;; path : 읽을 파일 경로
;;; element-type : 그냥 기본값쓰자. 박아두기 뭐해서 뽑아둔것.
;;; buffer-length : buf 크기. 한번에 얼마씩 읽을지 결정하는 값
;;; body : buf 에 담긴 내용을 알아서 써먹어라.
;;;
;;; 리턴값은 총 읽은 바이트 수
;;;
;;;
;;;
;;; 파일을 바이너리 형태로 읽어오고 싶어서 만들어봤다. 짜다 보니 아주
;;; 복잡해졌는데.. 남들은 이렇게 복잡하게 쓰지는 않을거란 생각이
;;; 드는군.
;;;
;;; 1. 어쩌다 보니 with- 라는 이름으로 했는데 짜놓고 보니 이게 안에서
;;; 루프를 도는 식이라 좀 쌩뚱맞은 이름이 되버렸네. 적절한 이름을
;;; 찾아보자... 였다가 그냥 성의없이 loop 를 앞에 붙여줬다 낄낄. with
;;; 로 시작해야 간지나는데 말이지.
;;;
;;; 2. 매크로의 body 부분에 buf 외에 buflen 까지 넘겨야 하는 상황을
;;; 피하기 위해서 buf 길이가 필요에 따라 줄어들길 바랬다. 즉 10 바이트
;;; 파일을 읽을때 버퍼길이가 4 라면 4,4,2 로 세번 바디가 실행이
;;; 되도록... 그런데 이짓을 하려고 보니 read-sequence 가 fill-pointer
;;; 를 받지를 않네. 좀더 고민을 해봐야 하나 하다가 문서에 displaced
;;; array 가 보이길래 그냥 그걸 썼다.
;;;
;;; 3. 매크로내에서 쓰이는 변수들이 매크로 외부의 심볼들과 쫑나지
;;; 않도록 gensyms 를 썼는데 이거 꽤나 성가시군.
;;;
;;;
(defmacro loop-with-file-contents ((buf path &key (element-type ''(unsigned-byte 8)) (buffer-length 8192)) &body body)
(let ((s (gensym))
(total-readed (gensym))
(readed (gensym)))
`(let ((,buf (make-array ,buffer-length :element-type ,element-type)))
(with-open-file (,s ,path :element-type ,element-type)
(loop
with ,total-readed fixnum = 0
for ,readed fixnum = (read-sequence ,buf ,s)
when (zerop ,readed) return ,total-readed
do (progn
(incf ,total-readed ,readed)
(let ((,buf (if (= ,readed ,buffer-length)
,buf
(make-array ,readed :element-type ,element-type :displaced-to ,buf))))
,@body)))))))


;;; 사용은 요렇게 하면 된다. 파일명이 od.lisp 인것은 원래 od 를 짜보려던것이라..
(loop-with-file-contents (buf "/tmp/od.lisp" :buffer-length 128)
(print buf))


추가.

;;; od 비슷하게 마저 짜봤다.
;;; format 의 ~X 에 인자를 줄때 두번째 인자가 캐릭터라고 되어있길래
;;; #\0 등을 주는 삽질을 했는데 그냥 '0 로 쿼트해서 주면 되는거였네...
;;; 너무 loop 에 의존하는 코딩을 하게 되는것 같아 찝찝하군.
(loop-with-file-contents (buf "/tmp/od.lisp" :buffer-length 16)
(loop for c fixnum across buf
do (format t " ~2,'0X" c)
finally (fresh-line)))


format 의 ~{ ~} 가 배열도 받았으면 정말 깔끔했을텐데 리스트만 받아먹더라.




2008년 8월 9일 토요일

몬헌 -_-

이런 병신같은 조작감을 가진 게임은 정말 오랜만이네
플스때는 이런겜도 그냥 참고 했었는데 PC 로 이런걸 할려니 짜증만 나는구나.
꼬라지를 보니 플스걸 생각없이 걍 가져온듯.
키보드를 생각해서 인터페이스를 좀 손봤어야지 새퀴들아

한게임 가입 절차도 병신이고 이건뭐..

병신같은 게임을 안그래도 짜증나는 여름에 하려니
정말...




2008년 8월 7일 목요일

tinyscheme 간단한 용도에 임베딩해서 사용할수 있는 BSD 스타일 라이센스의 scheme 인터프리터 구현체

http://tinyscheme.sourceforge.net

문서가 좀 그런면이 있는데 인터페이스 함수들이 워낙 간단하니 적당히 쓰면 잘 돌더라. 심각한 스크립팅이 필요하면 다른걸 찾아보자. 원래 ecl 을 써볼려고 했는데 이건 덩치가 너무 크고 라이센스도 빡세더라. 간단한 일에 부담없이 쓰기엔 요놈이 아주 좋아보인다.


//
// 아래 소스 빌드할때 써먹은 CMakeLists.txt
// 별거없고 USE_INTERFACE 를 디파인했다는것만 기억해두자
// 그외 여러가지 조정할게 많아 보이는데 아직 모름.
//

// PROJECT(play-with-tinyscheme)
// INCLUDE_DIRECTORIES(/home/yoonkn/tmp/tinyscheme1.39)
// LINK_DIRECTORIES(/home/yoonkn/tmp/tinyscheme1.39)
// LINK_LIBRARIES(tinyscheme)
// ADD_DEFINITIONS(-DUSE_INTERFACE)
//
// ADD_EXECUTABLE(a a.cpp)



extern "C" {
#include "scheme-private.h"
#include "scheme.h"
}
#include <unistd.h>
#include <iostream>
using namespace std;

static void die(const char* msg) {puts(msg); exit(-1);}
static pointer c_add(scheme* sc, pointer args);


int main()
{
// 초기화. 전역이 아니라 멀티쓰레드간에 써도 안심?
scheme* sc = scheme_init_new();
if(!sc) die("init failed");

// display 등으로 출력되는 값이 튀어나오는 곳이겠군.
scheme_set_output_port_file(sc, stdout);

// scheme 코드를 실행하려면 load_string 이나 load_file 을 쓰자
// scheme.c 를 보니 init.scm 등을 먼저 읽고 시작하는게 바른
// 사용방법인듯 하다. load_string 류 함수는 코드 실행후 실행여부를
// retcode 에, 평가된 값을 value 에 담아주는 모냥이다.
sc->vptr->load_string(sc, "(define foo \"fuckshit\")");
if(sc->retcode != 0) die("exec failed");

// scheme 내의 값을 읽으려면 요렇게. 심벌만 넣어서 실행하고
// .value 를 읽어오면 되는듯
sc->vptr->load_string(sc, "foo");
const char* foo_value = sc->vptr->string_value(sc->value);
puts(foo_value);

// C 쪽에서 만든 덧셈 함수를 scheme 인터프리터에 추가하자.
sc->vptr->scheme_define(sc,
sc->global_env,
sc->vptr->mk_symbol(sc, "c-add"),
sc->vptr->mk_foreign_func(sc, c_add));

// c_add 함 불러보고 리턴값을 찍어보자
sc->vptr->load_string(sc, "(c-add 111 222)");
if(sc->retcode != 0) die("fucked");
printf("(c-add ..) return : %d\n", sc->vptr->ivalue(sc->value));

// 이번엔 반대로 scheme 쪽에서 함수를 만들어보자
sc->vptr->load_string(sc, "(define (scm-add a b) (+ a b))");
if(sc->retcode != 0) die("fucked");

// 이걸 C 쪽에서 부르자.. 음 물론 scheme 코드 만들어서 load_string
// 써도 되겠지만.. C 레벨에서.. 어라? 인터페이스가 안빠져있네
// scheme_call 이란 함수가 있긴 한데 외부로 노출된 함수는 아니네
// 음.. 뭐 일단 내가 원했던 내용까지는 파악이 됐으니 걍 여기까지



// 정리. 그런데 scheme_init_new 는 안쪽에서 sc 를 malloc 해서
// 주는데 deinit 함수중에는 sc 자체를 free 까지 해주는 함수가
// 안보이네 일단 샘플이니 여기서 그냥 free 를 했지만 정말 써먹을
// 상황이 온다면 dll 간에 malloc/free 가 섞일수도 주의하자.
scheme_deinit(sc);
free(sc);
}



// scheme 에 노출할 함수는 pointer foo(scheme*, pointer) 형태의
// 시그너쳐를 가지고 pointer 를 통해서 인자들이 리스트 형태로
// 들어온다. 복잡한데 쓸거 아니니 이정도만 알면 안심
pointer c_add(scheme* sc, pointer args)
{
// 첫번째 인자가 존재하고 정수가 맞는지 확인
if(args == sc->NIL) return sc->NIL;
pointer a = pair_car(args);
if(!is_integer(a)) return sc->NIL;

// 이거.. 변수 따로 잡기 귀찮아서 그냥 덮어썼는데
// 그래서 arg list 들의 첫번째 car 를 팝 한 효과가 났다.
args = pair_cdr(args);

// 다음 인자가 존재하고 정수가 맞는지 확인 꼴을 보니 좀 머리 쓰면
// 이쁘게 짤수 있을거 같은데 오늘은 샘플이니 그냥..
if(args == sc->NIL) return sc->NIL;
pointer b = pair_car(args);
if(!is_integer(b)) return sc->NIL;

// 더한값을 scheme 자료형태로 리턴
return mk_integer(sc, ivalue(a) + ivalue(b));
}

2008년 7월 31일 목요일

haskell 로 웹페이지 한번 긁어봤다. 그리고 Maybe, Either, mapM 을 배웠다.

-- Network.HTTP 로 구글을 읽어오는 걸 짜봤다.
-- 그런데 302 moved 를 안따라가네.. 불친절하군.
-- response 받아서 2xx 나올때까지 재귀돌려야 하나?
-- 아니면 Network.HTTP 는 로우레벨이고 좀더 하이레벨 함수들이 있을까?
--
-- 어쨌건 이번에 배운건 Maybe 라는 놈이랑 Either 라는 놈
--
-- Maybe a 는 Just a 나 Nothing 이 될수있는데 패턴매칭으로 어떤 경우인지
-- 가려내서 에러처리를 해야 겠지만 샘플이니 그냥 fromJust 을 써먹었다.
--
-- Either a b 는 Left a 나 Right b 로 떨어지는놈.
-- 역시 마찬가지로 패턴매칭으로 적당히 처리를 해야 곘지만 불편하니 fromRight 이란걸 만들어봤다.
--
-- 역시 IO (IO 와 모나드의 정확한 관계는 모르겠다. 모나드중의 IO 인것은
-- 맞는데 모든 모나드가 IO 처럼 시퀀셜한 액션을 나타내는것은 아닌것
-- 같기도 하고.. 단순히 사이드이펙트를 가질수있는 모든것들이 모나드인가??
-- 이부분은 좀더 공부하면 알게되겠지)..
--
-- ..IO 위주의 코딩이 되니 편안하네. 문법만 조금 달라졌을뿐 돌아가는
-- 모양새는 C 와 다를게 없으니. 그런데 아무리 생각해도 내가 만들
-- 대부분의 프로그램들은 이런식의 절차적인 특성을 지닐텐데.. 아님 내
-- 생각이 절차적인 한계를 벗어나지 못하는 건가.
--
--
-- 이 모나드라는게 정말 끝까지 따라다닐거 같은데..
-- lisp 이라면 mapcar 류함수와 와 IO 함수를 쉽게 섞을수 있는데
-- (mapc #'print '(1 2 3 4))
--
-- haskell 의 map 은 IO 함수를 받지를 않네.
-- map putStr ["fucking", "hard"]
--
-- 뭐 저런걸 돌리는 다른 함수가 있긴 하겠지.
--
-- 음. 검색을 좀 해보니 mapM 이란게 있네. M 은 모나드의 M 이겠지.
-- 내 원래 이걸 직접 만들어볼려고 했는데 아직 모나드는 커녕 타입조차도 몰라서 실패했다.
-- 내가 만들어보려고 한 함수는
-- (a -> IO b) -> [a] -> IO [b]
-- 뭐 이런식으로 해볼라고 했는데 이게 터무니 없는 것이었나보다.
-- mapM 의 타입은
-- Monad a => (b -> a c) -> [b] -> a [c]
-- 이렇네..
--
-- Monad a=> 라면 a 가 Monad 클래스에 속한다는걸 나타내던가.. 좀더 읽고 짜봐야겠다.

import Network.HTTP
import Network.URI
import Data.Maybe(fromJust)

fromRight :: (Either a b) -> b
fromRight e = case e of
Right r -> r
Left l -> error "not right"

main =
let req = Request (fromJust $ parseURI "http://www.google.com") GET [] ""
in do
rep <- simpleHTTP req
putStrLn $ show $ fromRight rep
return ()

2008년 7월 30일 수요일

헤스켈 셀렉션 소트 구현.. 헐.

haskell 잠깐 구경하는 중인데 이걸로 selection sort 를 짜보려다 좌절을 먹고 소감이나 적어둔다.

for i ← 0 to n-2 do
    min ← i
    for j ← (i + 1) to n-1 do
        if A[j] < A[min]
            min ← j
    swap A[i] and A[min]

처음엔 selection sort 의 정의 그대로 2중 루프 돌면서 작은 값 찾아서 자리바꾸는 식으로 구현을 해보려고 했는데 이렇게 접근하니 아주 제한적인 부분만 알고있는 내 haskell 능력으로는 구현이 불가능하더라.

루프야 대강 재귀돌리면 되는데 문제는 swap.. haskell 의 리스트가 싱글링크드리스트 인것 같은데 이걸 어떻게 효율적으로 스왑을 하나.. 처음엔 당연히 스왑함수가 지원될줄 알았는데 안보이네.. 그리고 이걸 짜보려고 해도 이놈의 리스트가 불변값이라 어쩔수 없이 여러번의 복사? 가 일어날듯 해보였다.

물론 리스트를 조각내서 짜깁기 하는식으로 짜면야 간단하긴 한데... 아무래도 남들은 이런식으로 쓰지 않을거란 생각이 들었다.

그래서 대강 찾아보니 IO array 라던지 ST array 라던지 하는 수정가능한 자료구조가 있다는건 알게됐는데 문제는 이놈들이 모나드... 아직 모나드 공부는 안했지만 모나드와 다른 함수들이 자연스럽게 섞이지 않는 문제점을 겪었기에 ( 아직 공부중이라 잘 몰라서 그럴수도 있지. 하지만 모나드 라는게 사이드 이펙트를 막고자 나온거라면 모나드 함수가 비 모나드 함수안에서 투명하게 불리는것은 불가능하겠지? )..

... 모나드에 겁을 먹고 바로 구글링을 해봤다.

결국 http://www.cs.bris.ac.uk/Teaching/Resources/COMS12100/2003-4/lectures/notes.html 에서 셀렉션 소트 구현을 찾았는데

mport List

selectSort :: Ord a => [a] -> [a]
selectSort [] = []
selectSort ns =
m : selectSort (remove m ns)
where m = minimum ns

insertSort :: Ord a => [a] -> [a]
insertSort [] = []
insertSort (n:ns) =
insert n (insertSort ns)

이렇더라.. 음..
헐... 놀랍다.
함수형 언어와 절차형 언어의 접근이 다르다는걸 머리론 알고 있었지만 그걸 느끼긴 처음이네.
그리고 이미 몇년간 C/C++ 식 코딩을 해온 나한테 저런건 머리를 쥐어짜도 안나올거란걸 느꼈다.

좀더 공부를 해볼까? 그냥 접을까?


PS 그런데 저 잘난 구현도 리스트의 사본을 계속해서 만드는데 기분이 편치 않네.
성능 생각하면 모나드쪽의 어래이를 써야 할것 같은데 정말 헤스켈로 프로젝트 뛰는
애들이 어떤식으로 코딩하는지 궁금하네.


2008년 7월 22일 화요일

엘더스크롤3 모로윈드 945GC 내장브가로 플레이 시도

E2140 노오버
램 2G
GMA950

모드는 베터바디, 베터페이스? 등등 몇개만.
초반만 보면 1024*768 에서 10~30 fps 나오는데 액션이 아니니 할만하군
똥컴으로 단련된 인내심이라 20프레임만 나와도 기분좋다.

내장브가 사면서 게임은 포기했는데 내가 하는겜들은 죄다 고전 RPG 류라 별 불편함이 없네.. 컴업하기 전 PC 가 워낙 구려서 내장이라지만 성능이 더 좋고.

그래도 폴아웃3 나오면 브가하나 사줘야겠지....
돈생기면...

win32 fibers

http://blogs.msdn.com/larryosterman/archive/2005/01/05/347314.aspx

정리 졸라 잘됐다.



gobject 그냥 구경만 해봤다.

gstreamer 를 써야 할일이 있어서 최소한의 것만 읽어봤다.
  • 타입정보를 모두 들고 있는 놈. 객체의 생성,복사,파괴 등이 모두 이 타입시스템을 통해서 하는식.
  • 새 타입을 등록하려면 class structure 와 instance structure 가 필요한데
  • instance structure 는 각 인스턴스마다 고유한 값을 가질 값들.. 즉 그냥 멤버변수라고 보면 되고
  • class structure 는 같은 클래스라면 공유하는 값들..  vtable 이나 클래스 스코프 변수등등이 되겠지.
  • 어떤 타입을 만들어 달라고 타입시스템에 요청을 하면 타입시스템이 그 타입에 해당하는 class structure 인스턴스를 관리 하고 그 타입의 instance structure 의 값을 하나 만들어서 사용자한테 준다.


  • 쓰기가 더러운데 한 타입을 관리하는데 두개의 구조체가 쓰인다는걸 알면 남은것은 더러운 포인터질.
  • gstreamer 에서 제공되는 템플릿 코드를 읽기위해서 최소한의 것만 읽어봤다. 틀린내용이 있을지도 몰겠군.