http://mldonkey.sourceforge.net/

donkey(당나귀)는 p2p 프로그램의 대명사입니다. 많이 쓰이는 overnet 도 donkey 에서 힌트를 얻어 나왔지요. overnet 과 donkey 의 차이는 donkey 는 중앙 서버가 필요한 반면에 overnet 의 경우에는 중앙 서버가 필요없는 완벽한 p2p 라고 할 수 있겠습니다.

하여튼 donkey 는 이미 소스가 공개 되어서 emule, aMule, xMule, 푸루나 등의 clone 이 만들어졌습니다. 안의 구조는 같지만 사용하기 편하게 조금씩 바꾼 프로그램들이지요.

그 중에서 가장 특징이 있는 donkey 를 꼽는다면 주저없이 mldonkey 를 꼽겠습니다. mldonkey 는 두가지 중요한 특징이 있습니다.

1) explore 로 원격 제어가 가능하다.

다른 donkey 와 다르게 mldonkey 는 인터넷 explore 를 통해 접근이 가능합니다. 아래는 explore 에서 본 mldonkey 의 제어창입니다.



2) 사용자 계정 설정이 가능하다.

 mldonkey 내에서는 사용자 설정을 할 수 있습니다. 저희 집 같은 경우 신발장에 donkey 서버가 있습니다. 물론 mldonkey 도 설치되어 있지요. mldonkey 안에 3명의 계정이 있답니다. 각각의 사람이 접속해서 자료를 다운을 걸어 놓으면 자신의 계정 폴더에 다운로드됩니다.


 donkey 의 가장 큰 문제는 느린 다운 속도였습니다. 이 때문에 donkey 프로그램을 하루종일 켜놓는 경우가 많죠. 하지만 donkey 하나 쓸려고 컴퓨터를 하루종일 켜 놓는 것은 낭비입니다. mldonkey 가 없다면 형이랑 동생이랑 둘다 donkey 를 사용한다면 컴퓨터를 2대 켜놓아야 합니다. 하지만 mldonkey 를 쓰면 mldonkey 가 설치된 컴퓨터 한대가 계속 일을 하게 됩니다. 형/동생 계정으로 다운로드를 제어하면 되지요.

 저희 집 같은 경우 신발장에 자료 저장용 linux 컴퓨터가 있는에 이 녀석이 mldonkey 서버 역할을 하고 있습니다. 우리집 식구는 모두 mldonkey 계정이 있습니다. 일단 자료만 걸어 놓으면 하루종일 받고 있습니다. 똘똘한 놈이지요.


 


저작자 표시 비영리
신고


제가 아는 인터넷 앨범 프로그램에 가장 많이 쓰이는 것은 2가지 있습니다.

1) Gallery (http://gallery.menalto.com)
Gallery - YOUR PHOTOS ON YOUR WEBSITE
2) album.pl (http://perl.bobbitt.ca/album)



입니다. 두개 중에 우열을 가린다면 Gallery 가 압승입니다. album.pl 은 perl 로 만들어져 있는데 아무래도 php 로 만들어진 gallery 보다 느립니다. 서버에 부하도 많이 줍니다.

제가 사용하는 gallery 는 ubuntu linux 에서 자동 업데이트 되는 버젼으로 사용합니다. 아무래도 apt-get(우분투 프로그램 업데이터) 으로 업데이트 하는 것이 편하니까요.

제 홈페이지(http://whria.net) 와 보시면 photography 부분이 있습니다. 이것은 gallery 로 만들어져 있습니다. 매우 짜임새있고 좋습니다. 단점이라면 댓글 다는 부분이 조금 부족합니다.
저작자 표시 비영리
신고


유니 코드 (UTF-8 or UTF-16LE) 를 local (아스키 또는 각자의 codepage) 로 변환시키는 문제는 유니코드 지원 프로그래밍을 위해서는 매우 복잡한 문제이다.

먼저 보통 말하는 local codepage 랑 아스키랑 같은 것이라는 것을 알자. 나는 처음에 이게 차이가 있을 까봐 정말 머리가 아팠다.

결국...

UTF8 <-> UTF16LE
UTF16LE <-> UTF8
UTF8 <-> local
UTF16LE <-> local

이렇게 4 가지 조합만 바꿀 수 있으면 unicode 를 완벽하게 지원하는 프로그램을 짤 수 있다.

c++ 에서 사용할 수 있는 locale 을 바꿔 주는 library 가 몇가지 있는데...

1) iconv
2) boost
3) qt 의 qstring
4) 그리고 피부미인의 codechanger ㅋㅋㅋ

