2009-12-11

tcllib 1.12 is out

這個消息已經晚了幾天(1.12 在 2009/12/08 已經 release 了),不過因為我是到現在才知道,所以還算是「新」消息吧。

官方網站還沒有更新,但是 SourceForge 檔案列表上已經有放上去檔案了。

Read Me 上的 Overview:

72 new packages in 10 modules
46 changed packages in 25 modules
14 internally changed packages in 12 modules
166 unchanged packages in 65 modules
301 packages, total in 95 modules, total

有趣的是,我看到有一個 coroutine package 包含在 1.12 這次的 release 裡,這需要 Tcl/Tk 8.6 或者是更高的版本才可以使用。

2009-10-25

更新 Windows 平台環境: 使用 ActiveTcl 8.6 beta-2

Active Tcl 8.6 Beta

我發現 Active Tcl 更新了安裝檔案,所以也跟著更新了。這次的更新也更新了原本附帶的套件到目前的最新版(例如說 VFS),所以我已經昇級到這個版本了。

注意:這一版的 code base 仍然是 Tcl/Tk 8.6 beta 1,可以算是針對一些套件做 upgrade 的吧。

2009-10-23

清除掉 Visual C++ 2008 Express 最近使用的專案列表

package require registry

label .show -text "Below is the list:"
grid .show -row 0 -column 0 -columnspan 2 -pady 3 -ipady 1

set count 0
set rootKey "HKEY_CURRENT_USER\\Software\\Microsoft\\VCExpress\\9.0\\ProjectMRUList"

foreach id [registry values $rootKey] {
if {[string length $id] >= 4} {
set text [registry get $rootKey $id]
ttk::checkbutton .$count -text $text -variable check($id)
grid .$count -column 0 -columnspan 4 -ipady 1 -sticky nsew
set check($id) 0
incr count 1
}
}

proc doClean {} {
foreach id [registry values $::rootKey] {
if {[string length $id] >= 4} {
if {$::check($id) == 1} {
registry delete $::rootKey $id
}
}
}

exit
}

# Let our button in next row
incr count 1

button .exit -text "Exit" -command exit
grid .exit -column 2 -row $count -pady 3 -ipady 1 -sticky nsew
button .clean -text "Clean" -command doClean
grid .clean -column 3 -row $count -pady 3 -ipady 1 -sticky nsew
使用 checkbutton 建立列表,讓使用者選擇要清除最近使用的專案列表中的哪一個。我們使用一個陣列記住目前使用者的選擇,如果使用者按 Clean,就去清掉使用者所選擇的那些項目。

Geometry Manager 使用 grid 來管理。

2009-10-10

tDom and TclXML

Tcl 是個極容易擴充的語言(並且因此影響到後面出現或者是同期的 scripting language),在處理 XML 方面,有二個主要的套件:

我會比較偏好 tDom,因為他雖然是用 C 實作,而且在架構上沒有 TclXML 的野心那麼大,但是 tDom 在管理上比較簡單(只有一個套件),不像 TclXML/TclDOM 需要好幾個套件組合起來、而且 TclDOM 隨著各個實作的不同,能力也不同(pure Tcl, Expat, libxml2)。

更多資料:TclDOM vs tDOM

TDBC 1.0 b13 已經包含 tdbc::postgres

我發現 TDBC PostgreSQL driver 已經完成了,所以小小的測試了一下(使用 PostgreSQL 8.4.1):
package require tdbc::postgres
tdbc::postgres::connection create db -user danilo -password test -port 5432

set statement [db prepare {
SELECT VERSION()
}]

$statement foreach row {
puts [dict get $row version]
}

$statement close
db close
沒錯,確實已經可以運作了,而 tdbc::postgres 主要是透過 libpg 來實作的。

另外,TDBC 同時也包含了 Oracle 的 driver,但是這一個我就沒有測試了。

2009-09-22

刪除 Adobe Flash Sol 記錄

