Create TOC

레이블이 Programming인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Programming인 게시물을 표시합니다. 모든 게시물 표시

2013년 8월 30일

Python/Spiral Array

원문

문제는 다음과 같습니다:

6 6

  0   1   2   3   4   5
 19  20  21  22  23   6
 18  31  32  33  24   7
 17  30  35  34  25   8
 16  29  28  27  26   9
 15  14  13  12  11  10

위처럼 6 6이라는 입력을 주면 6 X 6 매트릭스에 나선형 회전을 한 값을 출력해야 합니다.

풀이

#!/usr/bin/python
# -*- coding: utf-8 -*-

def fill_round(matrix, num, mx, my, base_x, base_y):
    ix = base_x
    iy = base_y

    # LR 진행
    for n in range(0, mx):
        matrix[iy][ix] = num
        num = num + 1
        ix = ix + 1
    ix = ix - 1
    mx = mx - 1

    # UD 진행
    iy = iy + 1
    for n in range(1, my):
        matrix[iy][ix] = num
        num = num + 1
        iy = iy + 1
    iy = iy - 1
    my = my - 1

    if my < 1:
        return

    # RL 진행
    ix = ix - 1
    for n in range(mx - 1, -1, -1):
        matrix[iy][ix] = num
        num = num + 1
        ix = ix - 1
    ix = ix + 1
    mx = mx - 1

    if mx < 1:
        return

    # DU 진행
    iy = iy - 1
    for n in range(my - 1, 0, -1):
        matrix[iy][ix] = num
        num = num + 1
        iy = iy - 1
    return num

def solution(x, y):
    if x < 0 or y < 0:
        return [[]]
    matrix = [[-1 for i in range(0, x)] for j in range(0, y)]

    num = 0
    w = x
    h = y
    i = 0
    while True:
        num = fill_round(matrix, num, w, h, i, i)
        i = i + 1
        w = w - 2
        h = h - 2
        if w <= 0 or h <= 0:
            break
    return matrix

matrix = solution(6, 6)
print '\n'.join([' '.join(['%3u' % n for n in m]) for m in matrix])

print ''

matrix = solution(9, 7)
print '\n'.join([' '.join(['%3d' % n for n in m]) for m in matrix])

결과

  0   1   2   3   4   5
 19  20  21  22  23   6
 18  31  32  33  24   7
 17  30  35  34  25   8
 16  29  28  27  26   9
 15  14  13  12  11  10

  0   1   2   3   4   5   6   7   8
 27  28  29  30  31  32  33  34   9
 26  47  48  49  50  51  52  35  10
 25  46  59  60  61  62  53  36  11
 24  45  58  57  56  55  54  37  12
 23  44  43  42  41  40  39  38  13
 22  21  20  19  18  17  16  15  14

Python/LCD Display

원문

한 친구가 방금 새 컴퓨터를 샀다. 그 친구가 지금까지 샀던 가장 강력한 컴퓨터는 공학용 전자 계산기였다. 그런데 그 친구는 새 컴퓨터의 모니터보다 공학용 계산기에 있는 LCD 디스플레이가 더 좋다며 크게 실망하고 말았다. 그 친구를 만족시킬 수 있도록 숫자를 LCD 디스플레이 방식으로 출력하는 프로그램을 만들어보자.

입력

입력 파일은 여러 줄로 구성되며 표시될 각각의 숫자마다 한 줄씩 입력된다. 각 줄에는 s와 n이라는 두개의 정수가 들어있으며 n은 출력될 숫자( 0<= n <= 99,999,999 ), s는 숫자를 표시하는 크기( 1<= s < 10 )를 의미한다. 0 이 두 개 입력된 줄이 있으면 입력이 종료되며 그 줄은 처리되지 않는다.

출력

입력 파일에서 지정한 숫자를 수평 방향은 '-' 기호를, 수직 방향은 '|'를 이용해서 LCD 디스플레이 형태로 출력한다. 각 숫자는 정확하게 s+2개의 열, 2s+3개의 행으로 구성된다. 마지막 숫자를 포함한 모든 숫자를 이루는 공백을 스페이스로 채워야 한다. 두 개의 숫자 사이에는 정확하게 한 열의 공백이 있어야 한다.

풀이

#!/usr/bin/python
# -*- coding: utf-8 -*-

q = {
    '1': {
        0: lambda c: [c, 0, 0],
        1: lambda c: [0, (c - 1), 1],
        2: lambda c: [c, 0, 0],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [c, 0, 0],
    },
    '2': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [0, (c - 1), 1],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [1, (c - 1), 0],
        4: lambda c: [1, (c - 2), 1],
    },
    '3': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [0, (c - 1), 1],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [1, (c - 2), 1],
    },
    '4': {
        0: lambda c: [c, 0, 0],
        1: lambda c: [1, (c - 2), 1],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [c, 0, 0],
    },
    '5': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [1, (c - 1), 0],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [1, (c - 2), 1],
    },
    '6': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [1, (c - 1), 0],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [1, (c - 2), 1],
        4: lambda c: [1, (c - 2), 1],
    },
    '7': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [0, (c - 1), 1],
        2: lambda c: [c, 0, 0],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [c, 0, 0],
    },
    '8': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [1, (c - 2), 1],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [1, (c - 2), 1],
        4: lambda c: [1, (c - 2), 1],
    },
    '9': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [1, (c - 2), 1],
        2: lambda c: [1, (c - 2), 1],
        3: lambda c: [0, (c - 1), 1],
        4: lambda c: [1, (c - 2), 1],
    },
    '0': {
        0: lambda c: [1, (c - 2), 1],
        1: lambda c: [1, (c - 2), 1],
        2: lambda c: [c, 0, 0],
        3: lambda c: [1, (c - 2), 1],
        4: lambda c: [1, (c - 2), 1],
    },
}

def print_x(s, nums):
    if s <= 0:
        return
    c = s + 2
    r = s * 2 + 3

    print ''.join([' ' * q[n][0](c)[0] + '-' * q[n][0](c)[1] + ' ' * q[n][0](c)[2] + ' ' for n in nums])
    print '\n'.join([''.join(['|' * q[n][1](c)[0] + ' ' * q[n][1](c)[1] + '|' * q[n][1](c)[2] + ' ' for n in nums]) for i in xrange(0, r / 2 - 1)])
    print ''.join([' ' * q[n][2](c)[0] + '-' * q[n][2](c)[1] + ' ' * q[n][2](c)[2] + ' ' for n in nums])
    print '\n'.join([''.join(['|' * q[n][3](c)[0] + ' ' * q[n][3](c)[1] + '|' * q[n][3](c)[2] + ' ' for n in nums]) for i in xrange(0, r / 2 - 1)])
    print ''.join([' ' * q[n][4](c)[0] + '-' * q[n][4](c)[1] + ' ' * q[n][4](c)[2] + ' ' for n in nums])