1 번은 가장 많이 쓰는데 static 으로 compile 할라면 머리아프다. 나는 DLL 을 정말 싫어한다.
2 번은 사람들이 잘 모르는데 boost 안에 일부 function 이 unicode 프로그래밍의 중요한 clue 를 제공한다. 여기서 개발된 것이 4 번의 피부미인의 codechanger 이다.
3 번 qt 는 일단 install 할라면 너무 머리아프다. build 하다가 다른 library 랑 부딛치면 돌아버린다.

4 번 피부미인의 codechanger 는 내가 medicalphoto 라는 프로젝트를 하면서 정말정말 어렵게 만든겁니다.  여기에만 특별히 공개하겠습니다. ^^g 이걸 쓰려면 boost library 를 설치해야합니다. 아니면 utf8-codecvt_facet.hpp 에 있는 boost/config.hpp 나 boost/detail/workaround.hpp 등만 copy 해서 사용해도 됩니다.


사용법은 아래와 같다.

MCodeChanger::_CCL("unicode letters") = "local code letters"
MCodeChanger::_CCU("local code letters") = "unicode letters"



1. codechanger.h

////////////////////////////////////////////////////////////////////////////////
// Copyright : Han Seung Seog
// It was so damn hard to make this library
// http://prettygom.com
// http://sshan.net
// 2008. 8. 1
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "../boost.h"
#include <string>
#include <boost/format.hpp>
#include "tchar.h"
#include "utf8_codecvt_facet.hpp"
#include "unicode.h"

#ifdef _UNICODE
    #define _CCL U_W
    #define _CCU W_U
    #define _CCW mbs_to_wcs
    #define _CCN wcs_to_mbs
#else
    #define _CCL U_L
    #define _CCU L_U
    #define _CCW LocaltoLocal
    #define _CCN LocaltoLocal
#endif // _UNICODE

class MCodeChanger
{
public:
    static tstring LocaltoLocal(const tstring& str)
    {
        return str;
    }

    static std::string L_U(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(mbs_to_wcs(str),local);
    }
    static std::string U_L(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(mbs_to_wcs(str,local));
    }
    static std::string W_U(const std::wstring& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return wcs_to_mbs(str,local);
    }
    static std::wstring U_W(const std::string& str)
    {
        std::locale local(std::locale(""),new utf8_codecvt_facet);
        return mbs_to_wcs(str,local);
    }

static std::wstring
mbs_to_wcs(std::string const& str, std::locale const& loc = std::locale(""))
{
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;
    codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);
    std::mbstate_t state = 0;
    std::vector<wchar_t> buf(str.size() + 1);
    char const* in_next = str.c_str();
    wchar_t* out_next = &buf[0];
    codecvt_t::result r = codecvt.in(state,
        str.c_str(), str.c_str() + str.size(), in_next,
        &buf[0], &buf[0] + buf.size(), out_next);
    return std::wstring(&buf[0]);
}
 
static std::string
wcs_to_mbs(std::wstring const& str, std::locale const& loc = std::locale(""))
{
    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_t;
    codecvt_t const& codecvt = std::use_facet<codecvt_t>(loc);
    std::mbstate_t state = 0;
    std::vector<char> buf((str.size() + 1) * codecvt.max_length());
    wchar_t const* in_next = str.c_str();
    char* out_next = &buf[0];
    codecvt_t::result r = codecvt.out(state,
        str.c_str(), str.c_str() + str.size(), in_next,
        &buf[0], &buf[0] + buf.size(), out_next);
    return std::string(&buf[0]);
}
};

2. [ utf8_codesvt_facet.hpp ]

// Copyright ?2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
// Distributed under the Boost Software License, Version 1.0. (See accompany-
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#pragma once

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// utf8_codecvt_facet.hpp

// This header defines class utf8_codecvt_facet, derived fro
// std::codecvt<wchar_t, char>, which can be used to convert utf8 data in
// files into wchar_t strings in the application.
//
// The header is NOT STANDALONE, and is not to be included by the USER.
// There are at least two libraries which want to use this functionality, and
// we want to avoid code duplication. It would be possible to create utf8
// library, but:
// - this requires review process first
// - in the case, when linking the a library which uses utf8
//   (say 'program_options'), user should also link to the utf8 library.
//   This seems inconvenient, and asking a user to link to an unrevieved
//   library is strange.
// Until the above points are fixed, a library which wants to use utf8 must:
// - include this header from one of it's headers or sources
// - include the corresponding .cpp file from one of the sources
// - before including either file, the library must define
//   - BOOST_UTF8_BEGIN_NAMESPACE to the namespace declaration that must be used
//   - BOOST_UTF8_END_NAMESPACE to the code to close the previous namespace
//   - declaration.
//   -  -- to the code which must be used for all 'exportable'
//     symbols.
//
// For example, program_options library might contain:
//    #define BOOST_UTF8_BEGIN_NAMESPACE <backslash character>
//             namespace boost { namespace program_options {
//    #define BOOST_UTF8_END_NAMESPACE }}
//    #define  BOOST_PROGRAM_OPTIONS_DECL
//    #include "../../detail/utf8/utf8_codecvt.cpp"
//
// Essentially, each library will have its own copy of utf8 code, in
// different namespaces.