看到 Adobe Flash 用戶: 請笑一個給世界看, 您上鏡頭了! 以後,因為不知道怎麼樣在 IE8 上讓 Flash 可以正常使用但是又不會使用 Sol 記錄使用者的一些資訊,所以我寫了一個 tcl script 來嘗試刪除這些記錄,下面就是我寫的 script:
set SolFile [set env(USERPROFILE)]
append SolFile {\Application Data\Macromedia}

if {[file exist $SolFile]==1} {
file delete -force $SolFile
}
使用了大絕招(加上參數 -force)來刪除目錄以及其中的所有檔案,這樣就可以半自動的刪除掉這些試圖記錄的資訊。如果有其它的需要或者是需要再增加其它的目錄進行刪除,只要修改一下就 OK 了。

2009-09-20

Eagle

The Eagle Project


Eagle (Extensible Adaptable Generalized Logic Engine) is an implementation of the Tcl scripting language for the Common Language Runtime (CLR).

這是個仍然在發展中的案子,把 Tcl 搬到 .NET 的世界了。

2009-09-15

Tcl and the Tk Toolkit Second Edition is out

根據 comp.lang.tcl 的消息,有人已經收到來自於 Amazon 的實體書了,所以已經正式開賣並且已經開始供貨,但是不知道台灣目前的進口情況,因為博客來和天瓏目前都是處於沒有進口(或許該說沒有東西可以供使用者訂購)的狀況。

雖然沒有加入 8.6 的 OO (物件導向)或者是其它的改進有點可惜,但是按照目前 8.6 的發展情況來看,加入的結果將會使這本書的出版更為難產,我想將版本放在 8.5 是個合理的決定。

目前和 Amazon 的書評綜合看起來,都是比較正面的評價,所以我想第二版仍然維持了清楚並且組織良好的風格,it is a good news.

Update:
2009/10/20 天瓏已經開始賣了,我已經拿到書了。

2009-09-13

優雅的關閉程式

在 Windows 平台下,ActiveTcl 預設是使用 wish.exe 來開啟 .tcl 檔案,如果直接執行不需要 tk 的程式,往往會留下一個 wish window。

解決的方法很簡單,在最後使用 exit 關閉程式就可以了:
exit

這樣就可以優雅的關閉程式而不會留下一個 wish window --- 即使是用 wish.exe 開啟的。

2009-09-09

Tcl and the Tk Toolkit (2nd Edition)



John K. Ousterhout’s Definitive Introduction to Tcl/Tk–Now Fully Updated for Tcl/Tk 8.5

Paperback: 816 pages
Publisher: Addison-Wesley Professional; 2 edition (September 12, 2009)
ISBN-10: 032133633X
ISBN-13: 978-0321336330
光是作者的名字 (John K. Ousterhout and Ken Jones ) 就讓人想要買這本書了啦,但是目前天瓏提供的日期
2009/09/142009/09/29(而且還不確定)。原本在 2005 年就已宣佈有計畫更新為第二版,但是直到現在才又有新的消息。
在 Tcler's Wiki 上也有相關的訊息

2009-09-05

Download and Uncompress zip file

在使用的過程裡,我發覺 vfs 1.4.0 應該是有 bug 的,如果要使用 vfs::zip 來解壓縮,要把版本昇到 1.4.1 才行。

下面是從臺灣證券交易所下載檔案,然後使用 vfs::zip 解壓縮的範例:

#!c:/tcl/bin/tclsh86.exe
package require http
package require vfs::zip

########################################################################
# Now download file from network
########################################################################

set day [clock format [clock seconds] -format {%d}]
set now [clock seconds]

if {$day > 7} {
set value [clock format [clock add $now -30 day] -format {%Y%m}]
} else {
set value [clock format [clock add $now -60 day] -format {%Y%m}]
}

set remoteFile "http://www.twse.com.tw/ch/statistics/download/04/001/"
append remoteFile $value
append remoteFile "_C04001.zip"