print_x(2, '1234567890')
print ''
print_x(4, '1234567890')

실행 결과는 아래와 같다.

      --   --        --   --   --   --   --   --
   |    |    | |  | |    |       | |  | |  | |  |
   |    |    | |  | |    |       | |  | |  | |  |
      --   --   --   --   --        --   --
   | |       |    |    | |  |    | |  |    | |  |
   | |       |    |    | |  |    | |  |    | |  |
      --   --        --   --        --   --   --

        ----   ----          ----   ----   ----   ----   ----   ----
     |      |      | |    | |      |           | |    | |    | |    |
     |      |      | |    | |      |           | |    | |    | |    |
     |      |      | |    | |      |           | |    | |    | |    |
     |      |      | |    | |      |           | |    | |    | |    |
        ----   ----   ----   ----   ----          ----   ----
     | |           |      |      | |    |      | |    |      | |    |
     | |           |      |      | |    |      | |    |      | |    |
     | |           |      |      | |    |      | |    |      | |    |
     | |           |      |      | |    |      | |    |      | |    |
        ----   ----          ----   ----          ----   ----   ----

2013년 7월 1일

nodejs/sample

간단한 node.js sample.

var url = require('url');
var domain = require('domain');
var fs = require('fs');

require('http').createServer(function(req, res) {
	var u = url.parse(req.url, true);
	if (u.pathname == '/error') {
		if (u.search == '') {
			res.writeHead(200);
			res.write('<html><title>error</title></head><body>error</body></html>');
		}
		else {
			res.writeHead(u.query.e);
			res.write('<html><title>error</title></head><body>' + u.query.e + '</body></html>');
		}
		res.end();
	}
	else {
		if (u.pathname == '/') {
			u.pathname = '/index.html';
		}
		var d = domain.create();
		d.run(function() {
			fs.readFile(__dirname + '/public_html'+ u.pathname, d.intercept(function(data) {
				res.writeHead(200);
				res.write(data, 'utf8');
				res.end();
			}));
		});

		d.on('error', function(err) {
			console.log(err);
			var errpage = '/error';

			if (err.errno == 34) {
				errpage = errpage + '?e=404';
			}
			res.writeHead(302, {'Location': errpage});
			res.end();
		});
	}
}).listen(1234);

2012년 8월 13일

Python/ctypes in Win32

ctypes를 이용해 Win32 환경에서 작업하는 예제 기록.

자료구조

ctypes vs Win32

ctypes.wintypes를 참고한다.

배열

WCHAR [1000]의 배열을 선언한다고하면

FileNameType = c_wchar * 1000
a = FileNameType()

익명 구조체/공용체 선언

SYSTEM_INFO 구조체는 아래와 같이 역명 구조체와 공용체를 가지고 있다.

typedef struct _SYSTEM_INFO {
	union {
		DWORD  dwOemId;
		struct {
			WORD wProcessorArchitecture;
			WORD wReserved;
		};
	};
	DWORD     dwPageSize;
	LPVOID    lpMinimumApplicationAddress;
	LPVOID    lpMaximumApplicationAddress;
	DWORD_PTR dwActiveProcessorMask;
	DWORD     dwNumberOfProcessors;
	DWORD     dwProcessorType;
	DWORD     dwAllocationGranularity;
	WORD      wProcessorLevel;
	WORD      wProcessorRevision;
} SYSTEM_INFO;

이 구조체를 ctypes로 표시하면 아래와 같다.

class _Noname1(ctypes.Structure):
    _fields_ = [("wProcessorArchitecture", ctypes.c_ushort),
                ("wReserved", ctypes.c_short)]


class _Noname2(ctypes.Union):
    _anonymous_ = ("s",)
    _fields_ = [('dwOemId', ctypes.c_ulong),
                ('s', _Noname1)]


class SYSTEM_INFO(ctypes.Structure):
    _anonymous_ = ("u",)
    _fields_ = [("u", _Noname2),
                ("dwPageSize", ctypes.c_ulong),
                ("lpMinimumApplicationAddress", ctypes.c_void_p),
                ("lpMaximumApplicationAddress", ctypes.c_void_p),
                ("dwActiveProcessorMask", ctypes.c_ulong),  # 64 bit에서는 c_longlong이 되어야 한다.
                ("dwNumberOfProcessors", ctypes.c_ulong),
                ("dwProcessorType", ctypes.c_ulong),
                ("dwAllocationGranularity", ctypes.c_ulong),
                ("wProcessorLevel", ctypes.c_ushort),
                ("wProcessorRevision", ctypes.c_ushort)]

pointer type 선언

위에서 선언한 SYSTEM_INFO에 대한 pointer type으로 LPSYSTEM_INFO을 선언한다고 하면

LPSYSTEM_INFO = ctypes.POINTER(SYSTEM_INFO)

ctypes.LP_c_char를 문자열로 변환

ctypes.LP_c_charctypes.c_char_p로 형변환하면 된다.

ctypes.cast(ctypes.LP_c_char 객체, ctypes.c_char_p).value

함수 호출

Win32 API 호출

ctypes.windll뒤에 원하는 dll 모듈과 함수를 사용하면 된다. 예를 들어 kernel32GetsystemInfo함수를 호출한다면 아래와 같이 호출할 수 있다.

ctypes.windll.kernel32.GetsystemInfo( ... )

DLL 함수 호출

test1.dllvoid __cdecl testfunction1() 함수를 호출한다고 하면

test1 = ctypes.CDLL('test1.dll')
if test1:
	test1.testfunction1()

함수 인자로 pointer 전달

si = SYSTEM_INFO()
ctypes.windll.kernel32.GetSystemInfo(ctypes.byref(si))

함수 인자로 string buffer 전달

buf = ctypes.create_unicode_buffer(4096)
r = ctypes.windll.kernel32.GetWindowsDirectoryW(buf, 4096)
if r > 0:
	print buf.value

함수 반환값 검사