// Note:(Robert Ramey).  I have made the following alterations in the original
// code.
// a) Rendered utf8_codecvt<wchar_t, char>  with using templates
// b) Move longer functions outside class definition to prevent inlining
// and make code smaller
// c) added on a derived class to permit translation to/from current
// locale to utf8

//  See http://www.boost.org for updates, documentation, and revision history.

// archives stored as text - note these ar templated on the basic
// stream templates to accommodate wide (and other?) kind of characters
//
// note the fact that on libraries without wide characters, ostream is
// is not a specialization of basic_ostream which in fact is not defined
// in such cases.   So we can't use basic_ostream<OStream::char_type> but rather
// use two template parameters
//
// utf8_codecvt_facet
//   This is an implementation of a std::codecvt facet for translating
//   from UTF-8 externally to UCS-4.  Note that this is not tied to
//   any specific types in order to allow customization on platforms
//   where wchar_t is not big enough.
//
// NOTES:  The current implementation jumps through some unpleasant hoops in
// order to deal with signed character types.  As a std::codecvt_base::result,
// it is necessary  for the ExternType to be convertible to unsigned  char.
// I chose not to tie the extern_type explicitly to char. But if any combination
// of types other than <wchar_t,char_t> is used, then std::codecvt must be
// specialized on those types for this to work.

#include <locale>
// for mbstate_t
#include <wchar.h>
// for std::size_t
#include <cstddef>

#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>

namespace std {
    #if defined(__LIBCOMO__)
        using ::mbstate_t;
    #elif defined(BOOST_DINKUMWARE_STDLIB) && !defined(__BORLANDC__)
        using ::mbstate_t;
    #elif defined(__SGI_STL_PORT)
    #elif defined(BOOST_NO_STDC_NAMESPACE)
        using ::mbstate_t;
        using ::codecvt;
    #endif
} // namespace std

#if !defined(__MSL_CPP__) && !defined(__LIBCOMO__)
    #define BOOST_CODECVT_DO_LENGTH_CONST const
#else
    #define BOOST_CODECVT_DO_LENGTH_CONST
#endif

// maximum lenght of a multibyte string
#define MB_LENGTH_MAX 8

struct  utf8_codecvt_facet :
    public std::codecvt<wchar_t, char, std::mbstate_t> 
{
public:
    explicit utf8_codecvt_facet(std::size_t no_locale_manage=0)
        : std::codecvt<wchar_t, char, std::mbstate_t>(no_locale_manage)
    {}
protected:
    virtual std::codecvt_base::result do_in(
        std::mbstate_t& state,
        const char * from,
        const char * from_end,
        const char * & from_next,
        wchar_t * to,
        wchar_t * to_end,
        wchar_t*& to_next
    ) const;

    virtual std::codecvt_base::result do_out(
        std::mbstate_t & state, const wchar_t * from,
        const wchar_t * from_end, const wchar_t*  & from_next,
        char * to, char * to_end, char * & to_next
    ) const;

    bool invalid_continuing_octet(unsigned char octet_1) const {
        return (octet_1 < 0x80|| 0xbf< octet_1);
    }

    bool invalid_leading_octet(unsigned char octet_1)   const {
        return (0x7f < octet_1 && octet_1 < 0xc0) ||
            (octet_1 > 0xfd);
    }

    // continuing octets = octets except for the leading octet
    static unsigned int get_cont_octet_count(unsigned   char lead_octet) {
        return get_octet_count(lead_octet) - 1;
    }

    static unsigned int get_octet_count(unsigned char   lead_octet);

    // How many "continuing octets" will be needed for this word
    // ==   total octets - 1.
    int get_cont_octet_out_count(wchar_t word) const ;

    virtual bool do_always_noconv() const throw() { return false; }

    // UTF-8 isn't really stateful since we rewind on partial conversions
    virtual std::codecvt_base::result do_unshift(
        std::mbstate_t&,
        char * from,
        char * /*to*/,
        char * & next
    ) const
    {
        next = from;
        return ok;
    }

    virtual int do_encoding() const throw() {
        const int variable_byte_external_encoding=0;
        return variable_byte_external_encoding;
    }

    // How many char objects can I process to get <= max_limit
    // wchar_t objects?
    virtual int do_length(
        BOOST_CODECVT_DO_LENGTH_CONST std::mbstate_t &,
        const char * from,
        const char * from_end,
        std::size_t max_limit
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
        ) const throw();
#else
        ) const;