puts "======================================================"
puts "URL: $remoteFile"

set localFile $value
append localFile "_C04001.zip"

puts "Download File name: $localFile"
puts "======================================================"

set token [::http::geturl $remoteFile -binary 1]
set data [::http::data $token]

set channel [open $localFile w+]
fconfigure $channel -encoding binary -translation binary
puts -nonewline $channel $data
close $channel

::http::cleanup $token

########################################################################
# Now handle zip file
########################################################################

set mnt_file [vfs::zip::Mount $localFile $localFile]
file copy -force [glob $localFile/*] ./
vfs::zip::Unmount $mnt_file $localFile
file delete $localFile
幫朋友寫的,這樣再做一些適當的設定就可以定時下載最近的企業月報,而季報也可以比照辦理。

2009-08-02

在命令列呼叫 OpenOffice.Org Basic 巨集

這不只可以用 Tcl/Tk 來做到,只是我最習慣 Tcl/Tk 來做這些事情。

OpenOffice.Org Basic 寫的程式:
REM ***** BASIC *****

Option Explicit

Sub AutoFindGoodMan(cFile)
Dim Doc As Object
Dim Dummy()

Dim Sheet As Object
Dim Cell As Object
Dim Cell2 As Object
Dim Cell3 As Object
Dim Cell4 As Object
Dim Count As Integer

Doc = StarDesktop.loadComponentFromURL(ConvertToUrl(cFile), "_default", 0, Dummy())

Sheet = Doc.Sheets(0)

dim document as object
dim dispatcher as object
rem ---------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Zoom.Value"
args1(0).Value = 100
args1(1).Name = "Zoom.ValueSet"
args1(1).Value = 28703
args1(2).Name = "Zoom.Type"
args1(2).Value = 0
dispatcher.executeDispatch(document, ".uno:Zoom", "", 0, args1())

For Count = 66 To 841 Step 1
Cell = Sheet.getCellByPosition(0, Count)
IF Cell.Value > 1000 Then
Cell.CellBackColor = RGB(0, 0, 255)
Cell2 = Sheet.getCellByPosition(3, Count)
Cell3 = Sheet.getCellByPosition(5, Count)
Cell4 = Sheet.getCellByPosition(7, Count)

IF Cell3.Type = com.sun.star.table.CellContentType.EMPTY Then
IF Cell4.Value = 0.00 Then
Cell3.CellBackColor = RGB(255, 0, 0)
Cell4.CellBackColor = RGB(255, 0, 0)
ENDIF
ELSE
IF Cell3.Value < 9 AND Cell4.Value > 5 Then
IF Cell2.Value <= 15 Then
Cell2.CellBackColor = RGB(255, 255, 0)
ELSEIF Cell2.Value > 15 AND Cell2.Value <= 40 THEN
Cell2.CellBackColor = RGB(0, 255, 0)
ELSEIF Cell2.Value > 40 THEN
Cell2.CellBackColor = RGB(0, 255, 255)
END IF

Cell3.CellBackColor = RGB(0, 255, 0)
Cell4.CellBackColor = RGB(0, 255, 0)
ELSEIF Cell3.Value >= 80 Then
Cell3.CellBackColor = RGB(0, 255, 255)
End IF
End IF
End IF
Next Count

If (Doc.isModified) Then
If (Doc.hasLocation And (Not Doc.isReadOnly)) Then
Doc.store()
End If
End If


Doc.close(True)

End Sub

而可以用 Tcl/Tk 執行 soffice.exe,來幫我們自動執行這件事:

set DIR [pwd]
set DOCS [glob *.xls]

foreach file $DOCS {
set inputFile $DIR
append inputFile "/" $file
set exeList [list "C:\\Program Files\\OpenOffice.org 3\\program\\soffice.exe" "macro:///Standard.Module1.AutoFindGoodMan($inputFile)"]
exec {*}$exeList
}


但是我還沒有摸索出來在執行的時候不要顯示出來 OpenOffice.Org 文件視窗的方法,不論是使用命令列指定,或者在執行時設定的方式,都是沒有效果的(有可能是因為我沒有設定正確吧……)。

2009-07-30

執行程式

Tcl 使用 exec 來執行外部程式:

set var [list rundll32.exe shell32.dll,Control_RunDLL timedate.cpl,@0,2]
exec {*}$var

這裡使用 {*} 和 exec 結合的範例。

2009-07-17

math function

在 Tcl 8.5 以前,Tcl 的數學運算都是透過 expr 這個 command 做到的,而在 8.5 則引進了 tcl::mathfunc,讓使用一些數學運算的 function 上可以更直覺,使用上也更簡單。

如果不想寫一堆很長的 name space path,可以這樣做:

namespace path {::tcl::mathop ::tcl::mathfunc}
所以我們就可以這樣做:

srand [clock seconds]
這樣不管是撰寫程式還是讀 code 的時候,看起來都比較具可讀性。


另外,8.5 同時也 export 出來一些運算子(tcl::mathop)。
puts [* [sqrt 49] [+ 1 2 3]]
也就是,看起來會是類似 lisp 的前序式運算法。

2009-07-16

Access global variables in proc

在 procedure 裡存取全域變數,有二種做法:

1. 使用 global 命令宣告要存取的全域變數
2. 在 Tcl 支援 name space 之後,可以使用 name space 的表達方式(::)來存取變數
set x 0

proc appendMe {number} {
global x
incr x $number
}

proc appendMe2 {number} {
incr ::x $number
}

appendMe 3
puts $x

上面就是這二種方式的說明。

2009-07-15

Tcl/Tk 與編碼 (Encoding)

關於 Tcl 的編碼,可以分為二部份,一部份是 Tcl/Tk 直譯器本身支援的編碼,一部份是使用者的 Tcl script file 所使用的編碼。

首先是使用者的 Tcl script file 所使用的編碼,可以用下列的方法來指定:
tclsh.exe -encoding [編碼方式] [檔案]
wish.exe -encoding [編碼方式] [檔案]

我們可以使用下面的方式來查詢目前 Tcl/Tk直譯器本身所支援的編碼方式:
encoding names

例如用 Tclkit 來查詢,就可以得到他目前支援的編碼方式:
iso8859-2 iso8859-15 utf-8 ascii cp1252 macRoman koi8-r identity unicode iso8859-1

所以 Tclkit 不支援 BIG5... 如果需要的話要自己加上去。

2009-07-11

GetHomeDir

在 Windows,我們可以透過謮取 registry 和環境變數拿到使用者的 My Documents. 下面是來自於 Tcler' Wiki 的 code,只是我自己有小修改一些,好符合我自己的環境。
proc GetHomeDir { } {
global env

# Check if we're using windows
if { [expr [string compare "$::tcl_platform(platform)" "windows" ] == 0] } {
package require registry 1.0

set env_home [registry get {HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders} {Personal}]
set userprofile [set env(USERPROFILE)]
regsub -all {[%]USERPROFILE[%]} $env_home $userprofile env_home
} else {
set env_home $env(HOME)
}

return $env_home
}

另外,如果要刪除 Opera 在 UserProfile 下的 cookie,可以這樣做:
set CookieFile [set env(USERPROFILE)]
append CookieFile {\Application Data\Opera\Opera\profile\cookies4.dat}

if {[file exists $CookieFile]==1} {
file delete $CookieFile
}

因為 AVG 會對這裡一直警告(即使我關掉 Cookie),所以要寫一個小程式殺掉檔案,避免他一直警告(不過話說回來,我已經不用 AVG 了)。

2009-06-28

GIF photo images written with LZW compression

Tk 在 8.6 除了加入 PNG 格式的支援,同時因為 LZW 演算法專利已經過期,所以 Tk 8.6 也會加入 GIF photo images written with LZW compression 的支援。
下面是一些資訊:
"Unisys U.S. LZW Patent No. 4,558,302 expired on June 20, 2003, the counterpart patents in the United Kingdom, France, Germany and Italy expired on June 18, 2004, the Japanese counterpart patents expired on June 20, 2004 and the counterpart Canadian patent expired on July 7, 2004."
IBM 也握有 LZW 的專利,但是根據 GNU GIF 的網頁,IBM 的專利也將於 2006/10 到期,也就是說,實作的人將不用擔心觸碰到 LZW 專利地雷。
雖然我們有了 PNG,但是能夠使用 GIF 也不錯。

2009-06-27

Scripting: Higher Level Programming for the 21st Century

這是由 John K. Ousterhout 所寫的文章,而從現在 PHP/Perl/Python/Ruby/Tcl 各種 scripting language 的發展來看,似乎也是如 John K. Ousterhout 所推測的一樣。當然,自由軟體所帶來的效應,可能也是其中的一個原因之一。

Scripting language 的缺點就是慢,但是開發快速而且除錯方便,但是當硬體的速度愈來愈快的時候,Scripting language 的缺點也就不太算是缺點了,各種 Scripting language 只會愈來愈重要。

2009-06-25

Try/Catch/Finally syntax

Tcl 原本就有錯誤處理的機制(使用 catch),而在 TIP #329  (in 8.6 b1)又加入了類似 Try/Catch/Finally 來增強原本的機制。
proc read_hex_file {fname} {
set f [open $fname "r"]
set data {}
try {
while { [gets $f line] >= 0 } {
append data [binary format H* $line]
}
} trap {POSIX} {} {
puts "POSIX-type error"
} on error {em} {
error "Could not process file '$fname': $em"
} finally {
close $f
}
}
也就是說,原本 catch 是執行如果出錯,那就依據取得的 error code,再來判斷怎麼處理;而 try/finally 則是如果發生錯誤,會依據 error code 而把程式的流程流向該處理這個錯誤的 error handler,因此整個 code 如果寫的好會看起來比較清晰。對於錯誤的處理策略看起來比較清晰。

2009-06-24

SQLite and PostgreSQL

雖然 Tcl 在 8.6 終於加入了 TDBC,但是目前只有支援 SQLite, MySQL 等少數的資料庫,而沒有支援 PostgreSQL

PostgreSQL 有提供 Tcl 的介面(只是不是使用 TDBC API,而是 specify for PostgreSQL 的),而且需要自己去網站下載相關的檔案。

Google Student Summer 計畫裡,關於 Tcl 的部份,有看到關於 TDBC-PostgreSQL 的部份,只是不知道目前的進度怎麼樣了。

對我而言,SQLite 是單機使用的最佳選擇,而 PostgreSQL 雖然在 Open Source 界使用聲勢上弱於 MySQL,但是我還是最喜歡使用他(好吧,雖然現在因為沒有在寫關於網路和 WEB 的應用,所以沒有在用他了)。 而在甲骨文併購昇陽之後,MySQL 的前途變成了一件不明確的事情(雖然甲骨文不太可能就這樣壞掉自己的聲譽,所以囉),因此版權和 source code 所有權明確的 PostgreSQL 是一個好選擇,特別是當 PostgreSQL 的可靠度其實很可怕的時候(台灣的中鋼就是使用 PostgreSQL 哦)。

However,如果 TDBC-PostgreSQL 出來了,我會稍微測試一下相關的東西,看看這個 TDBC-PostgreSQL driver 的情況,如果有東西給我修改,對我而言比從零開始好,所以我已經放棄了一開始的想法,先從熟悉 TDBC 的方向著手。

另外,在 TDBC 之後,[Incr Tcl] 4.0(這個版本使用 TclOO 全部改寫)已經進入 Tcl core code,將會以 package 的方式存在,在 8.6 beta 2 就會進去了,所以 8.6 beta 2 出來的時候,我也會看看這部份的情況。

看起來 Tcl/Tk 8.6 將會是一個巨大的改版,不管是物件導向套件的引入(TclOO/iTcl),或者是資料庫 API 的統一(TDBC),甚至是引入 zlib 與 png 的支援,都將深刻的改變這個語言,同時也讓這個語言更好用更強壯。

A Slightly Skeptical View on Scripting Languages

A Slightly Skeptical View on Scripting Languages

一篇對於 Scripting Language 的文章。

比較語言的差異與優缺點是浪費時間,因為每個語言都有其優缺點,挑順手的就好了(除非是因為 project 還是 Boss 要求)。

不過就算是現在,我還是覺得 Tcl 很棒(雖然用的人沒有很多),因為 Tcl 的語言規則很簡單但是卻又變化無窮,John Ousterhout 真的好強啊~~~

Tkhtml v3

TkHTML

Tkhtml 是個通過 ACID2,for Tk 可以用來顯示 HTML/CSS 內容的 widget。

下面是在 Tcler's Wiki 上示範使用 Tkhtml 做出一個 Label widget 的範例:
package require Tkhtml 3.0

# Create and populate an html widget.
html .label -shrink 1
.label parse -final {
<b>Hello <i>world</i></b> example
}

# Pack the new html widget
pack .label

bind .label <KeyPress-q> exit
focus .label

Thread and Tcl

package require Thread
catch {console show}

set ::gThread [thread::create {thread::wait} ]

proc printTime { } {
thread::send -async $::gThread { puts stdout [clock format [clock seconds]] }
after 1000 printTime
}

printTime
puts "started test..."

#only needed for tclsh, to keep the interpreter alive and keep the event loop running
vwait forever
在經過一段時間的學習以後,我才慢慢的看懂了 Tcl 的 Thread 擴充套件應該怎麼用才對,相關的資訊可以看 Tcl Threading Model

如果要檢查 tclsh 是不是 build 成支援 thread,則可以用
expr {[info exists ::tcl_platform(threaded)] && $::tcl_platform(threaded)}
來做到。當值為 1 時,表示有支援。

Tcl/TK 8.5 new syntax: {*} 與 Eval

Tcl/Tk 8.5 引進了新的語法 {*},可以用來動態的建立命令執行,可以讓程式看起來更為簡單(使用 eval 會看起來比較複雜)。

我們可以用 Eval 這個指令將參數串接成一個字串後,將字串視為一個 Tcl Script 丟給解譯器去執行。下面是使用 Eval 版:
eval button .b $stdargs -text \$mytext -bd $border

{*} 可以將可以將串列的各個值分開為不同的參數,下面是改寫過後的版本:
button .b {*}$stdargs -text $mytext -bd $border

列出目前的磁碟機

我們可以使用 file 這個 command 來做到這件事,所拿到的是目前磁碟機的 list,下面是範例程式:
set disks [file volumes]

puts "Disks:"
foreach local $disks {
puts " $local --- [file system $local]"
}

在範例中,我們同時也使用了 file system 來取得檔案系統的資料(是 FAT 或者是 NTFS 等資料)。

Tcl/Tk 與 Thread

不知道為什麼,我對於 Thread 總是心存恐懼,雖然我已經懂得避掉一些不好的情況,但是遇上 Thread 總是怕怕的,可能是因為 Thread 非循序的特性讓我覺得無法自在的使用吧?

Tcl/Tk 在自己的 C API 已經有支援 Thread 的 API(編譯的時候要 enable),並且從 8.1 開始就已經是 thread safe 的軟體,而 Thread 這個套件則是讓我們可以透過 Tcl scripting 的方式來操作。

下面是 Tcl C API 關於 Thread 的部份:
Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread

在 Linux/FreeBSD/UNIX 世界裡,通常是遵循 POSIX 標準,所以是使用 PThread,而 Windows 平台則有自己的一套 API,而 Tcl/Tk 已經幫我們建立了一個中介層,所以不用管底層的差異。