함수 객체의 errcheck를 지정하면 함수의 반환값 검사를 모아서 할 수 있다. 예를 들어 test2.dllBOOL __cdecl testfunction2() 함수에 대해서 코드를 작성해보면 아래와 같다.

>def checkBOOL(result, function, args):
    if result == 0:
		raise ctypes.WinError()
	return args

test2 = ctypes.CDLL('test2.dll')
test2.testfunction2.errcheck = checkBOOL

test2.testfunction2()  # 함수 호출이 끝나면 바로 checkBOOL 함수가 호출되서 반환값 검사를 할 수 있다.

명시적인 함수 인자 지정

함수 객체의 argtypes를 이용해서 함수의 인자를 명시적으로 지정할 수 있다. 예를 들어 test3.dllBOOL __cdecl testfunction3(LPCWSTR, LPBOOL)에 대해서 코드를 작성해보면 아래와 같다.

test3 = ctypes.CDLL('test3.dll')
test3.testfunction3.argtypes = [ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_long)]

b = ctypes.c_long()
r = test3.testfunction3(u"hello, world!", ctype.byref(b))

명시적인 함수 반환형 지정

함수 객체의 restype을 시용해서 함수의 반환형을 명시적으로 지정할 수 있다(함수 반환형이 void라면 None을 사용한다). 예를 들어 test4.dllHANDLE __cdecl testfunction4()에 대해서 코드를 작성해보면 아래와 같다.

test4 = ctypes.CDLL('test4.dll')
test4.testfunction4.restype = ctypes.c_void_p

h = test4.testfunction4()

callback 함수

callback 함수 형식에 따라 ctypes.CFUNCTYPE 또는 ctypes.WINFUNCTYPE을 사용해서 callback 함수 형을 만들면 된다.

CFUNCTYPE

python 문서에 나온 예제를 Win32에 맞게 변형했다.

CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))


def py_cmp_func(a, b):
    print 'py_cmp_func', a[0], b[0]
    return 0

cmp_func = CMPFUNC(py_cmp_func)

IntArray5 = ctypes.c_int * 5
ia = IntArray5(5, 1, 7, 33, 99)
qsort = ctypes.windll.msvcrt.qsort
qsort.restype = None
qsort(ia, len(ia), ctypes.sizeof(ctypes.c_int), cmp_func)

WINFUNCTYPE

LF_FACESIZE = 32
LF_FULLFACESIZE = 64


class LOGFONT(ctypes.Structure):
    _fields_ = [
        ('lfHeight', ctypes.c_long),
        ('lfWidth', ctypes.c_long),
        ('lfEscapement', ctypes.c_long),
        ('lfOrientation', ctypes.c_long),
        ('lfWeight', ctypes.c_long),
        ('lfItalic', ctypes.c_byte),
        ('lfUnderline', ctypes.c_byte),
        ('lfStrikeOut', ctypes.c_byte),
        ('lfCharSet', ctypes.c_byte),
        ('lfOutPrecision', ctypes.c_byte),
        ('lfClipPrecision', ctypes.c_byte),
        ('lfQuality', ctypes.c_byte),
        ('lfPitchAndFamily', ctypes.c_byte),
        ('lfFaceName', ctypes.c_wchar * LF_FACESIZE)]
PLOGFONT = ctypes.POINTER(LOGFONT)


class ENUMLOGFONT(ctypes.Structure):
    _fields_ = [
        ('elfLogFont', LOGFONT),
        ('elfFullName', ctypes.c_wchar * LF_FULLFACESIZE),
        ('elfStyle', ctypes.c_wchar * LF_FACESIZE)]
PENUMLOGFONT = ctypes.POINTER(ENUMLOGFONT)


if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
    LPARAM = ctypes.c_long
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
    LPARAM = ctypes.c_longlong

#int CALLBACK EnumFontFamProc(ENUMLOGFONT *lpelf,__in  NEWTEXTMETRIC *lpntm, DWORD FontType, LPARAM lParam;
EnumFontFamProc = ctypes.WINFUNCTYPE(ctypes.c_int, PENUMLOGFONT, ctypes.c_void_p, ctypes.c_long, LPARAM)


def py_enum_font_fam_proc(lpelf, lpntm, FontType, lparam):
    print 'py_enum_font_fam_proc', lpelf.contents.elfFullName
    return 1

enum_font_proc = EnumFontFamProc(py_enum_font_fam_proc)

EnumFontFamilies = ctypes.windll.gdi32.EnumFontFamiliesW
hdc = ctypes.windll.user32.GetDC(0)
EnumFontFamilies(hdc, 0, enum_font_proc, 0)
ctypes.windll.user32.ReleaseDC(hdc)

2012년 8월 11일

cygwin/Windows 개발을 위한 Makefile template

cygwin에서 Windows 프로그램 개발을 위한 Makefile template.

BASECFLAGS = -DUNICODE -D_UNICODE -DWIN32 -D_WIN32 -Wall -Wextra -ffunction-sections -fdata-sections
CXXFLAGS = -fno-rtti -fno-exceptions

ifdef debug
	OPTFLAGS = -g -DDEBUG -Wall -Wextra -Wfloat-equal -Wunreachable-code
else
	OPTFLAGS = -Os -s -DNDEBUG
endif

ifdef x64
	MINGWPREFIX = x86_64-w64-mingw32
	CFLAGS = $(BASECFLAGS) $(OPTFLAGS) -DWIN64 -D_WIN64
else
	MINGWPREFIX = i686-pc-mingw32
	CFLAGS = $(BASECFLAGS) $(OPTFLAGS)
endif
LDFLAGS = -Wl,--gc-sections -mwindows -mno-cygwin

CC = $(MINGWPREFIX)-gcc
CXX = $(MINGWPREFIX)-g++
RES = $(MINGWPREFIX)-windres

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

%.o: %.cpp
	$(CXX) $(CFLAGS) $(CXXFLAGS) -c $< -o $@

%.res.o: %.rc
	$(RES) -i $< -o $@

Makefile은 아래와 같이 사용할 수 있다.

디버그 빌드시

$ make debug=1

x64 빌드시

$ make x64=1

2010년 10월 20일

core 수에 따른 make의 job 최적화

make 에는 -j 옵션이 있고, 이 옵션은 한번에 수행할 수 있는 job 을 지정하는 옵션이다.

이 job의 수는 총 core 개수 + core 개수의 20% 를 추가하는 것이 가장 효율이 좋다고 알려져 있다. 즉