#endif

    // Largest possible value do_length(state,from,from_end,1) could return.
    virtual int do_max_length() const throw () {
        return 6; // largest UTF-8 encoding of a UCS-4 character
    }
};


3. [utf8_codecvt_facet.cpp]

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// utf8_codecvt_facet.cpp

// Copyright ?2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// Please see the comments in <boost/detail/utf8_codecvt_facet.hpp> to
// learn how this file should be used.
#include "stdafx.h"
#include "utf8_codecvt_facet.hpp"

#include <cstdlib> // for multi-byte converson routines
#include <cassert>

#include <boost/limits.hpp>
#include <boost/config.hpp>

// If we don't have wstring, then Unicode support
// is not available anyway, so we don't need to even
// compiler this file. This also fixes the problem
// with mingw, which can compile this file, but will
// generate link error when building DLL.
#ifndef BOOST_NO_STD_WSTRING

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// implementation for wchar_t

// Translate incoming UTF-8 into UCS-4
std::codecvt_base::result utf8_codecvt_facet::do_in(
    std::mbstate_t& /*state*/,
    const char * from,
    const char * from_end,
    const char * & from_next,
    wchar_t * to,
    wchar_t * to_end,
    wchar_t * & to_next
) const {
    // Basic algorithm:  The first octet determines how many
    // octets total make up the UCS-4 character.  The remaining
    // "continuing octets" all begin with "10". To convert, subtract
    // the amount that specifies the number of octets from the first
    // octet.  Subtract 0x80 (1000 0000) from each continuing octet,
    // then mash the whole lot together.  Note that each continuing
    // octet only uses 6 bits as unique values, so only shift by
    // multiples of 6 to combine.
    while (from != from_end && to != to_end) {

        // Error checking   on the first octet
        if (invalid_leading_octet(*from)){
            from_next = from;
            to_next = to;
            return std::codecvt_base::error;
        }

        // The first octet is   adjusted by a value dependent upon
        // the number   of "continuing octets" encoding the character
        const   int cont_octet_count = get_cont_octet_count(*from);
        const   wchar_t octet1_modifier_table[] =   {
            0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
        };

        // The unsigned char conversion is necessary in case char is
        // signed   (I learned this the hard way)
        wchar_t ucs_result =
            (unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];

        // Invariants   :
        //   1) At the start of the loop,   'i' continuing characters have been
        //    processed
        //   2) *from   points to the next continuing character to be processed.
        int i   = 0;
        while(i != cont_octet_count && from != from_end) {

            // Error checking on continuing characters
            if (invalid_continuing_octet(*from)) {
                from_next   = from;
                to_next =   to;
                return std::codecvt_base::error;
            }

            ucs_result *= (1 << 6);

            // each continuing character has an extra (10xxxxxx)b attached to
            // it that must be removed.
            ucs_result += (unsigned char)(*from++) - 0x80;
            ++i;
        }

        // If   the buffer ends with an incomplete unicode character...
        if (from == from_end && i   != cont_octet_count) {
            // rewind "from" to before the current character translation
            from_next = from - (i+1);
            to_next = to;
            return std::codecvt_base::partial;
        }
        *to++   = ucs_result;
    }
    from_next = from;
    to_next = to;

    // Were we done converting or did we run out of destination space?
    if(from == from_end) return std::codecvt_base::ok;
    else return std::codecvt_base::partial;
}

std::codecvt_base::result utf8_codecvt_facet::do_out(
    std::mbstate_t& /*state*/,
    const wchar_t *   from,
    const wchar_t * from_end,
    const wchar_t * & from_next,
    char * to,
    char * to_end,
    char * & to_next
) const
{
    // RG - consider merging this table with the other one
    const wchar_t octet1_modifier_table[] = {
        0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
    };

    wchar_t max_wchar = (std::numeric_limits<wchar_t>::max)();
    while (from != from_end && to != to_end) {

        // Check for invalid UCS-4 character
        if (*from  > max_wchar) {
            from_next = from;
            to_next = to;
            return std::codecvt_base::error;
        }

        int cont_octet_count = get_cont_octet_out_count(*from);

        // RG  - comment this formula better
        int shift_exponent = (cont_octet_count) *   6;

        // Process the first character
        *to++ = static_cast<char>(octet1_modifier_table[cont_octet_count] +
            (unsigned char)(*from / (1 << shift_exponent)));

        // Process the continuation characters
        // Invariants: At   the start of the loop:
        //   1) 'i' continuing octets   have been generated
        //   2) '*to'   points to the next location to place an octet
        //   3) shift_exponent is   6 more than needed for the next octet
        int i   = 0;
        while   (i != cont_octet_count && to != to_end) {
            shift_exponent -= 6;
            *to++ = static_cast<char>(0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)));
            ++i;
        }
        // If   we filled up the out buffer before encoding the character
        if(to   == to_end && i != cont_octet_count) {
            from_next = from;
            to_next = to - (i+1);
            return std::codecvt_base::partial;
        }
        *from++;
    }
    from_next = from;
    to_next = to;
    // Were we done or did we run out of destination space
    if(from == from_end) return std::codecvt_base::ok;
    else return std::codecvt_base::partial;
}

