Tcl/Tk 문법 - 2부 Tk
Development 2008. 6. 9. 09:391999/07/16
1장 소개
1) X Window System과 Tk의 소개
X 윈도우 시스템은 MIT와 DEC가 공동으로 개발한, 하드웨어와 OS에 독립적인 윈도우 시스템이다. 하드웨어와 OS에 독립적일 수 있는 이유는, X 클라이언트와 X 서버로 각각의 기능이 분리되어 있기 때문이다. X 서버는 장치구동기(device driver)를 통해 하드웨어와 OS를 제어하고, X 클라이언트는 X 프로토콜을 이용해 X 서버에게 윈도우 작업을 요청하게 되는 것이다. X 프로토콜은 사람이 이해하기 어렵기 때문에, Xlib을 이용하여 C로 X 윈도우 프로그래밍을 할 수 있도록 지원하고 있다.
그러나 Xlib조차 프로그래밍하기가 쉽지 않다. 아주 간단한 윈도우를 하나 만드려고 해도 프로그래머가 지정해야 할 것들이 너무 많기 때문이다. 그래서 이미 Xlib 수준에서 구현된 위짓(widget)을 재사용하게 된다. 이것을 바로 툴킷(Toolkit)이라고 한다. 툴킷에도 여러 단계가 있어서 가장 하위 레벨은 X Toolkit Intrinsics이다. 이것은 여러 X 응용프로그램에서 자주 사용되는, 아주 핵심적인 위짓을 미리 만들어놓은-정의해놓은-라이브러리라고 할 수 있다. Xt라고 불리우는 X Toolkit Intrinsics 이외에, 좀 더 세련된 위짓들의 집합을 제공하는 것으로는 Motif와 Qt, Gtk 등이 있다.
Tk는 일반적인 뜻으로는 툴킷(Toolkit)을 의미한다. 그러나 여기서 말하는 Tcl/Tk는 Tcl에서 사용하는 툴킷으로 그 의미가 한정된다. 우리가 이제부터 살펴볼 것은 Tcl에서 윈도우를 어떻게 생성하고 다룰 것인가에 관한 것이다. Tk를 중심으로 Tcl/Tk를 익혀보기 위해서는 wish(windowing shell)가 필요하다. 1부에서 밝힌대로 Tcl/Tk를 설치했다면 wish가 존재할 것이다. /usr/X11R6/bin이나 /usr/openwin/bin 등의 X 응용프로그램 디렉토리에서 찾아서 실행해보자. 제대로 설치가 되어 있다면 다음 명령을 수행했을 때, 버튼 위에 쓰여진 환영 인사를 만날 수 있을 것이다.
button .b -text "Hello, world!"
pack .b
pack은 사용자가 만든 위짓 인스턴스를 화면에 디스플레이하는 명령이다.
2) X resource
X 윈도우 시스템에서 폰트나 색상, 사이즈와 같이 위짓의 속성을 바꿀 수 있는 변수들을 X resource라고 한다. 리소스(resource)는 X 클라이언트가 요청하면 X 서버가 할당해주는 형태로 되어 있다. X 윈도우 시스템에는 여러가지 위짓이 존재하고, 각각의 위짓은 또 다양한 리소스를 필요로 하게 되므로 상당히 많은 종류의 리소스가 존재한다. 그러나 여기서는 Tcl/Tk에서 중요하게 다루는 몇 가지 리소스에 대해 짧게 살펴보고 지나갈 것이다. X 윈도우 프로그래밍에 관심있는 독자라면 Xlib 프로그래밍이나 X 툴킷 프로그래밍에 관련된 책을 읽어보는 것이 좋겠다.
우선 가장 많이 사용되는 것은 색상이다. 아주 간단한 RGB방식으로 빨간색, 파란색, 녹색을 1 바이트(0에서 255까지)씩 빛을 혼합하는 것이다. 예를 들면 흰색은 #ffffff이고, 검정색은 #000000이다. 빨간색은 #ff0000이고, 녹색은 #0000ff이다. 보라색은 #ffff00이 되겠다. 그러나 프로그래머가 매번 광원의 색을 혼합하여 색상을 만들어내는 것은 번거로운 일이 될 것이다. X 윈도우 시스템에서는 showrgb라는 명령으로 이미 지정되어 있는 색상의 이름을 확인할 수 있다. k에서는 이렇게 정의되어 있는 색상의 이름을 그대로 사용할 수 있다.
다음으로 많이 사용하는 리소스는 폰트이다. 폰트는 XLFD(X Logical Font Description)을 따라서 그 이름을 지정하면 되는데, 복잡한 설명보다는 xlsfonts를 이용하여 폰트 리스트에서 마음에 드는 폰트명을 골라서 사용하면 된다. 그러나 폰트명만 가지고는 폰트의 생김새를 알 수 없으므로, xfontsel이라는 프로그램으로 각각의 폰트가 어떻게 생겼는지 확인하는 것이 좋겠다. 어떻게 사용하는지는 차차 살펴보기로 하자.
2장 Tk Widget
Tk 위짓은 Motif의 스타일을 제공하는 위짓이다. 각각의 위짓은 클래스(class)와 인스턴스(instance)로 그 개념을 나누어 볼 수 있다. 클래스는 특정 위짓의 종류를 지칭하고, 인스턴스는 그 위짓 클래스에 속하는 위짓을 하나 만들어 이름을 붙여준 것을 가리킨다. 위짓 인스턴스는 계층을 이루어서 하나의 윈도우를 구성하게 된다. Xterm을 예로 보면, Xterm은 왼쪽이나 오른쪽에 스크롤바(scrollbar)를 가지고 있고, 나머지 부분에 텍스트입력창이 존재한다. 이런 경우에는 최상위의 윈도우 아래에 스크롤바와 텍스트입력창이 존재하는 계층구조라고 할 수 있을 것이다. 메뉴(menu)를 가지고 있는 X 응용프로그램이라면 메뉴 안에 메뉴 아이템이 존재하고, 그 아이템이 다시 메시지창을 가진다든가 해서 아주 복잡한 계층구조를 형성할 것이다.
Tk에서 제공하는 위짓에는 프레임(frame), 레이블(label), 버튼(button), 체크버튼(checkbutton), 라디오버튼(radiobutton), 메시지(message), 리스트박스(listbox), 스크롤바(scrollbar), 스케일(scale), 엔트리(entry), 메뉴(menu), 메뉴버튼(menubutton) 등이 있다.
특별한 위짓으로는 top-level 위짓이 있는데, 이것은 “.”(dot)으로 표현된다. “.”을 쓰면 최상위의 위짓이고, “.a”라 하면 top-level 위짓 바로 아래 레벨에 위치하는 위짓 인스턴스 a가 되는 것이다.
1) 프레임(frame)
프레임은 위짓을 그룹으로 묶을 때 사용하는 위짓이다. 나중에 살펴 볼 pack 명령만으로는 위짓들을 관리하기가 어려워서 프레임을 이용하여 위짓을 그룹단위로 사용하게 된다. 프레임은 -relief 옵션을 주어 5가지의 형태로 만들 수 있는데, 다음의 예는 각각의 형태를 한 윈도우에 모아서 보여주는 것이다.
foreach re { raised sunken flat groove ridge } {
frame .$re -width 15m -height 10m -relief $re -bg gray40 -borderwidth 4
pack .$re -side left -padx 2m -pady 2m
}
[그림 1]
2) 버튼(button)
버튼은 마우스 버튼을 누르면 움푹하게 들어가고, 손가락을 떼면 다시 올라오는 위짓이다. 가장 흔히 만날 수 있는 위짓이 바로 버튼이다. 버튼도 프레임과 마찬가지로 -relief 옵션을 이용하여 5가지의 형태로 만들 수 있다.
다음은 버튼 2개를 하나의 프레임 안에 넣는 예이다. “.f.b1″ 또는 “.f.b2″는 f라는 프레임 인스턴스 아래에 두 개의 버튼 인스턴스가 존재한다는 의미이다. 물론 위에서 설명한 바와 같이, 프레임 f는 top-level 위짓 바로 아래 레벨에 위치하는 프레엠 위짓 클래스의 f라는 이름을 가진 인스턴스가 되는 것이다.
frame .f
button .f.b1 -text button1
button .f.b2 -text button2
pack .f.b1 .f.b2
아무 것도 나오지 않는다. 이상할 것은 없다. 바로 프레임 f를 pack하지 않았기 때문이다. pack에 대해서는 뒤에서 자세히 다루어 보도록 한다. 다음 명령을 추가하면 버튼 2개가 나타날 것이다.
pack .f
3) 체크버튼(checkbutton)과 라디오버튼(radiobutton), 리스트박스(listbox)
체크버튼은 여러 개의 버튼을 눌러서 동시에 여러가지를 선택할 수 있게 하는 버튼이다. 반면에 라디오버튼은 라디오에서 채널을 맞추듯 한 번에 단 하나만을 선택할 수 있게 하는 버튼이다. 체크버튼과 라디오버튼은 그 버튼이 체크되는 순간에 특정 변수에 특정 값을 대입할 수 있도록 -variable, -value 옵션을 제공한다.(-value 옵션은 라디오버튼에서만 사용된다.) 리스트박스는 체크버튼을 확장해 놓은 것으로 생각할 수 있는 위짓으로 하나 이상의 아이템을 선택할 수 있다.
checkbutton .red -text Red -variable color_red
checkbutton .green -text Green -variable color_green
checkbutton .blue -text Blue -variable color_blue
pack .red .green .blue -side top -fill x
radiobutton .red -text Red -variable color -value red
radiobutton .green -text Green -variable color -value green
radiobutton .blue -text Blue -variable color -value blue
pack .red .green .blue -side top -fill x<
[그림 2]
[그림 3]
위의 두 예제는 체크버튼과 라디오버튼이 어떻게 다른가를 알려주는 예이다. 체크버튼의 경우에, 몇 개를 선택하고서 puts $color_red $color_green $color_blue를 실행하여 각각의 값을 확인해 보자. 체크되어 있는 색상의 변수에는 이, 아닌 경우에는 0이 대입되어 있는 것을 알 수 있다. 라디오버튼의 예제는 색상을 선택한 후에, puts $color 해 보면 값이 설정되어 있는 것을 확인할 수 있다.
listbox .name -selectmode browse
pack .name
set f [open /etc/passwd]
while {[gets $f line] >= 0} {
set item [lindex [split $line :] 0]
.name insert end “$item”
}
close $f
[그림 4]
이 예제를 -selectmode 옵션의 값을 single, multiple, extended로 바꾸어가며 테스트해보자. 그러면 마우스의 바인딩(binding)이 어떻게 바뀌는지 알 수 있다. 예를 들면, extended로 바꾸어 놓고 실행하면 마우스의 첫번째 버튼을 누른 채로 드래그할 때 해당 아이템들 모두를 선택할 수 있다.
4) 메시지(message)
메시지는 길이가 긴 텍스트를 보여주는 메시지 창을 의미한다. 다음의 예는 오른쪽 정렬로 텍스트를 보여준다. 폰트를 지정하고, 배경색과 전경색을 지정하는 방법을 눈여겨 보아두자.
message .m -justify right -font "-*-helvetica-*-*-*--*-120-*" -bg white -fg black -text "Message widgets are similar to labels except that they display multiline strings."
pack .m
[그림 5]
5) 스크롤바(scrollbar) & 스케일(scale)
스크롤바는 대개 수직으로 세워져 있는 위짓인 반면에, 스케일은 수평으로 눕혀져 있는 위짓이다. 물론 각각의 위짓은 옵션을 이용하여 그 모양을 반대로 바꿀 수 있다. 스크롤바는 많은 아이템을 검색할 때 사용되고, 스케일은 슬라이더(slider)를 이용하여 정수값을 변화시킬 때 사용된다.
listbox .li -yscrollcommand ".sc set"
scrollbar .sc -command ".li yview"
pack .li -side left
pack .sc -side right -fill y
foreach it [lsort [glob *]] {
.li insert end $it
}
[그림 6]
스크롤바를 상하로 움직이면 리스트박스 인스턴스인 .li에 yview명령을 수행하게 되어 리스트박스가 상하로 움직이게 되는 것이다.
scale .percent -from 0 -to 100 -orient horizontal -command showvalue
pack .percent
proc showvalue parameter {
puts [.percent get]
}
[그림 7]
이 예는 슬라이더를 움직이면 그 해당 정수값을 출력하는 것이다. horizontal을 vertical로 바꾸면 슬라이더가 수직으로 나타날 것이다. 스케일에 -command 옵션으로 값에 변화가 있을 때마다 프러시져를 호출할 수 있다. 잘 살펴보면 프러시져 안에서 스케일의 현재 값을 얻기 위해 .percent get하고 있음을 알 수 있다.
6) 엔트리(entry)
엔트리는 텍스트 입력창이다. 엔트리에 텍스트를 입력한 후에 puts $var로 변수의 값을 확인해보자.
entry .e -relief groove -textvariable var
pack .e
7) 메뉴(menu)와 메뉴버튼(menubutton)
메뉴에는 체크버튼, 라디오버튼, 메뉴버튼, 명령(command), 구분선(separator) 등을 아이템으로 가질 수 있다. 체크버튼과 라디오버튼은 위에서 설명한 바와 같은 방식으로 작동하고, 명령은 프러시져를 호출하기 위해 사용하며, 구분선은 아이템을 시각적으로 그룹화하기 위해 사용된다.
menubutton .mb -text "Menu" -menu .mb.m
pack .mb
menu .mb.m
.mb.m add radiobutton -label Red -variable red
.mb.m add radiobutton -label Blue -variable blue
.mb.m add separator
.mb.m add command -label "Hello" -command hello
proc hello {} {
puts "Hello, world!"
}
다만 메뉴 자체는 pack 명령을 사용하지 않는다. 메뉴가 속해있는 다른 위짓이 그 작업을 대신 수행해준다. 여기서는 메뉴버튼을 pack해서 화면에 디스플레이하고, menu인 .m을 연결시킨다.
메뉴의 한 항목이 다시 메뉴를 부르는 것을 캐스케이딩 메뉴(cascading menu)라고 하는데, 이것은 add하는 항목에 cascade라고 쓰고 -menu option을 이용하여 새로운 메뉴를 연결시키면 가능하다.
.mb.m add cascade -labe "Another menu" -menu .mb.cm
menu .mb.cm
.mb.cm add radiobutton -label Green -variable green
메뉴바를 만들고 거기서 다시 서브메뉴를 만드는 경우가 있는데, 이런 경우에는 우선 메뉴바를 하나 만들고, 메뉴바에 메뉴버튼을 몇 개 붙인 후, 각각의 버튼에 메뉴를 연결하는 것이다. 메뉴바는 메뉴버튼을 그룹으로 만드는 것이므로 프레임으로 선언한다.
frame .menubar -relief raised
menubutton .menubar.file -text File -menu .menubar.file.menu
menubutton .menubar.edit -text Edit -menu .menubar.edit.menu
pack .menubar -fill x -expand true
pack .menubar.file .menubar.edit -side left
menu .menubar.file.menu
.menubar.file.menu add command -label “Open”
.menubar.file.menu add command -label “Save”
.menubar.file.menu add command -label “Exit”
File과 Edit 메뉴인 .menubar.file.menu와 .menubar.edit.menu는 위에서 설명했던 대로 사용자가 만들면 된다. 중요한 것은 메뉴는 pack하지 않고, 메뉴를 연결하는 위짓(여기서는 메뉴바와 메뉴버튼)은 반드시 pack해야 한다는 것이다. 메뉴의 단축키를 지정하거나 특정 문자에 밑줄을 긋기 위해서는 -accelerator와 -underline 옵션을 사용하면 된다.
.menubar.file.menu add command -label "Open" -underline 0 -accelerator "Ctrl+O" -command open
proc open {} {
puts "open"
}
이 예에서 -underline 옵션의 값이 0인데, 이것은 Open이라는 label의 첫글자 O에 밑줄을 긋겠다는 의미이다. 단축키는 Ctrl+O로 지정했지만, 실제로 Ctrl+O를 누른다고 해서 그 항목이 선택되지는 않는다. 단축키와 그 항목을 연결하기 위해서는 bind 명령을 사용해야 한다. 이것은 뒤에서 다루기로 한다.
3장 Pack
pack 명령을 이용하면 위짓들의 위치를 조정할 수 있다. pack 명령에서 사용되는 옵션에는 -after, -anchor, -before, -expand, -fill, -in, -ipadx, -ipady, -padx, -pady, -side 등이 있는데, 가장 일반적으로 쓰는 옵션은 -side라고 할 수 있다. -side 옵션의 값으로 줄 수 있는 것은 left, right, top, bottom이 있다.
button .a -text a
button .b -text b
button .c -text c
세 개의 버튼을 생성한 후에, 다음의 두 명령을 각각 실행하여 위짓들의 배치를 확인해보자.
pack .a .b .c -side left
pack .a .b .c -side top
[그림 8]
[그림 9]
위짓들을 배치하다보면 가끔 상하나 좌우로 조금씩 공간이 생기는데, 이것을 없애주려면 -fill 옵션을 사용하면 된다. -fill 옵션에는 x, y, both로 각각 값을 줄 수 있다.
button .a -text aaaaaaaa
button .b -text b
button .c -text cccc
pack .a .b .c -fill x
-fill 옵션없이 pack 명령을 수행한 것과 결과가 어떻게 다른지 비교해보자. -fill 옵션말고도 빈 공간을 채우는 방법으로 -expand 옵션을 사용하는 것이 있는데, -expand는 모든 위짓이 함께 공간을 채우는 것이 아니라, 특정 위짓에게 남은 공간을 모두 할당해준다. 그러나 -fill 옵션처럼 그 위짓이 빈 공간을 모두 채우는 것이 아니라, 잠재적으로 그 위짓에게 공간을 사용할 권리가 부여된 것이다. -fill 옵션을 함께 사용하여 빈 공간을 채울 수 있다. 다음의 예제를 실행하고 윈도우 크기를 늘여보자.
button .a -text aaaaaaaa
button .b -text b
button .c -text cccc
pack .a .b .c -side left
[그림 10]
오른쪽에 빈 공간이 생긴다. 이제 다음 각각의 pack 명령을 수행하여 -expand 옵션이 어떤 효과를 내는지 살펴보도록 하자.
pack .a .b .c -expand 1
pack .a .b -side left -expand 0
pack .c -expand 1 -fill x
[그림 11]
[그림 12]
[그림 13]
이제 위짓들을 정렬하는 방법에 대해 알아보자. 정렬을 위해서는 -anchor 옵션을 사용할 수 있는데, 옵션의 값으로 center(중앙), n(북), ne(북동), e(동), se(남동), s(남), sw(남서), w(서), nw(북서)의 방향값을 줄 수 있다.
pack .a -anchor nw
명령을 수행한 후, 윈도우의 크기를 늘여서 위짓이 어떻게 정렬되어 있는지 확인해보자.
-padx, -pady 옵션은 위짓과 다른 위짓(또는 윈도우 경계) 사이의 간격을 조정할 때 사용하고, -ipadx, -ipady 옵션은 위짓 내부의 텍스트나 이미지와 위짓 경계와의 내부 간격을 조정할 때 사용하는 옵션이다.
pack .a .b .c -padx 2m -pady 3m -ipadx 2m -ipady 2m
4장 이벤트(event)와 액션(action)
다음 표는 이벤트와 그 이벤트의 의미이다.
Button | 마우스 버튼이 눌러졌음 |
ButtonPress | 마우스 버튼이 눌러졌음 |
ButtonRelease | 마우스 버튼이 눌러졌다가 다시 놓아졌음 |
Key | 키가 눌러졌음 |
KeyPress | 키가 눌러졌음 |
KeyRelease | 키가 눌러졌다가 다시 놓아졌음 |
Enter | 마우스 포인터가 윈도우 안으로 들어왔음 |
Leave | 마우스 포인터가 윈도우 바깥으로 나갔음 |
Motion | 마우스가 윈도우 내에서 움직임 |
Expose | 윈도우가 다시 그려짐 |
Map | 윈도우가 화면에 나타남 |
Unmap | 윈도우가 화면에서 없어짐 |
FocusIn | 키보드 포커스가 윈도우 안으로 들어왔음 |
FocusOut | 키보드 포커스가 윈도우 바깥으로 나갔음 |
Gravity | 윈도우의 gravity가 변화했음 |
Circulate | 윈도우가 쌓여있는 순서가 변했음 |
Configure | 윈도우의 위치가 크기가 변했음 |
Destroy | 윈도우가 제거되었음 |
Property | X 윈도우 속성이 윈도우에 쓰여졌음 |
Visibility | 윈도우의 visibility가 변했음 |
Reparent | 윈도우 매니저에 의해 윈도우의 parent가 바뀌었음 |
Colormap | 윈도우의 컬러맵이 변화했음 |
일반적인 X 윈도우 시스템의 이벤트는 위와 같고, 마우스의 첫번째 버튼이 눌러진다든가 하는 특정한 이벤트는 ButtonPress-1과 같이 지정할 수 있다. 키보드의 경우, Control-1, Shift-M, Alt-V, Mod5와 같이 특정 키를 가리킬 수 있다.
이벤트에 액션을 연결시키는 명령은 bind 명령인데, 이벤트가 발생하는 범위를 지정할 수 있다.
bind all {puts "Entering %W at (%x, %y)"}
all 대신에 위짓의 이름을 쓰면 그 위짓 내부에서만 이벤트와 액션을 연결하는 바인딩(binding)이 효과를 가지게 된다. %W는 이벤트가 발생한 윈도우의 이름이고, %x, %y는 xy좌표이다. %K는 키 이벤트의 이름이고, %A는 키 이벤트를 ASCII코드로 바꾸어 주는 변수이다. 윈도우의 너비와 높이를 알려주는 것으로 %w, %h가 있고, 이벤트 종류를 알려주는 %T를 사용할 수도 있다.
5장 캔버스(canvas) 위짓
캔버스(canvas)는 그림을 그릴 수 있는 위짓이다. 캔버스에 그릴 수 있는 것으로는, line(선), oval(원과 타원), rectangle(사각형), polygon(다각형), arc(원호), text(텍스트), bitmap(비트맵), image(이미지), window 등이 있다.
canvas .can -width 300 -height 200
pack .can
.can create arc 130 40 50 120
이것은 (130, 40)부터 (50, 120)에 걸쳐 원호를 그리는 것이다. -fiil 옵션으로 내부를 특정 색으로 채울 수도 있다.
.can create bitmap 200 20 -bitmap error
.can create image 100 100 -image earth.gif
이 예제들은 비트맵과 일반 이미지를 그리는 것인데, -bitmap이나 -image 옵션의 값은 비트맵 파일의 이름이나 이미지의 이름이다. error의 경우에는 Tk에서 이미 정의된 비트맵인데, 이밖에도 gray25, gray50, hourglass, info, questhead, question, warning 등이 있다.
이미지를 다루기 위해서는 image를 먼저 만드는 과정이 필요하다. image라는 명령을 사용하는 것인데, 다음의 예를 참고하자.
image create photo x -file earth.gif
label .y -image x
pack .y
[그림 14]
x라는 이름으로 earth.gif를 이미지로 만들고, label에다가 얹는다. 버튼 위에도 얹을 수 있다. 그러면 이미지가 있는 버튼을 만들 수 있는 것이다. Tk에서는 GIF와 PPM/PGM 포맷의 image를 사용할 수 있다.
.can create line 100 120 150 130 -arrow first
다시 캔버스로 돌아가서 선을 그려보자. -arrow 옵션의 값으로는 last와 both를 줄 수도 있는데, 화살표모양을 어디에 달 것인가를 결정하는 것이다. 좌표를 더 많이 주고 -smooth 옵션의 값을 1로 주면 베지어 곡선(Bezier curve)을 그릴 수 있다.
.can create line 230 140 150 60 100 110 120 30 -smooth 1
원이나 타원의 경우 oval 오브젝트를 만들면 되는데, 원이나 타원이 들어갈 사각형의 두 대각점을 지정하면 된다. 사각형을 만드는 방법도 마찬가지이다. 다각형의 경우, 좌표를 나열하면 다각형을 그려준다.
.can create polygon 30 50 60 40 20 100 120 180 -fill orange
위짓을 넣기 위해 윈도우를 만들어 본다. 캔버스내에 윈도우의 위치가 정해지므로 위짓을 pack하지는 않는다.
button .can.b -text hello -relief raised
.can create window 100 100 -window .can.b
캔버스에 그림을 다 그렸으면 출력을 해야 하는 경우가 있다. postscipt 명령을 주면 캔버스의 그림을 PS형식의 파일로 저장한다.
.can postscript -colormode color -file result
그러나 필자가 실험해 본 결과로는, 안타깝게도 버튼 위짓이 출력되지 않았다.
[그림 14.5]
6장 텍스트 위짓(text widget)
텍스트 위짓은 텍스트를 보여주기 위한 위짓이다. 다른 위짓도 크기가 커지면 스크롤바를 달아주어야 하는데, 텍스트 위짓은 텍스트의 분량이 많을 것으로 예상을 하고 미리 스크롤바를 달아주는 것이 좋다.
text .t -yscrollcommand ".sc set"
entry .e -textvariable var
scrollbar .sc -command ".t yview"
pack .sc -side right -fill y
pack .t .e -side top -expand 1 -fill x
이제 텍스트 위짓에 파일의 내용을 올리도록 한다. 이것은 리스트박스에서 했던 것과 비슷한 작업이다. 리스트박스의 예제를 참고하도록 하자.
proc print filename {
set f [open $filename]
while {![eof $f]} {
.t insert end [read $f 100]
}
close $f
}
print /etc/passwd
텍스트와 관련하여 텍스트의 일부를 잘라 내어, 복사하고 붙이는 작업을 할 수 있는데, 이렇게 잘라 내거나 복사하려는 텍스트는 클립보드(clipboard)나 selection 메카니즘을 이용하게 된다. selection은 X 응용프로그램간의 텍스트의 저장을 Tcl에서 지원하게 위해 제공되는 것이고, 클립보드는 Tk에서 사용하는 데이터의 저장공간이다. selection은 화면 상에서 사용자에게 보이지만, 클립보드는 보이지 않는다. 위의 예제를 실행하고 마우스로 텍스트를 긁어서 엔트리 위짓에 복사해보자. 텍스트를 선택하게 되면 selection에 자료가 복사되는데, 다음과 같은 명령으로 확인할 수 있다.
selection get
클립보드에 자료를 복사하고 꺼내는 것은 다음과 같다.
clipboard append "Hello, world!"
selection get -selection CLIPBOARD
selection이나 클립보드에 저장된 자료를 제거하는 것은 get이나 append 대신 clear를 사용하면 가능하다.
텍스트를 입력할 때, 포커스를 지정하는 명령으로 focus가 제공된다. 다음은 frame1 위짓의 entry 위짓에 포커스를 맞추는 예이다.
focus .frame1.entry
포커스를 없애려면 focus none을 수행하면 된다.
7장 Dialog Window
대화 상자(dialog window)를 만드는 것은 tk_dialog를 이용하면 가능하다. 다음은 OK, Cancel, Quit라는 세 개의 버튼을 가지는 대화 상자를 생성한다. 디폴트(default)로 선택되는 버튼은 0번째 OK버튼이다. 비트맵으로 info를 사용하였다.
tk_dialog .dlg "Hello" "This is a hello." info 0 OK Cancel Quit
[그림 15]
사용자가 직접 대화 상자를 만들기 위해서는 toplevel 명령을 이용하여 toplevel 위짓을 구성하고, 그 위짓을 Diaglog 클래스로 선언하는 것이다. toplevel 위짓은 기본 윈도우 바깥에 윈도우를 하나 더 생성하는 역할을 한다.
toplevel .top -class Dialog
label .top.l -relief flat -text "My own dialog box"
button .top.b -relief ridge -text "OK" -command { puts "OK" }
pack .top.l .top.b -side left
[그림 16]
이벤트가 발생하면 그 이벤트는 그 윈도우와 그 하위에 있는 위짓에만 전달이 된다. 이것을 grab이라고 하는데, 이벤트를 특정 윈도우와 연결시키려면 다음과 같이 grab을 설정하면 된다.
grab set .dlg
반대로 이 설정을 풀려면 set 대신 release를 사용한다.
Tk에서는 변수의 값이 변하거나 윈도우의 visibility 상태가 바뀌거나, 또는 윈도우가 사라지게 될 때까지 기다리게 하는 tkwait 명령이 있다.
tkwait variable hello
tkwait visibility .top
tkwait window .dlg
다음은 OK 버튼과 Cancel 버튼을 가진 대화상자를 만들고, 대화상자에서 임의의 버튼을 선택할 때까지 기다리는 예제이다.
toplevel .top
grab set .top
button .top.ok -text OK -comman { destroy .top }
button .top.cancel -text Cancel -comman { destroy .top }
pack .top.ok .top.cancel -side left
tkwait window .top
8장 기타
위짓에 속한 기본 리소스가 아닌 윈도우 매니저가 관리하는 리소스는 wm 명령을 이용하면 된다. 예를 들어, 윈도우의 타이틀을 바꾸려면 위짓의 리소스를 바꾸어 해결할 수 있는 것이 아니라, 윈도우 매니저에게 요청해야 한다.
wm title .top "My dialog window"
이 윈도우를 아이콘으로 만들어(minimize) 보자.
wm iconify .top
윈도우 매니저가 관리하는 리소스를 바꾸거나 그 정보를 알아내기 위해서 wm 명령을 사용할 수 있다. 자세한 내용은 man -s n wm을 참조해야 할 것이다.
tkwait의 예제에서 나왔던 destroy 명령은 윈도우를 제거하는 명령이다. 윈도우를 제거하면서 관련된 명령이나 윈도우 상태 또한 제거한다. 윈도우가 쌓여있는 순서를 바꾸기 위해 raise나 lower 명령을 사용할 수 있다.
예제파일
MP3 연주기로 유명한 Mpg123은 텍스트 기반의 프로그램이다. 이것의 대표적인 X 인터페이스는 Tk3play이다. 다시 말하면, Mpg123은 텍스트 상에서 MP3 파일을 디코딩(decoding)해서 연주해주는 작업을 하고, Tk3play는 버튼이나 레이블을 이용하여 Mpg123을 제어하는 역할을 맡는다. 아래 예제는 필자가 Tk3play를 몰랐을 때, Mpg123을 X 윈도우 상에서 제어하는 인터페이스가 필요해서 작성했던 Tcl/Tk 스크립트이다. Tk3play의 아주 기본적인 몇 가지 기능을 가지고 있는 인터페이스라고 할 수 있다.
#!/usr/local/bin/wish -f
#
# mpgplay
#
# 이 스크립트는 wish를 이용한 mpg플레이어입니다.
# This script run mpeg3 audio player with wish.
# 아규먼트로부터 디렉토리명을 제외한 MP3 파일의 이름을 구한다.
set filenamelist [split [lindex $argv 0] /]
set listend [expr [llength $filenamelist] - 1]
set filename [lindex $filenamelist $listend]
# 타이틀과 MP3 파일명을 위한 레이블을 만들고
# Play, Stop, Quit을 위한 버튼을 만든다.
label .title -text ” Terzeron’s mp3 player ” -foreground black
-background pink -relief ridge
label .name -text $filename -foreground black -background white
-relief ridge
frame .ground -relief sunken
button .ground.play -text Play -foreground blue -background white
button .ground.quit -text Quit -foreground red -background white
button .ground.stop -text Stop -foreground purple -background white
# 레이블과 버튼 등의 위짓을 배치한다.
pack .title -side top -fill x
pack .name -fill x
pack .ground -fill x
pack .ground.play .ground.stop .ground.quit -side left -expand 1 -fill both
# 버튼과 키입력에 대한 이벤트 처리 프러시져를 연결시킨다.
bind .ground.play { playproc }
bind .ground.quit { quitproc }
bind .ground.stop { stopproc }
bind . { playproc }
bind . { stopproc }
bind . { quitproc }
# 기본값 지정
set pidno 0
set playing 0
set stopping 0
# Play 프러시져
proc playproc {} {
global argv pidno playing stopping fileloc
# 이미 연주 중이면 무시
if {$playing == 1} {
return
}
# 버튼의 색상과 relief형태를 바꾼다.
.ground.play configure -background yellow -foreground black -relief sunken
.ground.stop configure -background white -foreground purple -relief raised
if {$stopping == 1} {
# 연주 중에 멈춘 경우에는 CONT 시그널을 보내 mpg123을 동작시킨다.
exec /usr/bin/kill -CONT $pidno
} else {
# 아직 시작하지 않은 경우에는 mpg123을 fork/exec하여 실행시킨다.
set pidno [exec /usr/local/bin/mpg123 [lindex $argv 0] >& /dev/null &]
}
set playing 1
set stopping 0
}
# Stop 프러시져
proc stopproc {} {
global argv pidno stopping playing
# 연주가 멈춰 있는 경우나 아직 시작하지 않은 경우에는 무시한다.
if {$stopping == 1 || $playing == 0} {
return
}
# 버튼의 색상과 relief 형태를 바꾼다.
.ground.stop configure -background yellow -foreground black -relief sunken
.ground.play configure -background white -foreground blue -relief raised
set stopping 1
set playing 0
# STOP 시그널을 mpg123으로 보내 잠시 프로세스를 멈추게 한다.
exec /usr/bin/kill -STOP $pidno
}
# Quit 프러시져
proc quitproc {} {
global argv pidno playing stopping
# KILL 시그널을 보내 프로세스를 종료시킨다.
if [catch {if {$pidno != 0} { exec /usr/bin/kill -9 $pidno } } ] {
;
}
# top-level 위짓을 없앤다.
destroy .
# 끝낸다.
exit 0
}
# 스크립트가 실행하면 바로 Play 프러시져를 호출하여 연주를 시작한다.
playproc
[그림 17]
이 인터페이스는 Tk3play에 비하면 기능도 부족하고 깔끔한 위짓 배치를 보여주지도 못한다. 그러나 독자들이 ‘왜 Tcl/Tk 인가?’하는 의문에 답할 수 있는 한 가지 사례를 보여주는 예제 프로그램이 될 수 있을 것이다. 이 기사를 읽은 독자라면 누구나 Tcl/Tk를 이용하여 손쉽게 X 윈도우 프로그래밍을 할 수 있을 것이다.
Mpg123과 Tk3play는 다음 URL에서 구할 수 있다.
http://www-ti.informatik.uni-tuebingen.de/~hippm/mpg123.html
http://www.msc.cornell.edu/~bef2
서울대학교 전산과학과 데이타베이스 연구실 조영일
Tcl/Tk 문법 - 1부 Tcl
Development 2008. 6. 9. 09:341999/05/15
소개
Tcl은 Tool Command Language, Tk는 Toolkit의 약자로서, 응용프로그램을 제어하고 확장하는 것을 돕는 프로그래밍 언어의 하나이다. Tcl의 장점은 Tk와 함께 사용되어 응용프로그램이 X Window를 손쉽게 다룰 수 있도록 할 수 있다는 데 있다. 물론 요즘에는 Scheme, Lisp, Perl 등의 강력한 경쟁자들이 생기긴 했지만, 아직도 많은 개발자들이 Tcl/Tk에 대해서 친근감을 느끼고 있다. 게다가 Tcl/Tk는 C source로 embed하여 사용할 수 있다는 강점을 가지고 있다.
Tcl/Tk는 [티클티케이]라고 읽는다고 개발자 J. K. Ousterhout가 말했다. Ousterhout는 Tcl의 장점으로 쉽고, 강력한 스크립트 언어이며, 다른 패키지와 연결하기 쉽다는 점을 밝히고 있다.
필자가 꼽는 여타의 프로그래밍 언어에 대한 Tcl/Tk의 장점은 쉽다는 것이다. 아주 간단하게 문법을 익힐 수 있어서 초보자들이 X Window 상에서 실행되는 프로그램을 개발하는 것이 아주 용이하다. 그러나 이 장점은 역으로 단점이 되기도 한다. Tcl자체만으로는 시스템 프로그래밍에 적합하지 않다는 점이 다. 그러나 프로그래밍 언어는 모든 기능을 가질 수도 없고, 가진다고 해도 널리 쓰일 수 있는 것은 아니기 때문에 Tcl 나름대로 유용하게 쓰일 곳이 있기 마련이다. 그러나 미리부터 실망할 필요는 없다. Tcl을 C로 embed시켜 서 시스템 프로그램을 개발한다면 Tcl의 장점을 살리면서 C의 강력한 기능 을 지원받을 수 있으니 말이다. 자, 이제부터 티클티케이가 당신의 개발도 구가 될 수 있도록 가볍게 시작하도록 하자.
설치 및 실행
Tcl/Tk에 관련된 거의 모든 패키지는 http://www.scriptics.com/software에서 구할 수 있다. 윈도우즈(Windows)와 매킨토시(Macintosh)환경에서 사용할 수 있는 바이너리 배포본도 제공된다. 필자가 권하는 버전은 Tcl/Tk 8.1b3이다.
ftp://ftp.scriptics.com/pub/tcl/tcl8_1/tcl8.1b3.tar.gz
ftp://ftp.scriptics.com/pub/tcl/tcl8_1/tk8.1b3.tar.gz
에서 소스를 직접 내려받을 수도 있다. 컴파일 과정은 아주 간단하다. Tcl과 Tk 소스를 모두 풀어놓고 tcl8.1b3/unix 디렉토리에서 configure;make를 실행하면 컴파일까지 끝난다. 수퍼유저 권한으로 make install을 실행하면 /usr/local/bin에서 tclsh과 wish를 실행할 수 있을 것이다. 이전 Tcl/Tk버전을 이미 설치했다면 tclsh과 wish가 최신 버전(tclsh8.1과 wish8.1)을 링크하고 있지 않을 테니, 확인을 해야 하는 번거로움이 있다. tclsh은 Tcl 명령만을 실행할 수 있는 인터프리터이고, wish은 Tcl/Tk 명령을 실행할 수 있는 인터프리터인데, 1부에서는 tclsh로도 충분히 모든 기능을 확인할 수 있을 것이다.
이 문서는 총 3부로 구성되어 있고, 1부는 Tcl의 문법, 2부는 Tk의 문법, 3부는 Tcl/Tk의 확장에 대해 다루고 있다.
1부 Tcl의 문법
1장 기초 문법과 변수, 표현식, 리스트
1) 기초 문법과 변수
가장 처음에 하고 싶은 일은 출력일 것이다. 모든 프로그래밍 언어가 그렇 게 하듯이 세상에 인사부터 하는 게 예의일 것이다.
puts "Hello, World!"
인사를 여러 번 할 수 있도록 문자열을 변수에 저장하려면,
set hello "Hello, World!"
put $hello
csh과 비슷하게 대입에는 set, 변수의 값 사용(dereference)에는 $를 사용한다. 더욱 재미있는 점은 csh처럼 unset 명령도 제공된다는 점이다.
다소 불편한 점이라면, 표현식을 처리하기 위해서는 반드시 expr을 사용해 야 한다는 것이다. 이것은 Tcl이 변수 타입에 대해서 느슨한 태도를 취하기 때문인데, 만약 다음과 같은 명령을 준다면,
set j 3; set i $j+1
i에는 문자열로 $j+1이 대입될 것이다. 이것은 원하는 바가 아닐 수도 있다. $j+1을 표현식(expression)으로 간주하고 처리하기 위해서는 앞에서 밝힌 바와 같이 expr을 써서,
set i [expr $j+1]
이라고 명령을 주어야만 한다. 다소 번거로운 일이긴 하지만, 거꾸로 생각해보면 표현의 자유로움과 다양성을 보장받을 수 있다는 것을 의미하기도 한다. 이 예에서 우리는 ;이 Tcl문장의 구분자(separator)로 사용된다는 것과 [ ]이 하나의 Tcl명령의 결과값을 반환한다는 것을 덤으로 알게 되었다.
Tcl에서 사용되는 특수문자는 일반적으로 셸(shell)에서 사용하는 a, ,
, f 등을 그대로 사용할 수 있다. 예를 들어, 다음의 실행 결과는 My name is “Young-il Cho”. 가 될 것이다.
set firstname "Young-il"
set lastname "Cho"
set myname "My name is "$firstname $lastname".
";
puts $myname
사실 Tcl의 각 문장 하나하나는 결과값을 매번 반환하기 때문에 마지막 줄의 puts는 필요하지 않을 수도 있다. 그렇기 때문에, puts $myname 대신에 set myname 이라고 입력해도 같은 결과를 얻을 수 있다.
변수는 타입이 정해지지 않았기 때문에, 다른 타입의 값을 대입할 수 있을 뿐만 아니라, 일반 변수를 배열처럼 사용할 수도 있다. 다음은 1월과 2월의 이름을 배열에 넣은 후에, 1월의 이름을 구하는 예제이다. 배열이라고는 하지만, 마치 Perl의 해시(hash) 변수처럼 사용할 수 있다.
set month(1) Jan
set month(2) Feb
set month(1)
다차원 배열도 가능하다. 다음은 4월 3일부터 5일까지의 요일을 다차원 배열에 대입해보는 아주 간단한 예이다.
set mday(4,3) Sat
set mday(4,4) Sun
set mday(4,5) Mon
puts $mday(4,4)
정수값을 가지고 있는 변수는 incr 명령을 이용하여 증감시킬 수 있는데, 그 변수에 들어 있는 값이 정수값으로 읽을 수 있는 값이기만 하면 된다.
set x "1"
incr x
여기에 다시 100배를 해서 3을 빼는 작업을 해보도록 하자. 100를 하기 위해서는 앞에서와 같이 expr $x*100도 가능하겠지만, append 명령을 이용하여 정수값 뒤에 0을 두 개 붙이는 것도 가능하다. 다음 예의 결과값은 2 * 100 - 3이니까 197이 될 것이다.
append x "00"
incr x -3
puts $x
강력하게 타입을 검사하는 컴파일 프로그래밍 언어에서는 상상도 하지 못할 엉뚱한 작업들을 태연하게 해내고 있다. 그만큼 융통성이 있다고 볼 수도 있고 거꾸로 사용자들이 에러를 내기 쉬울 수도 있다고 볼 수도 있다.
변수 중에서 예약되어 있는 변수 두 가지가 있다. 하나는 프로그램으로 넘겨지는 argument 리스트에 관련된 argv0, argv, argc이고, 또 하나는 환경 변수를 해시 형태로 가지고 있는 env이다. argv0은 Tcl로 작성된 스크립트의 이름을 가리키고, argv는 argument 리스트 전체를 배열로 가지고, argc는 argument의 개수를 정수값으로 가지고 있다. 다음의 예를 실행파일로 만들어서 argument로 hello 1 2 world를 사용해 실행해보면 이해가 어렵지 않을 것이다.
#!/usr/local/bin/tclsh
puts "This program $argv0 has $argc arguments : $argv
";
puts "User's ID is $env(USER).
";
2) 표현식
표현식은 수식이나 문자열 처리에 관한 것이다. Tcl에서 제공하는 연산자는 ANSI C의 것과 거의 동일하다. 사칙 연산자(+, -, *, -)와 나머지 연산자(%)를 비롯하여 관계연산자(>, <, >=. <=, !=, ==)와 논리연산자(!, &&, ||), 비트 연산자(!, ^, |, ~, <<, >>), 3항 연산자(? :)가 모두 지원된다.
또한 C에서 제공하는 수학 함수(삼각함수, 지수함수 등)를 거의 모두 사용할 수 있다. 기본적으로 프로그래밍의 경험이 조금이라도 있는 독자라면 여기에서 자세히 다루지는 않고 이름만 나열해도 쉽게 man page를 이용해 쉽게 찾아볼 수 있을 것으로 간주하고 넘어가도록 하겠다.
abs, acos, asin, atan, ceil, cos, cosh, double, exp, floor, fmod, hypot, int, log, log10, pow, round, sin, sinh, sqrt, tan, tanh
tclsh 실행 도중, man abs를 입력해보면 C의 man page를 볼 수 있다. abs, labs, llabs가 C에서 제공되고 있지만, Tcl에서는 long 타입의 변수를 사용할 수 없는 관계로 labs와 llabs는 사용할 수 없다. 물론 Tcl을 C에서 라이브러리로 사용할 때는 long이 사용되어야 하므로 long를 다루는 방법이 제공된다.
리스트나 문자열 형태의 값을 Tcl 명령으로 인식하여 작업을 수행하는 eval이라는 명령이 있다. eval {puts $tcl_version}라고 입력하면 puts $tcl_version이 실행될 것이다. 그러면 굳이 eval 명령을 사용해야 하는 이유에 대한 의구심이 생길 지도 모르겠다. 다음의 예를 보자.
set y 3
foreach f {set unset} {
eval $f y
}
puts $y
우선 변수 y에 3을 대입하고 foreach 문에서 변수 f에 set과 unset을 대입하면서 매번 eval $f y를 실행하기 때문에, set y와 unset y가 실행된다. unset에 의해 y를 변수로 사용할 수 없게 되었으므로 마지막 명령 puts는 에러를 발생하게 되어 있다.
문자열 처리에 관련된 명령들은 뒤에서 다시 설명하도록 하겠다.
3) 리스트
리스트는 [, ] 또는 “, “을 이용해 만들 수 있다.
set x {hello world}
set x "hello world"
는 같은 결과를 가지게 된다. 주의할 것은 set x [hello world]는 hello를 명령으로 인식하여 에러를 발생하게 된다는 점이다.
리스트를 다루기 위해 제공되는 명령에는 리스트를 붙이거나 인덱스를 이용해 특정 아이템을 꺼내거나 쪼개거나 검색하는 명령이 있다. 리스트 안에 리스트를 둘 수도 있는데, 이런 경우 lindex를 두번 사용하여 특정 단어를 지정할 수 있다. 다음은 New York의 York를 가리키는 예를 든 것이다.
set x {California Chicago {New York} Washington Texas}
lindex [lindex $x 2] 1
리스트를 붙이는 방법에는 리스트에 존재하는 모든 아이템을 모아서 붙이는 concat 명령과 각 리스트를 하나의 아이템으로 유지시키면서 붙이는 list 명령이 있는데, 다음을 비교해보자.
set y {Miami {Salt-lake City} Alaska}
concat $x $y
list $x $y
이 명령들의 결과는 다음과 같다.
California Chicago {New York} Washington Texas Miami {Salt-lake City} Alaska
{California Chicago {New York} Washington Texas} {Miami {Salt-lake City} Alaska}
이제는 리스트를 쪼개고 합치고 하는 작업을 하기로 한다. passwd파일의 일부을 변수 a에 담고, :을 구분자(delimiter)로 삼아서 : 단위로 쪼개어 변수 b에 리스트로 저장한다. 그리고는 다시 하나의 아이템으로 합쳐보도록 하자. 결과적으로 변수 c는 a와 같은 내용을 포함하게 될 것이다.
set a root:x:0:1:Super-User:/:/sbin/sh
set b [split $a :]
set c [join $b :]
이번에는 리스트의 일부를 찾거나 치환하거나 리스트를 정렬하는 명령에 대해 알아보도록 하자. 아이템을 찾는 것은 lsearch, 치환하는 것은 lreplce와 lrange, 정렬하는 것은 lsort이다. 리스트가 포함하고 있는 아이템 수를 반환하는 llength명령은 지나가도록 한다. 치환하거나 아이템을 찾을 때 사용되는 인덱스(index 또는 offset)를 설명하는 일은 필자에게나 독자에게나 모두 머리 아픈 일이 될 테니, 간단한 예로 대신하고자 한다. 다음은 리스트 변수 x의 2번째 위치부터 1 빼기 1개(0개)의 아이템과 Detroit라는 새로운 아이템을 바꿔치기 하고 2번째 위치부터 3 빼기 1개(2개)의 아이템을 Detroit와 Boston으로 치환하는 것이다. 그 다음은 3번째 공백 위치에 Illinois과 Detroit를 끼워넣는 것이다. 리스트의 일부를 꺼내는 lrange 명령도 있으나 여기서는 설명을 생략하기로 한다.
lreplace $x 2 1 Detroit
lreplace $x 2 3 Detroit Boston
linsert $x 3 Illinois Detroit
lrange $x 1 2
주의할 것은 이런 명령이 리스트 변수 x에 대해서 물리적인 효과를 가지지는 못한다는 점이다. x에 물리적인 효과를 주려면 set x [linsert $x 3 Illinois Detroit] 처럼 새로 대입해야만 한다. 위 명령의 결과는 다음과 같다.
California Chicago Detroit {New York} Washington Texas
California Chicago Detroit Boston Texas
California Chicago {New York} Illinois Detroit Washington Texas
Chicago {New York}
lappend는 위의 명령들과는 조금 다르다. 변수를 새로운 아이템을 추가한 결과로 바꾸어주기 때문이다.
lappend x Hawaii
이제 정렬해보자. lsort에 사용되는 옵션(option)에는 -ascii, -dictionary, -integer, -real, -command, -increasing, -decreasing, -index가 있는데, 디폴트(default) 값은 -ascii와 -increasing이다. Tcl/Tk가 버전 8로 올라오면서 -dictionary와 -index가 추가되었는데, -dictionary 옵션은 -ascii 옵션과 거의 동일하지만, 대소문자가 구분되지만 비교시에는 무시되고 단어 중간에 나오는 숫자는 문자로서 취급되지 않고 수치로 취급된다는 점이다. man page에 나오는 예를 적어보았다.
lsort -dictionary {bigBoy bigbang bigboy}
lsort -dictionary {x10y x9y x11y}
직접 실행하여 결과를 얻어보길 바란다. -index 옵션은 다음과 같은 예를 보면 쉽게 이해할 수 있을 것이다. 각각의 아이템은 리스트 형태로 되어있고, 그 리스트 중에서 index가 가리키는 아이템이 정렬할 때 키(key)로 사용되는 것이다.
lsort -integer -index 1 {{First 24} {Second 18} {Third 30}}
2장 제어문, 프러시져
1) 제어문
제어문에는 if, while, for, foreach, switch, continue, break 등이 있다. source나 이전에 다루었던 eval등이 제어문에 속하기는 하지만, source의 설명은 다음 장으로 미룬다. 제어문은 대체로 프로그래밍의 기본에 속하기 때문에 프로그래밍의 경험이 조금이라도 있는 독자라면 쉽게 이해할 것으로 간주하여 간단히 설명하고 다음으로 넘어가도록 하겠다. 다만 Tcl에서 주의해야 할 점은 C와는 달리 비교문은 {과 }로 둘러싸야 한다는 것이다.
if {$x < $y} {
puts "X is less than Y."
} else if {$x == $y} {
puts "X is equal to Y."
} else {
puts "X is greater than Y."
}
위의 예제는 x와 y의 수치값을 비교하여 각각의 경우에 대해 설명을 출력한다. 다음의 while, for, foreach는 모두 동일한 작업을 수행한다.
set i 0
while {$i > 5} {
puts $i
if {$i == 3} {
break;
}
incr i
}
for {set i 0} {$i > 5} {incr i} {
puts $i
if {$i == 3} {
break;
}
}
foreach i {0 1 2 3 4 5} {
puts $i
if {$i == 3} {
break;
}
}
2) 프러시져(procedure)
프러시져는 C의 함수(function)과 같다고 할 수 있다. 문법은 “proc 프러시져이름 매개변수리스트 프러시져본체”로 되어 있다. 명시적으로 return을 이용해서 결과를 반환할 수도 있고, return을 사용하지 않으면 마지막으로 사용된 표현식의 결과가 return값으로 사용된다.
proc average parameters {
set sum 0.0
foreach i $parameters {
set sum [expr $sum + $i]
}
return [expr $sum / [llength $parameters]]
}
프러시져의 호출은 다음과 같은 방법으로 할 수 있다.
average {1 2 3 4 5 6 7 8 9 10}
{1 2 3 4 5 6 7 8 9 10}이 parameters라는 리스트형 변수로 넘겨지는 것이다. 그러나 매개변수로 하나만 사용될 수 있는 것은 아니고 여러 개를 지정하거나 기본값을 지정할 수도 있다.
proc sum {x {y 3}} {
return [expr $x + $y]
}
변수 y의 기본값으로 3이 정해져 있기 때문에, sum 3 4 과 같은 형태의 호출이 가능하고, sum 3 과 같은 형태로도 호출을 할 수 있다. 그 결과값은 7과 6일 것이다.
프러시져 내부로 제어가 넘어가면 기본적으로는 외부나 상위의 프러시져의 변수를 사용할 수 없다. 매번 매개변수를 사용할 수는 없는 노릇이므로 global이나 upvar를 사용하여 상위레벨의 변수에 접근하게 된다. global 명령은 외부의 변수들을 전역변수로 지정하여 현재 프러시져 내부에서 지역변수처럼 자연스럽게 사용할 수 있게 한다. upvar는 Tcl의 “참조에 의한 호출”(call-by-reference)을 지원하기 위해 사용되는 명령으로 상위레벨의 프러시져에서 사용되는 변수를 새로운 이름으로 지정해서 지역변수로 사용하게 한다.
set virtual_average 30.0
proc average parameters {
global virtual_average
set sum 0.0
foreach i $parameters {
set sum [expr $sum + $i]
}
return [expr $virtual_average + $sum / [llength $parameters]]
}
이 예제는 평균을 구하는 위의 예제에 가평균을 사용하기 위해 약간 손을 본 프러시져이다. virtual_average가 외부에서 정의되었기 때문에 proc average에서는 사용할 수가 없어서 global 명령으로 virtual_average를 지역변수화한 것이다. 다음의 예는 upvar를 이용해서 새로운 지역변수로 상위레벨의 변수를 참조하는 것을 보이는 것이다.
proc print array_name {
upvar $array_name arr
foreach item [lsort $arr] {
puts $item
}
}
upvar는 정수값을 이용해서 참조의 대상이 되는 변수를 어느 레벨까지 찾을 것인가를 결정할 수 있는데, #0을 쓰면 무한대로 거슬러 상위로 올라갈 수 있다. 다음의 예는 바로 상위의 프러시져의 array_name이나 혹은 그 프러시져를 호출한 더 상위의 프러시져에서 사용된 array_name을 arr로 참조하겠다는 의미이다. 그 다음 줄은 상위로 계속 거슬러 올라가면서 array_name이라는 변수를 찾겠다는 의미이다.
upvar 2 $array_name arr
upvar #0 $array_name arr
upvar와 비슷한 명령으로 uplevel이라는 명령이 제공되는데, 이 명령은 eval과 upvar를 합쳐놓은 기능을 한다. 다음 명령이 프러시져 내부에서 사용되면 이 프러시져를 호출한 프러시져의 x변수를 참조해다가 43을 대입하는 것을 실행할 수 있게 한다.
uplevel 1 {set x 43}
3장 문자열 처리
Tcl은 8 bit-clean하다고 한다. 이 말은 ASCII 코드 이외의 문자를 다룰 수 있다는 의미이다. 그래서 tclsh에서 한글 출력이 가능하다. wish의 경우에는 조금 사정이 달라서, 폰트만 지정하면 출력은 문제가 없지만,아직까지도 입력서버에 관련된 사항이 미비하여 한글입력은 가능하지 않다.
문자열을 다루는 것은 리스트를 다루는 것과 비슷한 형태의 명령을 통해 가능하다. 다만 문자열 처리 명령은 string과 기타 명령을 조합한 형태이다. 예를 들면, string length는 문자열의 길이를 출력하는 명령이고, string index는 문자열의 몇번째 글자를 지정하는 명령이다.
1) 정규 표현식(regular expression)
문자열에 대해서 설명하기 전에 정규 표현식(regular expression)에 대해서 설명을 해야겠다. 다소 안타깝지만, Tcl의 정규 표현식은 Perl의 정규 표현식이 만들어내는 것보다는 표현력이 약하다. 그러나 사용하는데 별 무리는 없을 것이다.
[HTML]
. | 임의의 한 글자 |
* | 바로 앞 글자 또는 부분문자열(substring)이 0번 이상 반복될 수 있음 |
+ | 바로 앞 글자 또는 부분문자열이 1번 이상 반복될 수 있음 |
? | 바로 앞 글자 또는 부분문자열이 존재하거나 존재하지 않을 수 있음 |
^ | 문자열의 처음 위치(첫 글자 자체를 가리키는 것은 아님) |
$ | 문자열의 마지막 위치(마지막 글자 아님) |
특수문자 | 특수문자를 정규 표현식에서의 의미가 아닌 문자 그 자체로 인식 |
(정규표현식) | ()를 이용하여 표현식과 일치하는 문자열을 부분문자열로 간주 |
[문자열] | []안의 문자들 중 임의의 한 글자(예제 참고) |
정규표현식|정규표현식 | 두 정규 표현식 중 임의의 한 표현식 |
[/HTML]
정규 표현식은 regexp나 regsub와 같은 명령을 통해 사용될 수도 있고, 문자열 관련 명령 중의 패턴(pattern)으로도 사용될 수 있다. 다음에 나올 예는 regexp와 regsub가 각각 패턴의 일치성을 검사하거나 패턴을 치환하는 것이다.
regexp {[^a-z].*} The
regexp {[^a-z].*} them
regexp {[^a-z].*} 123
[] 내부 문자열의 첫 글자로 ^가 나오면 [] 내부의 문자열을 제외한 모든 글자가 해당되도록 되어 있으므로 위의 예는 a부터 z까지의 소문자를 제외한 글자로 시작하는 단어만 참(true)로 간주하여 패턴 매치(pattern match)의 결과를 1이나 0으로 돌려주게 된다. 그러므로 두번째 단어를 제외한 두 단어는 패턴 매치가 성공하여 1이 반환된다. 매치된 부분문자열을 변수에 저장할 수도 있는데, 다음의 예를 보자.
regexp {([A-Z][a-z]+) ([a-z]+)} “King died!” line noun verb
line에는 King died가 noun에는 King이 verb에는 died가 저장될 것이다. 옵션으로 -nocase와 -indices가 지원되는데, -nocase는 대소문자를 구별하지 않으면서 패턴 매치를 수행하는 옵션이고, -indices는 일치하는 부분문자열을 변수에 저장하는 대신, 부분문자열의 첫 글자와 마지막 글자의 인덱스(index 또는 offset)을 대입해준다. 이 옵션을 써서 위의 예를 실행하게 되면 line은 0 8, noun은 0 3, verb는 5 8을 가지게 될 것이다.
다음은 regsub를 이용해 잘못된 스펠링 teh를 the로 바꾸고 그 바뀐 문자열을 x에 저장하는 것이다.
regsub teh "I can't believe teh truth of teh events" the x
puts $x
결과는 예상과는 달리 앞 쪽의 teh만 제대로 고쳐질 것이다. 매번 teh가 나올 때마다 고치려면 -all옵션을 사용하면 된다.
2) format
C의 printf는 너무 유명해서 모르는 프로그래머가 없을만한 함수이다. printf의 최대 장점은 문자열의 format을 정해서 프로그래머가 원하는 형태로 출력이 가능하다는 점인데, Tcl에서는 이런 format을 위해 format명령과 scan명령을 제공한다. format 명령은 printf와 비슷하고 scan은 sscanf과 비슷하다.
puts [format "My name is %s and my age is %d." Terzeron 25]
이런 식으로 해서 ANSI C의 printf가 제공하는 모든 기능을 Tcl에서도 사용 가능하다. 거꾸로 sscanf도 가능한데, 다음의 예를 보자. scan의 결과는 매치되는 부분문자열의 개수이고, 마지막에 사용된 변수에 매치되는 부분문자열이 저장된다.
scan "My name is Terzeron and my age is 25." "My name is %s" name
3) 문자열 명령
드디어 문자열 자체를 다루는 명령들에 대해서 알아볼 시간이다. 앞에서도 언급했다시피 string 명령은 compare(비교), first(첫번째 매치되는 글자의 index), last(마지막으로 매치되는 글자의 index), index(그 인덱스에 위치한 글자), length(문자열의 길이), match(패턴 매치 결과), range(부분문자열), tolower(소문자로 바꾸기), toupper(대문자로 바꾸기), trim, trimleft, trimright(해당 글자를 문자열 앞쪽이나 뒤쪽에서 잘라내기), 등의 명령과 조합하여 사용해야 한다.
string length "hello"
string range "hello" 3 4
string compare "hello" "hello"
string compare "hello" "Hello"
string index "hello" 4
string first l "hello"
string last l "hello"
string match {[a-z]*} “hello”
string trim aaabbcccaaa a
string trimleft aaabbcccaaa a
string trimright aaabbcccaaa a
string toupper hello
string tolower Hello
위 예제를 한 줄씩 설명하기는 시간 낭비일테니까, 각자 직접 실행하여 결과를 얻어보길 바란다. 필자는 string match가 잘 되지 않아서 다소 애를 먹은 경험이 있다. 위 예제의 결과를 차례대로 나열해보면 이렇다. 5, lo, 0, 1, o, 2, 3, 1, bbccc, bbcccaaa, aaabbccc, HELLO, hello
4장 파일 입출력, 프로세스 관리
이전까지는 어떤 시스템에서도 잘 실행되었을 법한 명령들에 대해서 다루어 보았다. 그러나 파일 입출력이나 프로세스 문제는 시스템마다 다르기 때문에, 지금부터는 POSIX를 따르는 유닉스 시스템에서 실행되는 명령들에 대해서 다루어보기로 한다.
1) 시스템
디렉토리를 지정하는 방법으로 C shell에서 사용하는 ~도 사용가능하다. ~terzeron이라라고 하면 terzeron이라는 사용자의 홈 디렉토리를 의미하고, ~라고 하면 지금 프로그램의 실행자의 홈 디렉토리를 의미한다. cd 명령으로 디렉토리를 옮길 수 있고, pwd 명령은 현재 디렉토리를 확인할 수 있고, file 명령으로 디렉토리에 관한 문자열 작업을 가능하게 돕는다. file 명령의 옵션으로는 다음과 같은 것들이 있다.
[HTML]
dirname | 파일이 위치한 디렉토리 이름 |
rootname | 파일의 확장자를 제외한 이름 전체 |
extension | 파일의 확장자 |
tail | 파일의 전체 경로에서 디렉토리 부분을 제외한 나머지 |
atime | 최종 접근 시간(access time) |
mtime | 최종 변경 시간(modified time) |
size | 파일의 바이트(byte) 크기 |
type | 파일의 타입 |
readlink | 심볼릭 링크(symbolic link)가 가리키는 파일의 이름 |
exists | 파일이 존재하는가? |
isdirectory | 파일이 디렉토리인가? |
isfile | 파일이 일반 파일인가? |
executable | 실행가능한가? |
readable | 읽기가능한가? |
writable | 쓰기가능한가? |
owned | 프로그램 실행자의 소유인가? |
stat | 파일의 atime, ctime, dev, gid, ino, mode, mtime, nlink, size, uid를 키로 가지는 배열을 반환한다. |
lstat | stat과 같으나 심볼릭 링크에 대해서는 링크 자체의 정보를 반환한다. |
[/HTML]
glob을 이용하면 shell에서처럼 *이나 ?같은 메타 문자를 사용할 수 있다. glob 명령으로 파일이름 리스트를 구하고 file 명령으로 각 파일에 대한 정보를 구하거나 테스트를 수행할 수 있다. 다음의 예는 /usr/include/sys 디렉토리에 존재하는 헤더 파일 중 x로 시작하는 이름을 가진 파일들을 읽어서 그 크기를 조사해보는 것이다.
set filelist [glob /usr/include/sys/x*.h]
foreach f $filelist {
puts “$f [file size $f]”
}
2) 파일 입출력
파일을 열고 닫고 읽고 쓰기 위해 제공되는 명령에는 open, close, gets, puts, read, flush, eof, seek, tell 등이 있다. 파일을 다루기 위해서 가장 먼저 해야 할 일은 파일을 여는(open) 작업이다. 파일을 열면 파일id가 반환되고 이 id를 가지고 읽고 쓰는 작업을 수행할 수 있는 것이다.
set filename /usr/include/limits.h
set f [open $filename r]
while {[gets $f line] >= 0} {
puts $line
}
close $f
이 예제는 가장 간단한 파일 입출력을 보여주고 있다. 한 줄씩 읽어서 line이라는 변수에 저장하고 다시 출력하고 있다. 이제 다른 파일로 복사하는 프로그램으로 고쳐보자. 위의 예에서는 읽기 위해서 모드(mode)를 r(읽기)로 주었는데, 이번에는 강제적으로 덮어쓰기 위해 w+(강제로 덮어쓰기) 모드로 열어야 한다.
set infile /usr/include/limits.h
set outfile ~/limits.h
set inf [open $infile r]
set outf [open $outfile w+]
while {[gets $inf line] >= 0} {
puts $outf $line
}
close $outf
close $inf
flush는 puts가 버퍼링을 하기 때문에 출력이 지연되는 것을 강제적으로 막기 위해 사용되는 명령이다. 위의 예제에서 puts 명령 다음에 flush $outf라고 써주게 되면 puts가 버퍼를 다 채우지 못했더라도 강제적으로 버퍼를 비워서 출력이 빠르게 진행된다. 이 밖에 파일의 변위(offset)를 가지고 특정 위치로 이동할 수 있도록 seek 명령이 제공되고, 현재 파일의 어느 부분을 읽거나 쓰고 있는지 알기 위해 tell 명령이 제공된다. 이렇게 랜덤한 접근을 하는 경우 파일의 끝을 알아야 하는데, 이럴 때 eof 명령으로 파일의 끝인가를 검사할 수 있다.
3) 프로세스 관리
프로세스는 파일 상태로 디스크에 존재하는 프로그램이 실행되어서 메모리에 올라와 있는 것을 말한다. 프로세스를 만들기 위해서는 exc 명령으로 프로그램을 실행시켜야 한다. 다음 예는 stdio.h에서 printf라는 단어를 포함하고 그 중에서 FILE이라는 단어를 포함하지 않는 줄을 찾아주는 프로세스를 만드는 것이다.
exec grep printf /usr/include/stdio.h | grep -v FILE
현재 실행되고 있는 Tcl 스크립트의 출력을 다른 프로그램(필터)으로 넘길 수 있는데, 이것은 파일 입출력에서 다루었던 open 명령을 이용하는 것이다. 다음 예는 stdio.h에서 printf 라는 단어가 나오는 모든 줄을 test라는 파일로 저장하는 것을 보인다.
set in [open /usr/include/stdio.h r]
set out [open {| grep printf > test} w]
while {[gets $in line] >= 0} {
puts $out $line
}
close $out
close $in
open 명령에 사용될 수 있는 파이프(pipe)나 입출력 재지정(redirection)을 위해 사용할 수 있는 기호에는 >>파일명(출력을 기존 파일에 덧붙임), >@파일id(파일id로 출력), >&파일명(표준출력과 표준에러를 파일로 보냄), 2>파일명(파일로 표준에러를 보냄), <파일명(파일로부터 표준입력을 받음), <<값(값으로부터 표준입력을 받음), <@파일id(파일id를 통해 표준입력을 받음) 이 있다. 이 기호들은 exec에서도 사용할 수 있다.
exec find / -name core -exec rm -f "{}" ; 2> /dev/null > result
find를 실행하게 되면 유저 권한으로는 들어갈 수 없는 디렉토리가 종종 있다. 그래서 이럴 때 뜨는 에러 메시지를 모아서 /dev/null로 보내는 방법을 이용한다. find의 실행 결과는 result라는 파일로 모은다.
close하기 전에 pid $out을 실행해보면 grep 프로세스의 프로세스 id가 출력된다. 그리고 pid라고 실행하면 현재 Tcl 스크립트나 tclsh의 프로세스 id가 출력된다.
프로세스를 종료할 때, exit를 통해서 상태값(status)을 반환할 수 있는데, 기본 상태값은 0이다. 물론 exit 명령 자체의 결과값은 없다.
4) 스크립트 실행하기
source 명령을 이용하면 C shell의 source 명령처럼 Tcl 스크립트를 불러다가 실행할 수 있다.
source /usr/local/lib/tcl8.1/history.tcl
5장 에러와 예외사항(exception)
에러(error)라는 표현은 독자들도 많이 알고 있을 것이지만, 예외사항(exception)은 Java가 널리 퍼지기 전에는 프로그래밍 이론 과목에서나 접했을 법한 용어이다. 예외사항은 아주 간단하게 말하면 에러의 상위집합(superset)이다. 다시 말해서 에러는 예외사항의 부분집합이다. 에러라고 하기에는 큰 문제가 발생한 것은 아니고 그렇다고 정상 종료도 아닌 결과가 예외사항이 되는 것이다.
예외사항은 Java에서처럼 발생시키는 것과 그것을 잡아서 처리한다는 개념이 존재하는데, 에러나 예외사항을 발생시키기 위해서는 error 명령와 return 명령을 사용할 수 있다. 반대로 발생한 예외사항을 감지해내기 위해서는 catch 명령을 사용해야 한다.
unset zzz
은 에러가 발생할 것이다. zzz라는 변수를 이전에 선언한 적이 없기 때문이다. 그러나 이렇게 발생한 에러를 잡으려면 다음과 같이 할 수 있다. message 변수를 지정하면 변수에 에러 메시지가 저장된다.
catch {unset x}
catch {unset x} message
에러를 발생시킬 때, 에러 메시지는 반드시 지정해야 하지만, 에러 정보와 에러 코드는 선택하게 되면 Tcl에서 지정해서 사용하는 errorInfo나 errorCode 변수에 저장할 수 있다. error 명령의 문법은 “error 에러메시지 에러정보 에러코드”이다.
error "can't unset the variable: no such variable"
예외사항을 발생시키는 것은 return 명령을 이용하는 것이다. return도 error 명령처럼 에러코드와 에러정보, 에러메시지등을 지정할 수 있는데, 문법은 “return -code 결과값 -errorinfo 에러정보 -errorcode 에러코드 에러메시지”이다. 결과값의 기본값은 0이다. 다음의 예는 전역 변수인 errorInfo와 errorCode를 이용해 return하는 것이다. 프러시져 내에서 실행되는 경우에는 errorInfo와 errorCode를 global 명령을 이용해 지역 변수처럼 사용할 수 있도록 처리해 주어야 한다는 사실을 잊지 않아야 한다.
return -code 4 -errorinfo $errorInfo -errorcode $errorCode
6장 기타
1) 배열
앞에서 Tcl에서의 배열이란 Perl에서의 해시 변수와 비슷하다고 언급한 적이 있다. 배열을 다루는 명령은 문자열 처리 명령처럼 array 명령에 다양한 옵션을 결합시켜서 사용해야 한다. 배열의 키를 모두 찾기 위해서는 names라는 옵션을, 배열의 키의 수를 구하기 위해서는 size 옵션을 사용한다.
array names my_array
array size my_array
배열에 대해서 검색을 할 수도 있는데, 이 때는 다음과 같은 형태로 가능하다. 배열을 만들고, search id를 구해서 배열에 원소가 아직 남아 있는지 검사하고 남아 있으면 매번 키를 구해다가 키를 이용해 배열을 다루게 된다. 검색이 끝나면 search에 관련된 정보를 반환한다.
set my_arr(1) hello
set my_arr(2) world
set my_arr(name) terzeron
set my_arr(age) 25
set search_id [array startsearch my_arr]
while {[array anymore my_arr $search_id]} {
set key [array nextelement my_arr $search_id]
puts $my_arr($key)
}
array donesearch my_arr $search_id
2) 정보(info)와 내부 명령
현재 Tcl 스크립트와 현재 버전의 Tcl/Tk의 정보를 볼 구할 수 있는 명령은 info이다. info 명령의 옵션을 다음과 같이 정리해 보았다.
[HTML]
args 프러시져명 | 프러시져의 아규먼트(argument)를 리스트로 반환한다. |
body 프러시져명 | 프러시져의 몸체 부분을 반환한다. |
cmdcount | 현재 인터프리터(interpreter)에서 사용된 명령의 수를 반환한다. |
commands 패턴 | 실행가능한 명령을 리스트로 반환한다. 패턴을 지정하는 경우에는 매치되는 명령만 반환할 수도 있다. |
complete 명령 | 버전 8에서 추가된 옵션으로 명령이 완전한 명령인가를 검사한다. |
default 프러시져명 아규먼트명 변수명 | 프러시져의 해당 아규먼트가 기본값을 가지는지 검사하여 변수에 결과값을 써준다. |
exists 변수명 | 변수가 존재하는지 검사한다. |
globals 패턴 | 전역 변수의 리스트를 반환한다. 패턴 매치도 가능하다. |
hostname | 현재 프로세스가 실행되고 있는 컴퓨터의 이름을 반환한다. |
level 번호 | 현재 스택(stack)의 레벨를 반환한다. |
library | 현재 Tcl의 라이브러리의 절대 경로를 반환한다. |
locals 패턴 | 지역 변수의 리스트를 반환한다. |
nameofexecutable | 현재 실행 프로그램(tclsh)의 절대경로를 반환한다. |
patchlevel | 패치된 레벨을 반환한다. |
procs 패턴 | 현재 정의되어 있는 프러시져를 패턴 매치하면서 반환한다. |
script | 스크립트의 이름을 반환한다. |
sharedlibextension | 공유라이브러리의 확장자명을 반환한다. |
tclversion | Tcl의 버전을 반환한다. |
vars 패턴 | 현재 사용가능한 변수명의 리스트를 반환한다. 패턴 매치도 가능하다. |
[/HTML]
내부명령으로 사용할 수 있는 것은 rename, time, trace 등이 있다. rename은 변수나 프로시져의 이름을 바꿀 수 있는데, 바꾸는 것 뿐만 아니라 {}로 바꾸어서 사용하지 못하게 제거할 수도 있다. time은 스크립트을 반복 수행하여 그 평균 수행시간을 계산해준다. 다음과 같이 사용할 수 있다.
time test.tcl 300
trace 명령은 변수의 값 변화를 추적할 수 있는 명령이다. 다음의 예를 보면서 설명하도록 하자.
trace variable age w p_age1
trace vinfo age
trace vdelete age w p_age1
이 예는 age라는 변수에 대해서 쓰기 작업이 이루어지면 p_age1이라는 프러시져를 매번 호출하고, age에 대한 trace 정보를 구하고, 추적 작업을 종료하는 것이다.
3) 히스토리(history)
C shell에서와 같이 history 명령을 실행하면 여태까지 실행했던 명령들을 볼 수가 있다.
history
history 명령에 keep 옵션을 주어 특정 개수만큼 히스토리를 유지할 수도 있고, nextid 옵션을 주어 다음 명령이 히스토리에서 몇 번째 명령이 될 것인가를 알아볼 수도 있다. 또한 redo 옵션으로 저장된 명령을 다시 실행할 수도 있다. 히스토리는 substitute 옵션을 통해 아이템을 변경할 수 있다.
history redo
history redo 3
set x helo
history substitute lo llo -1
마지막 명령은 바로 이전 명령행에서 lo를 llo로 바꾸게 하는 것이다. 조심해야 할 것이 하나 있다. 버전 8에서는 이 옵션이 없어지고 대신 change 옵션이 추가되었는데, 이 옵션은 명령행 전체를 치환한다. 비슷한 기능을 하는 add 옵션도 추가되었다. 히스토리를 지우는 clear 옵션도 제공된다.
set x helo
history change {set x hello} -1
!!는 history redo의 단축어로 제공된다. !번호 같은 형식으로도 히스토리를 이용할 수가 있다. substitute대신에 ^old^new와 같은 형식을 이용할 수도 있다. 이런 단축어들은 C shell에 기반한 것이다.
4) 매뉴얼(manual)
tclsh에서는 매뉴얼을 볼 수가 있다. 다른 키워드와 겹치지만 않는다면 man 키워드 로 매뉴얼을 볼 수 있다. 그러나 history만 해도 유닉스의 명령과 같기 때문에 man history로는 Tcl명령인 history를 공부할 수가 없다. 이럴 때는
man -s n history
로 문제를 해결할 수 있을 것이다.
서울대학교 전산과학과 데이타베이스 연구실 조영일
Erlang 관련 URL
Development 2008. 5. 23. 16:50http://www.erlang.org/doc/ (공식 사이트)
http://groups.google.com/group/erlangstudy/web/erlang-otp-r12b-release-highlight (erlang study 관련 구글그룹)
http://tempe.st/2007/05/erlang-ruby-and-php-battle-it-out/
Name mangling in C++
Development/C / C++ 2008. 3. 25. 15:59C 언어는 symbol에서 함수의 이름만으로 찾을 수 있다. 이 것은 C언어가 같은 함수 이름을
사용하는 것을 허용하지 않기 때문인데, C++에서는 다형성으로 인해서 같은 이름을 사용할 수 있다. 그래서 함수이름만으로 찾는 것이 불가능하다.
이런 것을 위해서 내부적으로 함수 이름을 변경해주는데 이것이 name mangling 이다.
다음과 같이 된다.
int foo(int ) {return 1;}
void goo(void) { int i=foo(), j=f(0); }
int _foo_v (int ) {return 1;}
void _goo_i (void) { int i=_foo_i(), j=_foo_v(0); }
참조 : http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B
BFD 라이브러리
Development 2008. 2. 5. 13:51Front-end는 라이브러리 사용자에게 제공되는 Interface이며, Back-end는 특정 오브젝트 파일 형식을 접근할 수 있는 함수와 자료로 이루어져 있다.
아래는 GNU의 BFD Library 의 Document 페이지이다.
http://www.gnu.org/software/binutils/manual/bfd-2.9.1/html_mono/bfd.html