job 수 = core 개수 + round(core 개수 * 0.2)

가 된다.

즉 Q6600 같이 core가 4개라면 4 + round(4 * 0.2) = 5가 된다.

시스템 마다 이것을 계산하는 shell script를 짜면 아래와 같다.

#~/bin/sh

cores=`cat /proc/cpuinfo | grep cores | wc -l`
jobs=`echo "$cores + $cores*0.2"|bc`
echo $jobs|awk '{print int($1+0.5)}'

2010년 6월 6일

OS/X - PyQt 설치

이 문서는 Snow Leopard에서 PyQt를 설치하는 방법을 기술한다.

준비

아래 경로에서 Cocoa 버전의 QT 를 다운 받는다.

http://qt.nokia.com/downloads/qt-for-open-source-cpp-development-on-mac-os-x

아래 경로에서 PyQt를 다운 받는다.

http://www.riverbankcomputing.co.uk/software/pyqt/download

아래 경로에서 sip를 다운 받는다.

http://www.riverbankcomputing.co.uk/software/sip/download

PyQt 빌드 및 설치

sip

우선 터미널에서 아래와 같이 sip를 빌드하고 설치한다.

$ export MACOSX_DEPLOYMENT_TARGET=10.6
$ python configure.py --universal --arch=i386 --arch=x86_64 -s MacOSX10.6.sdk
$ make
$ sudo make install

PyQt 빌드

$ export QTDIR=/Developer/Applications/Qt
$ python configure.py --confirm-license --use-arch=i386 --use-arch=x86_64
$ make
$ sudo make install

테스트

아래와 같은 python 코드를 저장하고 실행해본다

import sys
from PyQt4 import QtCore, QtGui


def translate(widgetname, defstr):
    return QtGui.QApplication.translate(widgetname, defstr)


class Sample(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Sample, self).__init__(parent)

        self.setWindowTitle(translate(u'mainwindow', u'Sample'))
        self.resize(250, 150)
        self.setCenter()

        self.statusBar().showMessage(translate(u'mainwindow', u'Ready'))

        workarea = QtGui.QWidget(self)

        quit = QtGui.QPushButton(translate(u'mainwindow', u'Close'), workarea)
        workarea.connect(quit, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT('close()'))
        quit.setToolTip(translate(u'mainwindow', u'This is a close button.'))
        QtGui.QToolTip.setFont(QtGui.QFont(u'Tahoma', 10))

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(quit)

        vbox = QtGui.QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        workarea.setLayout(vbox)
        self.setCentralWidget(workarea)

    def closeEvent(self, event):
        reply = QtGui.QMessageBox.question(
            self,
            translate(u'messagebox', u'Question'),
            translate(u'messagebox', u'Are you sure to quit?'),
            QtGui.QMessageBox.Yes,
            QtGui.QMessageBox.No)

        if QtGui.QMessageBox.Yes == reply:
            event.accept()
        else:
            event.ignore()

    def setCenter(self):
        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Sample()
    main.show()
    sys.exit(app.exec_())

실행하면 아래와 같은 화면이 표시된다.

2010년 3월 1일

기온 변화 그래프 2

기상청 홈페이지가 개편되면서 날씨 정보에 대한 xml를 제공하기 시작했습니다. 그러나 기온 변화 그래프에서 필요한 현재 시간 날씨 정보에 대해서는 xml 데이타를 제공하지 않습니다.

기온 변화 그래프를 계속 그리기 위해서 기상청 웹페이지를 해석해서 그래프로 그리는 간단한 python 스크립트를 작성해봤습니다.

이 스크립트는 기상청 페이지를 가져와서 xml로 변환하는 buildwexml.py와 그래프를 그리는 gengraph.py 두 부분으로 나뉘어 있습니다.

이 스크립트는 Debian Linux, python 2.5 환경에서 제작, 테스트 되었습니다.

코드는 아래와 같습니다

gengraph.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""gengraph.py

buildwexml.py를 이용해 생성한 xml 파일을 가지고 그래프를 그리는 스크립트
"""
__author__ = 'Yun-yong Choi'
__version__ = '0.1'

import time
import xml.etree.ElementTree

import Gnuplot, Gnuplot.funcutils

import buildwexml

# 데이타를 저장할 경로
write_root = '/tmp/'
# 그래프 파일 경로
graph_filename = '/home/markboy/temperature_graph.png'
writeinfo = {
      u'서울':[u'seoul.dat', u'Seoul'],
      u'부산':[u'busan.dat', u'Busan'],
      u'제주':[u'jeju.dat', u'Jeju'],
}
findcities = [ u'서울', u'부산', u'제주' ]

# web에서 xml 정보를 가져온다.
buildwexml.build(write_root + 'current.xml')

#xml을 해석한다.
xmlobj = xml.etree.ElementTree.parse(write_root + 'current.xml')
timestr = time.strftime('%Y/%m/%d %H', 
                time.strptime(xmlobj.getiterator('datetime')[0].attrib['data'], '%Y.%m.%d.%H:%S') )
# city node를 순회한다.
for city in  xmlobj.getiterator('city'):
    # 찾는 도시가 있으면
    if city.attrib['name'] in findcities :
        # 기온값을 저장한다.
        f = file(write_root + writeinfo[city.attrib['name']][0], 'at')
        f.write("%s %s\n" % (timestr, city.find('temperature').find('now').attrib['data']))
        f.close()
# 일주일분만 표시하기 위해서 7일전 날짜를 구한다.
ago = time.time() - 60 * 60 * 24 * 7
ago_str = time.strftime("%Y/%m/%d", time.localtime(ago) )

# plot 파일 저장
f = file(write_root + 'temperature_graph.plot', 'wt')
f.write("""
set term png small
set size 1.0, 0.6
set output '%s'
set grid
set key left bottom
set ylabel \"Temperature(C)\"