// How many char objects can I process to get <= max_limit
// wchar_t objects?
int utf8_codecvt_facet::do_length(
    BOOST_CODECVT_DO_LENGTH_CONST std::mbstate_t &,
    const char * from,
    const char * from_end,
    std::size_t max_limit
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
) const throw()
#else
) const
#endif
{
    // RG - this code is confusing!  I need a better way to express it.
    // and test cases.

    // Invariants:
    // 1) last_octet_count has the size of the last measured character
    // 2) char_count holds the number of characters shown to fit
    // within the bounds so far (no greater than max_limit)
    // 3) from_next points to the octet 'last_octet_count' before the
    // last measured character. 
    int last_octet_count=0;
    std::size_t char_count = 0;
    const char* from_next = from;
    // Use "<" because the buffer may represent incomplete characters
    while (from_next+last_octet_count <= from_end && char_count <= max_limit) {
        from_next += last_octet_count;
        last_octet_count = (get_octet_count(*from_next));
        ++char_count;
    }
    return static_cast<int>(from_next-from_end);
}

unsigned int utf8_codecvt_facet::get_octet_count(
    unsigned char   lead_octet
){
    // if the 0-bit (MSB) is 0, then 1 character
    if (lead_octet <= 0x7f) return 1;

    // Otherwise the count number of consecutive 1 bits starting at MSB
//    assert(0xc0 <= lead_octet && lead_octet <= 0xfd);

    if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
    else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
    else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
    else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
    else return 6;
}

namespace {
template<std::size_t s>
int get_cont_octet_out_count_impl(wchar_t word){
    if (word < 0x80) {
        return 0;
    }
    if (word < 0x800) {
        return 1;
    }
    return 2;
}

// note the following code will generate on some platforms where
// wchar_t is defined as UCS2.  The warnings are superfluous as
// the specialization is never instantitiated with such compilers.
template<>
int get_cont_octet_out_count_impl<4>(wchar_t word){
    if (word < 0x80) {
        return 0;
    }
    if (word < 0x800) {
        return 1;
    }
    if (word < 0x10000) {
        return 2;
    }
    if (word < 0x200000) {
        return 3;
    }
    if (word < 0x4000000) {
        return 4;
    }
    return 5;
}

} // namespace anonymous

// How many "continuing octets" will be needed for this word
// ==   total octets - 1.
int utf8_codecvt_facet::get_cont_octet_out_count(
    wchar_t word
) const {
    return get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
}


#endif



저작자 표시 비영리
신고


원래 컴퓨터 문자의 시초는 아스키 코드다. 아스키 코드에서는 1 문자는 1 byte 로 이루어져 있다.

하지만 이것으로는 모든 문자를 표현하는 것이 불가능하다. 요즘처럼 글로벌 시대에 다국어를 표현하려면 1 byte 는 많이 부족하다 특히 한글은 전세계 언어중에서 가장 큰 다양성을 가지고 있는데 모두 다 조합하면 다른 언어 다 합친것의 절반이상의 용량을 차지한다. 세종대왕님 감사합니다. ^^

다국어 뿐만 아니라 특수 문자 문제도 있기 때문에 적어도 2 byte 의 길이를 가진 code set 이 필요하게 되었다.

하지만 컴퓨터는 미국에서 개발되었고 걔네들은 2byte 쓸 이유가 없다. 특히 램값이 금값인 시절에 문자열 하나에는 1 byte 이상 차지하는 건 사치다. 그래서 1 byte = 1 문자로 최근까지 이어져왔다. 하지만 우리나라 같은 곳에서는 어쩔 수 없이 편법을 써서라도 한글을 표현해야 했고, 이를 극복하기 위해서 쓰는 대표적인 개념이 codepage 라는 개념이다.

데이터는 고정된 상태에서 codepage 에 따라 보이는 모양이 변한다. 예전에 일본 게임을 한국 윈도우에서 실행하면 메뉴의 글이 깨지는 것을 볼 수 있다. code page 가 일본으로 설정되어 있어야 제대로 보이기 때문이다. 하지만 일본 게임의 일본어를 보기위해 기본 code page 를 일본으로 설정하면 한글 윈도우 내의 다른 모든 한글이 엉망이 되버리는 문제가 있다.


이러한 문제로 개발 된 것이 unicode 이다.
모든 문자셋 + 기호를 지원하기 위해 2 byte 이상의 용량을 차지하는 문자셋을 개발한 것이다.

윈도우도 windows 2000 부터는 문자 set 으로 unicode 가 사용되었다. 기존의 아스키 코드가 1 byte 라면 window 에서 사용하는 unicode 는 2 byte 로 고정되어 있는 UTF16LE (little edition) 을 사용한다. 참고로 대부분의 unix 계열은 UTF-8 을 사용한다.

나도 처음에 unicode 하면 UTF16LE 인줄 알았다. 근데 잘 보니 unicode 에 종류가 무척 많다. 다 기억은 못하지만 UTF16BE (big edition) 도 있다. 다 알것 없고 unicode 는 2가지를 많이 쓴다고만 알면 된다.

1) UTF16LE --> windows 2000, winxp, vista, windows 7 등의 unicode / 2 byte 고정
2) UTF-8 --> unix/linux 계열에서 사용 / mysql 등의 database 에서 사용 / web 에서 표준 / 1 byte ~ 4 byte 가변
 
즉 많이 쓰는 것은 UTF16LE 와 UTF-8 두가지다.
 
UTF-8 이 참 재미있는 녀석인데 이놈은 개발 당시부터 아스키를 기준으로 만들어진 기존 프로그램을 그대로 이용하기 위해서 만들어졌다. 따라서 아스키 문자열과 호환이 된다. 하지만 1 byte 인 아스키 문자열이 커버하지 못하는 부분을 1 byte ~ 4 byte 까지 더 확장해서 표현한다. 그리고 문자열 중간에 null code 가 없기 때문에 기존 아스키 프로그램에 잘 돌아간다. 이런 이유로 unix 계열 / web / database 에서 unicode 하면 대부분 UTF-8 이다.

UTF16LE 는 마이크로 소프트 윈도우즈에서 사용되는 2 byte 문자셋이다. 장점은 문자열 길이 잴때 편하다(무조건 2로 나누면 되니깐... UTF-8 은 한문자가 몇바이트인지 앞에서부터 세보지 않으면 알 수 없다.)는 것 빼고는 다른 면에서 UTF-8 보다 뭐가 좋은지 잘 모르겠다. 결정적으로 기존 아스키 프로그램에 호환이 안되기 때문에 프로그램을 다시 짜야한다.

함수를 모조리 바꿔야 하는데 이게 보통 머리아픈게 아니다. 윈도우 내장 API 함수를 보면 MessageBoxA / MessageBoxW 이렇게 2가지가 있는데 A 로 끝나는 것은 기존의 아스키 함수 / W 는 Wide Character 를 쓰는 유니코드 함수이다. MFC 같은 라이브러리에서는 MessageBox 라고 하면 셋팅을 보고 알아서  MessageBoxA / MessageBoxW 중에 한놈으로 바꿔준다.


 


 
저작자 표시 비영리
신고



MedicalPhoto 는 의료용 사진관리 프로그램이다. 현재 의료용 사진관리 프로그램은 제대로 된 게 없다. 2004 년에 사진관리하기가 귀찮아서 만들었고 현재는 서울아산병원, 중앙대 병원 피부과에서 사용중이다. 무료 software 이다.

전세계인이 쓸 수 있는 사용하기 편한 의료용 사진관리 프로그램을 위해 개발되었다.

의사 입장에서 좋은 점은

1) 피부과 진단 코드가 거의다 들어있다. 거의 모든 textbook 에 있는 진단 코드와 ICD-10 코드 포함
2) 네트워크 지원으로 진료방에서 볼 수 있다.
3) 큰 화면을 지원하며 인터페이스가 직관적이라 사용이 편하다.
4) 자동 업데이트 지원

이 프로그램은 개발하면서 정말 오랜 시간이 걸렸다. 버그를 없애기 위해 엄청난 노력을 기울였다. 프로그래밍 입장에서 발전한 점은

1) 인스톨러 (ci installer 사용) & 웹 자동 업데이트
2) 서버-클라이언트 자동 업데이트
3) unicode 지원 (UTF-16LE & UTF-8)
4) Sqlite 데이터베이스로 사용
5) Joomla 로 홈페이지 작성 - maxmind 의 geographic tool 이용
6) GPL 라이센스를 따른다. - SVN 으로 코드 관리 중이다.
7) sourceforge.net 에 등록
8) pdf 토큐먼트 제공
9) 다중 모니터 지원