set xdata time
set timefmt \"%%Y/%%m/%%d\"
set xrange [\"%s\":]
set timefmt \"%%Y/%%m/%%d %%H\"
set format x \"%%m/%%d\"

plot """ % (graph_filename, ago_str) )

for key in writeinfo.keys() :
    f.write("'%s' using 1:3 title \"%s\" with line" % (write_root + writeinfo[key][0], writeinfo[key][1]))
    if key <> writeinfo.keys()[-1] :
        f.write(', ')
f.close()
# 그래프 그리기
g = Gnuplot.Gnuplot()
g.load(write_root + 'temperature_graph.plot')

buildwexml.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" buildwexml.py

기상청의 현재 날씨 정보 페이지를 가져와서 xml 파일을 만드는 스크립트
"""
__author__ = 'Yun-yong Choi'
__version__ = '0.2'

import os
import sys
import codecs
import urllib2

def getWebpage(url, referer='') :
    """url 파일을 읽어온다"""
    debug = 0
    if debug :
        return file(url.split('/')[-1], 'rt').read()
    else :
        opener = urllib2.build_opener()
        opener.addheaders = [
            ('User-Agent', 'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)'),
            ('Referer', referer),
        ]
        return opener.open(url).read()

def getMainPage():
    return getWebpage('http://www.kma.go.kr/weather/observation/currentweather.jsp')

def getDataPage():
    return getWebpage('http://www.kma.go.kr/weather/observation/currentweather_data.jsp', 'http://www.kma.go.kr/weather/observation/currentweather.jsp' )

def normalize(s):
    """<td> tag와  를 제거한 문자열을 돌려준다.
    
        s - 입력 문자열
    """
    return s.replace('<td>', '').replace('</td>', '').replace(' ', '')

def printUsing():
    """사용 방법을 출력한다"""
    print sys.argv[0], '<output file name>'
    
def getDateTime(buffers):
    """ html 내용을 해석해서 데아타가 생성된 날짜를 얻는다. 날짜 형식은 yyyy.mm.dd.HH:SS 이다.
    
        buffers - html 파일 내용
    """
    return buffers.split('<p class="table_topinfo">')[1].split('</p>')[0].split('/>')[-1]

    
def getDatablocks(buffers):
    """html 내용을 해석해서 도시별로 묶은 list를 돌려준다
    
        buffers - html 파일 내용
    """
    # <table class="table_develop 앞부분을 잘라낸다.
    a = buffers.split('<table class="table_develop"')[1]
    # 맨 처음 만나는 </table>을 기준으로 뒤를 잘라낸다.
    b = a.split('</table>')[0]
    # </thread>를 기준으로 앞을 잘라낸다.
    c = b.split('</thead>')[1].replace('<tr>', '')
    # 빈 줄 제거
    r = ''
    for line in c.split('\n') :
        line = line.decode('cp949').encode('utf-8')
        line = line.strip()
        if len(line) > 0 :
            r = r + line + '\n'
    # </tr> 기준으로 잘라내면 데이타 block이 완성된다.
    return r.split('</tr>\n')[:-1] # 마지막 block은 버린다.

def writeXMLheader(out):
    """XML header를 기록한다."""
    out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    out.write('<xml>\n')
    out.write('  <current_weather>\n')
    
def writeXMLfooter(out):
    """XML footer를 기록한다."""
    out.write('  </current_weather>')
    out.write('</xml>')
    
def writeXMLnode(out, datablock):
    data = datablock.split('\n') # 0번째 <tr>부분은 버린다.
    # 0 - 이름
    city = data[0].split('</a>')[0].split('>')[2]
    out.write("""    <city name="%s">
      <!-- 날씨 -->
      <weather>
        <!-- 현재일기 -->
        <now data="%s" />
        <!-- 시정(km) -->
        <visibility data="%s" />
        <!-- 운량 (1/10) -->
        <clouds data="%s" />
        <!-- 중하운량 -->
        <ml_clouds data="%s" />
      </weather>
      <!-- 기온 -->
      <temperature>
        <!-- 현재 기온 -->
        <now data="%s" />
        <!-- 이슬점온도 -->
        <dew_point_c data="%s" />
        <!-- 체감 온도 -->
        <wind_chill_c data="%s" />
      </temperature>
      <!-- 강수 -->
      <precipitation>
        <!-- 일강수(mm) -->
        <now data="%s" />
        <!-- 적설 (cm) -->
        <snow_cover data="%s" />
        <!-- 습도 (%%) -->
        <humidity data="%s" />
      </precipitation>
      <!-- 바람 -->
      <wind>
        <!-- 풍향 -->
        <direction data="%s" />
        <!-- 풍속(m/sec) -->
        <speed data="%s" />
      </wind>
      <!-- 기압 (hPa) -->
      <atmospheric_pressure>
        <!-- 해면 기압 -->
        <see_level data="%s" />
      </atmospheric_pressure>
    </city>
""" % (city,
    normalize(data[1]),
    normalize(data[2]),
    normalize(data[3]),
    normalize(data[4]),
    normalize(data[5]),
    normalize(data[6]),
    normalize(data[7]),
    normalize(data[8]),
    normalize(data[9]),
    normalize(data[10]),
    normalize(data[11]),
    normalize(data[12]),
    normalize(data[13]) ) )

def build(outputname) :
    """ 기상청 사이트에서 현재 날씨 정보를 읽어와서 xml로 저장한다.

        outputname - 저장할 파일 이름
    """
    out = file(outputname, 'wt')
    writeXMLheader(out)
    out.write('    <datetime data="%s" />\n' % getDateTime(getMainPage()))

    for datablock in getDatablocks(getDataPage()) :
        writeXMLnode(out, datablock)
    writeXMLfooter(out)

if __name__ == '__main__' :
    if len(sys.argv) <> 2 :
        printUsing()
        sys.exit(1)
    build(sys.argv[1])

2010년 2월 28일

Opera/다음 TV 팟 화면 정리하기

맥북에서 다음 TV 팟을 보려고 하면 미묘한 화면 길이 때문에 약간의 스크롤을 필요로 한다. 또한 덧글의 수준이 매우 낮은데 기본으로 덧글을 표시해서 귀찮다.

내가 보기 싫은 element를 숨기도록 user script를 작성했다.

// ==UserScript==
// @name tvpot.user.js
// @author	Yun-yong, Choi
// @version	0.1
// @include	http://tvpot.daum.net/*
// @compatible   Opera 9
// @description  Macbook 에서 TV pot을 볼때 페이지 길이를 줄이기 위해서 상단의 일부 메뉴와 덧글을 숨기는 script.
// ==/UserScript==
(function  () {
	function getElementsByClass( searchClass, domNode, tagName) {
		if (domNode == null) domNode = document;
		if (tagName == null) tagName = '*';
		var el = new Array();
		var tags = domNode.getElementsByTagName(tagName);
		var tcl = " "+searchClass+" ";
		for(i=0,j=0; i<tags.length; i++) {
			var test = " " + tags[i].className + " ";
			if (test.indexOf(tcl) != -1) el[j++] = tags[i];
		}
		return el;
	}
	function hideClass(className) {
		var els = getElementsByClass(className);
		for (var i=0; i < els.length; i++) els[i].style.display = "none";
	}
	function hideId(id) {
		var els = document.getElementById(id);
		if (els) els.style.display = "none";
	}

	///// 화면 상단
	// 최상위 메뉴 숨김
	hideId("DaumUI__minidaum");
	// TV Pot 로고 제거
	hideId("gnbLogoNav");
	// TV pot 메뉴 제거
	//hideId("gnbTabNavNew");
	// title, 브랜드팟 이동 메뉴 모두 제거
	hideClass("brandPotHeadWrap");
	// title 스킨 제거
		//hideClass("header");
	// 브랜드 팟 이동 메뉴 제거
		//hideClass("brandPotNav");
	///// 화면 하단
	// 통계 제거
	hideId("statisticsArea");
	// 추천 메뉴 제거
	hideClass("etcClipInfor");
	// 마이팟 담기, 통계 메뉴 제거
	hideClass("clipEtcFucntion");
	// 댓글 제거
	hideClass("commentArea");
	// 브랫드 팟 랭킹 목록 제거
	hideClass("brandPotRankingList");

	// 동영상을 화면 상단에 표시하기 위해서 화면을 scroll
	// @todo 계산을 해서 scroll 하도록 수정해야 한다.
	scrollTo(0, 100);
})();

2010년 1월 12일

Python/사진 파일의 시간을 사진을 찍은 시간으로 변경하기

사진 파일(jpg)의 시간을 사진을 찍은 시간으로 변경하는 python script. EXIF.py를 사용한다.

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""jpg 파일 변경 시간을 exif 에서 읽어온 시간으로 변경한다."""
__version__ = '0.1'

import os
import sys
import time
import dircache

import EXIF

# 허가할 확장자 목록
EXTENSIONS = ('.jpg', '.jpeg')

# 사진을 찍은 시간을 얻을 필드. 처음 발견하는 필드를 사용한다.
TAGS = ['Image DateTime', 'EXIF DateTimeOriginal', 'DateTime']


def printUsing():
    """사용 방법을 출력한다.
    """
    print sys.argv[0], '<file or directory>'


def EXIFDateTime2time(exifdatetime):
    """exif의 시간 문자열을 time 값으로 변경한다.

        @param[in]  exifdatetime    시간 문자열

        @return     변환된 time 값
    """
    return time.mktime(time.strptime(exifdatetime, '%Y:%m:%d %H:%M:%S'))


def correctJPGTime(filename):
    """jpg 파일 변경 시간을 수정한다.

        @param[in]  filename    수정할 파일 이름
    """
    fnl = filename.lower()
    for ext in EXTENSIONS:
        # 파일 확장자 검사
        if fnl.endswith(ext):
            f = file(filename, 'rb')
            # exif tag를 읽는다.
            tags = EXIF.process_file(f, details=False)
            for key in TAGS:
                if key in tags:
                    # TAGS 중 처음 발견한 tag의 시간 값을 사용한다.
                    exif_time = EXIFDateTime2time(str(tags[key]))
                    statinfo = os.stat(filename)
                    if exif_time != statinfo.st_mtime:
                        # 시간이 다르면 파일 시간을 변경한다.
                        os.utime(filename, (statinfo.st_atime, exif_time))
                        print 'fix:', filename
                    break
            break


def main():
    if os.path.isdir(sys.argv[1]):
        # 주어진 인자가 디렉토리면
        for name in dircache.listdir(sys.argv[1]):
            # 디렉토리의 파일들에 대해서 수정 작업을 한다.
            # sub directory에 대해서는 아무 작업도 하지 않는다.
            fullname = sys.argv[1] + os.path.sep + name
            if os.path.isfile(fullname):
                correctJPGTime(fullname)
    elif os.path.isfile(sys.argv[1]):
        # 주어진 인자가 파일이면
        correctJPGTime(sys.argv[1])


if __name__ == '__main__':
    if len(sys.argv) < 2:
        printUsing()
        sys.exit(1)
    main()

2010년 1월 2일

GCC/target platform이 64bit 인지 확인하는 방법

gcc에서 target platform이 64bit 환경인지 확인하기 위해서 아래 매크로들이 정의되었는지 확인하면 된다3.2이상에서 확인할 수 있다검사할 64bit 가 LP64만 존재할 경우 gcc 3.4이상에서는 __LP64__매크로 정의 여부만 확인해도 된다..

__alpha__
__ia64__
__ppc64__
__s390x__
__x86_64__

예제 코드는 아래와 같다

#include <stdio.h>

int main(int argc, char **argv)
{
#if defined(__alpha__) || defined(__ia64__) || defined(__ppc64__) || defined(__s390x__) || defined(__x86_64__)
	printf("64\n");
#else
	printf("32\n");
#endif
}

2009년 12월 1일

Python/자동 링크 생성

input에서 http 또는 https 링크를 찾아서 a tag를 붙여주는 python script

import re

re_href= re.compile('(\b(http|https)://([-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]))')
output = re_href.sub(r'<a href="\1" target="_self">\1</a>', input)

2009년 7월 10일

Opera/한글 키워드 사이트 검색을 구글로 넘기기

DNS 검색이 한글 키워드 검색 사이트(넷피아 등) 페이지로 넘어가면 그것을 구글 검색 페이지로 이동시키는 UserScript. 반드시 UTF-8 로 저장하고 사용해야 한다.

// ==UserScript==
// @name URL redirect from hangul keyword search site to google.com
// @author Yun-yong Choi
// @version 0.1
// @include             http://find.netpia.com/*
// @include             http://netpia.*.com/*
// @include				http://dns.paran.com/*
// @compatible			Opera 9
// ==/UserScript==
(function () {
      var newurl = 'http://www.google.co.kr/'
      // netpia 한글 키워드
      // url 에서 q=XXXX 의 XXXX 부분을 추출해서 구글에 넘긴다.
      matchObj = window.location.href.match(/q=(.+)&/)
      if (matchObj && (matchObj.length > 1)) {
        newurl = 'http://www.google.co.kr/search?complete=1&hl=ko&q=' + matchObj[1]
      }
      else {
        // 메가패스 한글 키워드
        // url에서 Query=XXXX 의 XXXX 부분을 추출해서 구글에 넘긴다.
        matchObj = window.location.href.match(/Query=(.+)&/)
        if (matchObj && (matchObj.length > 1)) {
          newurl = 'http://www.google.co.kr/search?complete=1&hl=ko&q=' + matchObj[1]
        }
      }
      window.location = newurl
})();

Opera/다음뷰바 제거 스크립트

다음 뷰바를 제거하는 UserScript. 반드시 UTF-8 로 저장하고 사용해야 한다.

// ==UserScript==
// @name remove_daumviewbar.user.js
// @author	Yun-yong, Choi
// @version	0.1
// @namespace	http://*.daum.net/*
// @compatible   Greasemonkey, Opera 8/9
// ==/UserScript==

if (/(?:^|\.)daum\.net/i.test(window.location.hostname)) document.addEventListener('load', function() {
	var iframe = document.getElementById("viewIframe");
	if (iframe)
	{
		window.location = iframe.src;
	}
}, false);

2009년 6월 11일

Python/피보나치 수열 구하기

12345678999(123억...)과 99987654321(999억...) 사이의 피보나치 수를 모두 더하면 얼마인가 에 대한 풀이를 해보았다. (원문 )

수의 범위가 매우 크기 때문에 루프 대신 generator를 사용했다. (루프로 코드를 짜보았지만 Quad Core에서도 오랜 시간 계산이 끝나지 않아서 포기했다)

import cProfile
import itertools


def Fibonacci_generator():
    """ 피보나치 수를 구하는 generator """
    yield 0
    yield 1
    prev1 = 0  # n-2
    prev2 = 1  # n-1
    result = 0
    while True:
        try:
            result = prev1 + prev2
            yield result
            prev1 = prev2
            prev2 = result
        except OverflowError:
            break


def solve(start, end):
    """ star ~ end 사이의 피보나치 수의 합을 구하는 함수."""
    total = 0L
    for fib in Fibonacci_generator():
        if fib >= end:
            break
        if fib > start:
            total += fib
    return total


def solve2(start, end):
    """ star ~ end 사이의 피보나치 수의 합을 구하는 함수."""
    return sum(itertools.takewhile(
        lambda fib: fib < end,
        itertools.dropwhile(lambda fib: fib > start,
                            Fibonacci_generator())))

start = 12345678999L
end = 99987654321L
cProfile.run('solve(%d, %d)' % (start, end))
print solve(start, end)
cProfile.run('solve2(%d, %d)' % (start, end))
print solve2(start, end)

결과는 아래와 같다.

$python fibo.py
         60 function calls in 0.000 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 fibonachi.py:25(solve)
       57    0.000    0.000    0.000    0.000 fibonachi.py:9(Fibonacci_generator)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


205486422643
         118 function calls in 0.000 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 fibonachi.py:35(solve2)
        6    0.000    0.000    0.000    0.000 fibonachi.py:37(<lambda>)
       51    0.000    0.000    0.000    0.000 fibonachi.py:38(<lambda>)
       57    0.000    0.000    0.000    0.000 fibonachi.py:9(Fibonacci_generator)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {sum}


205486422643

2009년 5월 19일

Python/py2exe를 이용해서 win32 binary를 만들때 manifest 추가

Windows 환경에서 py2exe 를 이용해서 exe를 만들때 manifest 를 추가할 수 있다.

setup.py를 아래와 같이 만든다.

manifest = """
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <asmv3:trustInfo xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <asmv3:security>
      <asmv3:requestedPrivileges>
        <asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </asmv3:requestedPrivileges>
    </asmv3:security>
  </asmv3:trustInfo>
</assembly>
"""

setup(name='MyApp',
    #...
    windows=[ { #...
        'other_resources':[(24, 1, manifest)],
    }]
)

2009년 5월 12일

Python/PyGTK

PyGTK 예제 소스를 순수 API를 호출하는 방법과 GtkBuilder를 사용한 방법으로 각각 구현해본다.

Hello, World

아래와 같은 모습을 가지도록 프로그램을 수정한다.

API 호출

코드

hello.py


#!/usr/bin/python
# -*- coding: utf-8 -*-
import gtk

class HelloWorld :
    def hello(self, widget, data=None) :
        print 'Hello, World'

    def delete_event(self, widget, event, data=None):
        print 'delete event occurred'
        return False

    def destroy(self, widget, data=None) :
        gtk.main_quit()

    def __init__(self) :
        self._win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self._win.connect('delete_event', self.delete_event)
        self._win.connect('destroy', self.destroy)
        self._win.set_border_width(10)
        self._btnhello = gtk.Button('Hello World')
        self._btnhello.connect('clicked', self.hello, None)
        self._btnhello.connect_object('clicked', gtk.Widget.destroy, self._win)
        self._win.add(self._btnhello)

    def main(self) :
        self._win.show_all()
        gtk.main()

def main() :
    w = HelloWorld()
    w.main()

if __name__ == '__main__' :
    main()

GtkBuilder

GtkBuilder를 사용하면 ui 구성 코드를 xml로 분리할 수 있다.

코드

hello.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<interface>
  <object class="GtkWindow" id="HelloWindow">
    <property name="border_width">10</property>
    <signal name="delete_event" handler="delete_event" />
    <signal name="destroy" handler="destroy" />
    <child>
      <object class="GtkButton" id="BtnHello">
        <property name="label">Hello, world</property>
        <signal name="clicked" handler="hello" />
      </object>
    </child>
  </object>
</interface>

hello2.py

>#!/usr/bin/python # -*- coding: utf-8 -*- import gtk class HelloWorld : def hello(self, widget, data=None) : print 'Hello, World' def delete_event(self, widget, event, data=None): print 'delete event occurred' return False def destroy(self, widget, data=None) : gtk.main_quit() def __init__(self) : builder = gtk.Builder() builder.add_from_file('hello2.xml') builder.connect_signals(self) self._win = builder.get_object('HelloWindow') self._btnhello = builder.get_object('BtnHello') self._btnhello.connect_object('clicked', gtk.Widget.destroy, self._win) def main(self) : self._win.show_all() gtk.main() def main() : w = HelloWorld() w.main() if __name__ == '__main__' : main()

Hello, World 업그레이드

아래와 같은 모습을 가지도록 프로그램을 수정한다.

API 호출

코드

hello_upgrade.py

>#!/usr/bin/python # -*- coding: utf-8 -*- import gtk class HelloWorld2 : def callback(self, widget, data) : print 'Hello again - %s was pressed ' % data def delete_event(self, widget, event, data=None): gtk.main_quit() return False def __init__(self) : self._win = gtk.Window(gtk.WINDOW_TOPLEVEL) self._win.set_title('Hello Buttons!') self._win.connect('delete_event', self.delete_event) self._win.set_border_width(10) self._box1 = gtk.HBox(False, 0) self._win.add(self._box1) self._button1 = gtk.Button('Button 1') self._button1.connect('clicked', self.callback, 'button 1') self._box1.pack_start(self._button1, True, True, 0) self._button2 = gtk.Button('Button 2') self._button2.connect('clicked', self.callback, 'button 2') self._box1.pack_start(self._button2, True, True, 0) def main(self) : self._win.show_all() gtk.main() def main() : w = HelloWorld2() w.main() if __name__ == '__main__' : main()

GtkBuilder

코드

hello2_upgrade.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<interface>
  <object class="GtkWindow" id="HelloWindow">
    <property name="title">Hello Buttons!</property>
    <property name="border_width">10</property>
    <signal name="delete_event" handler="delete_event" />
    <child>
      <object class="GtkHBox" id="box1">
        <child>
          <object class="GtkButton" id="button1">
            <property name="label">Button 1</property>
            <signal name="clicked" handler="callback" />
          </object>
        </child>
        <child>
          <object class="GtkButton" id="button2">
            <property name="label">Button 2</property>
            <signal name="clicked" handler="callback" />
          </object>
        </child>
      </object>
    </child>
  </object>
</interface>

hello2_upgrade.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import gtk

class HelloWorld2 :
    def callback(self, widget, data = None) :
        print 'Hello again - %s was pressed ' % widget.get_name()

    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False

    def __init__(self) :
        builder = gtk.Builder()
        builder.add_from_file('hello2_upgrade.xml')
        builder.connect_signals(self)
        self._win = builder.get_object('HelloWindow')

    def main(self) :
        self._win.show_all()
        gtk.main()

def main() :
    w = HelloWorld2()
    w.main()

if __name__ == '__main__' :
    main()

Reference

2009년 5월 8일

Urlencode된 파일 이름을 Decode하기

Opera에서 파일을 받으면 한글이름일 경우 urlencode 된 이름으로 저장된다. decode 하는 간단한 스크립트를 작성했다

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import sys
import urllib


def printUsing():
    """사용 방법을 출력한다."""
    print 'fixname.py  [  ...]'


def getUnquoteFileName(name):
    try:
        return unicode(urllib.unquote(name).decode('utf-8'))
    except UnicodeDecodeError:
        return unicode(urllib.unquote(name).decode('cp949'))


def main():
    for argv in filter(os.path.isfile, sys.argv[1:]):
        decoded_argv = getUnquoteFileName(argv)
        if argv != decoded_argv:
            print '%s -> %s' % (argv, decoded_argv)
            os.rename(argv, decoded_argv)

if __name__ == '__main__':
    if len(sys.argv) < 2:
        printUsing()
    else:
        main()

2008년 9월 20일

Win32/프로세스 실행 방법에 따른 argument 해석

프로세스 실행 방법에 따라서 argument 해석이 어떻게 달라지는지 간단한 테스트를 수행했다.

테스트

프로세스를 실행시킬 수 있는 API중 ShellExecuteEx()와 CreateProcess() 에 대해서 테스트를 수행한다. 실행시 인자는 "12345"를 사용한다.

ShellExecuteEx

입력

인자
SHELLEXECUTEINFO::lpFileC:\Test\MyTest.exe
SHELLEXECUTEINFO::lpParameters12345

결과

argument를 얻는 방법결과
CWinApp::m_lpCmdLine12345
GetCommandLineW()"C:\Test\MyTest.exe" 12345
argc2
argv[0]C:\Test\MyTest.exe
argv[1]12345

CreateProcess 1

입력

lpApplicationNameNULL
lpCommandLine"C:\Test\MyTest.exe" 12345

결과

argument를 얻는 방법결과
CWinApp::m_lpCmdLine12345
GetCommandLineW()"C:\Test\MyTest.exe" 12345
argc2
argv[0]C:\Test\MyTest.exe
argv[1]12345

CreateProcess 2

입력

lpApplicationNameC:\Test\MyTest.exe
lpCommandLine"C:\Test\MyTest.exe" 12345

결과

argument를 얻는 방법결과
CWinApp::m_lpCmdLine12345
GetCommandLineW()"C:\Test\MyTest.exe" 12345
argc2
argv[0]C:\Test\MyTest.exe
argv[1]12345

CrateProcess 3

입력

lpApplicationNameC:\Test\MyTest.exe
lpCommandLine12345

결과

argument를 얻는 방법결과
CWinApp::m_lpCmdLine
GetCommandLineW()12345
argc1
argv[0]12345

결론

  1. 프로세스를 실행할때는 가급적 ShellExecuteEx() API를 사용한다.
  2. CreateProcess() API를 사용할 때는 lpCommandLine 인자에 전체 명령행을 완성해서 전달한다.

2007년 11월 18일

To create a notification thread and then return

int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {

    // Create our events for event logging notification as well as our event for ending the notification thread
    g_evtNewEventLogRecord = CreateEvent(NULL, TRUE, FALSE, NULL);
    HANDLE hThread = chBEGINTHREADEX(NULL, 0, EventNotifyThread, NULL, 0, NULL);

    DialogBox(hinstExe, MAKEINTRESOURCE(IDD_EVENTMONITOR), NULL, Dlg_Proc);

    // Clean up
    QueueUserAPC(DoNothingAPC, hThread, NULL);
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(g_evtNewEventLogRecord);
    CloseHandle(hThread);
    return(0);
}

///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI EventNotifyThread(PVOID pvParam) {

    // Note that this is not the thread that called NotifyChangeEventLog.
    // The main thread does this in response to the WM_INITDIALOG message.
    // If the main thread were to terminate before this thread, then
    // notifications would cease to function. However, since it will always
    // terminate after this thread, then we can count on the notification event
    // working properly.

    // Wait for an event notification or for APC altering this thread to termiante.
    while (WaitForSingleObjectEx(g_evtNewEventLogRecord, INFINITE, TRUE) != WAIT_IO_COMPLETION) {
        FORWARD_WM_USERNOTIFYUPDATE(g_hwnd, PostMessage);
    }

    // We got an APC, this thread should terminate
    return(0);
}