내가 지금까지 써본 상용 의료용 사진 관리 프로그램보다 훨씬 빠르고 강력하다. 프로그램은 installer 가 5 메가 정도로 작고 메모리도 순간 최고 20 메가 정도 밖에 안 차지한다.

http://medicalphoto.org




저작자 표시 비영리
신고


내가 2004 년 울산대학교에 파견 근무를 나가서 만든 프로그램이다.

이 프로그램을 만들면서 SQL 프로그래밍을 익혔다. sql 서버는 mysql 로 동작하고 프로그램은 mysql++ 를 이용해서 코딩하였다.

mysql++ 는 아래에서 받을 수 있다.
http://tangentsoft.net/mysql++/

mysql 을 사용한다면 mysql++ 로 코딩하게 되겠지만 대부분 이렇게 큰 DB 를 사용할 필요는 없어 보인다.

이경우 sqlite 가 좋은 대안이다. 작년에 완성된 Medicalphoto (http://medicalphoto.org) 는 Sqlite (http://sqlite.org) 를 DB 로 사용한다. cppsqlite (http://www.codeproject.com/KB/database/CppSQLite.aspx)라는 좋은 라이브러리가 있고 유니코드도 UTF-8 범위에서 지원한다.

아래는 dermastat 화면이다. ^^

소스가 필요한 사람은 별도로 메세지를 주세요.


저작자 표시 비영리
신고


FEDORA 나 UBUNTU 를 설치하면 한글 / 영문 버젼을 선택해서 설치해야합니다.

문제는 한글을 사용하면서 display 되는 메뉴나 메세지는 영문으로 받고 싶은 상황입니다.

대부분의 문서가 영문으로 된 메세지, 메뉴를 기준으로 하기 때문입니다.

아래는 fedora 3 에서 영문 linux 상태에서 한글 입력하는 방법입니다.

리눅스는 locale 설정은

# locale

로 확인이 가능합니다. 여기서 보이는 LC_MESSAGES 가 한글이면 한글로 보이고 영문이면 영문으로 보입니다.

가장 중요한 포인트는

export LC_MESSAGES=en_US.UTF-8          ( 또는 UTF-8 유니코드가 아닌 다른 영문 locale )

로 설정하면 터미널에서 메세지가 영문으로 나옵니다.

ubuntu 도 기본적인 틀은 동일합니다.

가장 편리한 방법은 처음에 install 할 때 영문 linux 로 인스톨하고 한글을 쓸 수 있게 설정하는 것입니다.

ubuntu 의 경우 이렇게 install 하면 그놈 메뉴까지 영문으로 보입니다.



아래는 영문으로 설치한 fedora 3 에서 한글 사용법입니다.


fedora 에서 언어 설정을 한글로 하면 다 좋은데 터미널에서 아래 밑줄 (_) 이 보이지 않고 아무래도 한글이 가독성이 떨어지기 때문에 영문 메뉴에 비해서 눈에 확 안들어옵니다. 그래서 영문 fedora 상태에서 한글을 입력할 수 있나 한참을 삽질한 끝에 방법을 알아냈습니다. ^^



1. nabi 0.14 버젼을 받습니다.

http://nabi.kldp.net/

에서 받으면 됩니다.
설치를 하려면 GTK 2.4 버젼이 필요한데,

이는 fedora 인스톨 시에 GENOME 개발툴 안에 들어있습니다. 처음 fedora 설치시에 GENOME 개발툴 등을 설치해야 GTK 를 설치하는 수고를 덜 수 있습니다.

나비 홈페이지에 있는대로 설치를 합니다.

2.

나비가 어디에 설치되었는지 알 필요가 있습니다.
터미널에서

whereis nabi

를 쳐서 어디에 설치되었는지 확인합니다. 참고로 fedora 2 의 경우에는 한글로 설치하면 nabi 0.11 버젼이 설치됩니다. whereis 명령으로 위치를 확인 후에 nabi 를 실행해 보아서 어떤 것이 nabi 0.14 버젼인지 확인하세요.

3.

서비스에서 시스템 셋팅 -> 서비스 셋팅으로 들어가 보면
LLIM 이 부팅할 때 서비스로 시작되도록 되어 있는데 이를 해지해 줍니다. 해지후 SAVE

4.

/etc/sysconfig 에 있는 i18n 파일을 엽니다.

이것을 다음과 같이 고칩니다.

LANG="en_US.UTF-8"
SUPPORTED="en_US.UTF-8:en_US:en:ja_JP.UTF-8:ja_JP:ja:ko_KR.UTF-8:ko_KR:ko"
SYSFONT="latarcyrheb-sun16"
export LANG=en_US.UTF-8
export XIM_PROGRAM=/usr/local/bin/nabi
export XMODIFIERS="@im=nabi"
export GTK_IM_MODULE=xim

여기에서 /usr/local/bin/nabi 는 나비가 설치된 곳이 /usr/local/bin/ 일 경우에 해당합니다. 아까 whereis 에서 확인한 폴더를 여기에 적습니다.

5. 리부팅

리부팅하면 display 는 영문인 상태로 한글을 쓸 수 있습니다.

2004.10.06 한승석 http://whria.net
저작자 표시 비영리
신고


내가 만든 최초의 공개 프로그램 "천타를 꿈꾸며" ...

때는 1997 년. 당시에는 hetel, 나우, 천리안과 같은 pc 통신이 있었고 윈도우는 win95 가 많이 쓰이기 시작한 시기였다. 하지만 상당수의 사용자는 DOS 를 사용하고 있었다. 그리고 컴퓨터 교육이 붐이 일어서 많은 사람들이 타자연습부터 열공하고 있었다.

당시 가장 많이 사용된 프로그램은 "한메 타자 연습" 프로그램이었다. 그런데 이 프로그램에 치명적인 문제점이 있었으니 DOS 에서만 작동한다는 것이었다. win95 나 win98 과 같은 환경에서는 조금 안 이쁘게 동작하였다.

당시 방학을 맞아 뭔가 할 거리를 찾던 도중에 타자 프로그램을 만들기로 하였다.

지금은 reference 가 많이 공개되어 만들기 쉽지만 당시에 윈도우용 한글 타자 연습 만들기는 쉽지 않았다. 몇가지 문제가 있었는데...

1) 한글 IME 제어 문제 (최고 난이도 문제... backspace 누를 때마다 변하는 한글 code 를 잡아내는 문제등은 지금도 복잡한 문제이다.)
2) 한글 조합형 / 완성형 제어 문제 (당시 자료는 조합형 자료가 만아 convert 시키는 문제가 복잡했음)
3) 타자 결과를 www 으로 전송하는 문제 (당시 get / post 로 정보를 전달하는 법에 대한 자료가 정말 부족했다.)



하여튼 우여곡절 끝에 1.0 버젼을 만들었는데 반응이 폭발적이었다. 사진은 hitel 사진이다. 나우랑 천리안은 망해서 스크랩을 못했다.



당시 나우누리에서 3만회 이상 download 를 기록했던 것으로 기억한다. 다운수로 sort 했을 때 나우 역사 top 10 안에 들었다. 하지만 나는 방학때밖에 관리 할 수가 없었고 이후 번개손 등의 프로그램에 밀려서 현재는 아무도 안쓴다. ㅋㅋ


월간 천리안 1월호에 실리고 당시 모 컴터 잡지사 부록으로도 나갔다.


천타를 꿈꾸며를 통해 얻은 교훈은 ???

1) 남들이 하나도 안한 분야는 빨리 선점하라!!! 그러면 내가 대장이 된다.
2) 지속적으로 관리 안하면 무너진다.

저작자 표시 비영리
신고


 

추억의 MSX 기억하시나요?

제가 어렸을 때 열심히 BASIC 공부하다가 의욕이 넘쳐서 샀던 책입니다.

코아스 출판사의 기계어 입문이네요.



첫장이군요. 일본 사람 책을 번역한 거네요.

일본에서 온 형이 추천해 주었던 책이었죠.


 

머리말입니다. 마지막에 MSX 기계가 친근하게 느껴진다던데.. 당시에는 이해가 안가서 기계가 어렵게만 느껴졌죠.






BASIC 이 정말 느리긴 느렸습니다.




당시 5학년 4반이었군요. 1985 년이네요.

지금은 공학이랑 관계 없는 분야로 진로를 결정했지만

당시에 친구들이랑 프로그램 만들고 오락하는게 인생의 낙이었습니다.

BASIC 의 한계를 깨닳은 이후에 저는 이 책만 읽으면

사라만다, 그라디우스, 마성전설 같은 게임을 만들 수 있는 줄 믿고 용돈을 쏟아 부었죠.

지금 생각하면 절대 불가능한 일이죠. ^^
 


제 첫번째 컴퓨터였던 DPC-200 입니다. 아이큐 1000 이라는 모델이죠. 파란색 키보드를 게임(올림픽이라는 게임이 있었습니다.)하느라 5개쯤 뽀개먹은 기억이 생생합니다. 메가롬팩(당시 4만원쯤했죠)을 사고 싶어서 부모님께 조르던 기억... 성능이 좋은 아이큐 2000 을 가지고 싶었는데 못가졌던 아픈 기억도 있습니다. ^^
저작자 표시 비영리
신고


티스토리 툴바