Năm 2008, hồi học cấp 3, mình viết một thư viện cho Turbo Pascal 7.0 tên là TCVN, để chương trình Pascal ở chế độ văn bản hiển thị được chữ Việt và cho người dùng gõ tiếng Việt kiểu Telex hoặc VNI. Tệp TCVN.TPU còn lưu tới nay mang ngày 22/11/2008, chương trình trợ giúp đi kèm mang ngày 16/09/2008.
Thư viện từng được giới thiệu trên vài diễn đàn tin học, trong bài “Nhập xuất tiếng Việt trong Pascal với thư viện TCVN” (một bản chép lại ghi ngày 06/07/2011), kèm bản cài “Turbo Pascal tích hợp thư viện TCVN” do mình đóng gói. Bản cài đó, một tệp .exe cho Windows tải lên ngày 04/05/2011, vẫn còn trên MediaFire. Bài này ghi lại thư viện, kèm một bản lưu để tải về chỉ gồm thư viện, trợ giúp và các ví dụ.
Từ bản 7.3.4, Turbo Pascal (With DOSBox) của Lưu Nguyễn Thiện Hậu cũng tích hợp thư viện này. Trang download.com.vn ghi hơn 200.000 lượt tải Turbo Pascal (With DOSBox), và nút tải ở đó dẫn tới bản cài trên SourceForge. Một bài báo ngày 14/7/2014, nay trên trang Báo Đồng Tháp, viết về phần mềm hỗ trợ học Pascal của hai học sinh lớp 9 Trường THCS Vĩnh Kim; phần mềm dùng thư viện TCVN.TPU để hiển thị tiếng Việt có dấu trong Turbo Pascal.
Tìm lại thư viện này giống một lần khai quật khảo cổ: link tải trong bài giới thiệu cũ đã bị xoá, tệp thư viện nằm trong bộ cài của người khác, còn lệnh ẩn chỉ thấy được khi dịch ngược mã máy. May là có Claude (AI, chạy trong Claude Code) làm phần lớn việc đó cho mình. Tự làm thì mình sẽ mất rất nhiều thời gian, và chắc mình sẽ không làm.
Thư viện có gì
Chương trình khai báo uses tcvn; rồi gọi các thủ tục và hàm sau:
| Tên | Loại | Việc làm |
|---|---|---|
loadfont |
thủ tục | nạp font tiếng Việt TCVN3, xoá màn hình |
unloadfont |
thủ tục | trả lại font của máy |
TCVNInf |
thủ tục | in thông tin tác giả, chờ một phím |
telex(s) |
hàm | đổi chuỗi gõ kiểu Telex thành chữ TCVN3: telex('Tieesng Vieejt') |
vni(s) |
hàm | đổi chuỗi gõ kiểu VNI thành chữ TCVN3: vni('Tie61ng Vie65t') |
ReadT, ReadV |
hàm | nhập một chuỗi, người dùng gõ tiếng Việt kiểu Telex hoặc VNI |
Chương trình trợ giúp TCVNHELP.EXE (cũng chạy trong DOS) mô tả đủ 3 thủ tục và 4 hàm này:
Xem các trang khác của TCVNHELP.EXE
Ví dụ
program ViDu;
uses crt, tcvn;
var s: string;
begin
loadfont; { nap font TCVN3, xoa man hinh }
writeln(telex('Ddaay laf moojt dofng tieesng Vieejt'), ' (Telex)');
writeln(vni('D9a6y la2 mo65t do2ng tie61ng Vie65t'), ' (VNI)');
writeln;
write(telex('Gox moojt caau'), ' (Telex): ');
s := readt; { go Telex, nhan ve chuoi TCVN3 }
writeln(telex('Bajn vuwfa gox: '), s);
readln;
unloadfont; { tra lai font cua may }
end.
tooi hojc laajp trifnh.Xem VIDU.PAS trong trình soạn thảo Turbo Pascal 7.0
Ví dụ này cho thấy hai giới hạn của thư viện:
- Dấu phải gõ liền sau nguyên âm:
chafora “chào”, cònchaofra “chaò”;moojtra “một”, cònmootjra “môtj”. Bộ gõ ngày nay như JOKey cho gõ dấu ở cuối chữ. telex()đổi mọi chữ, kể cả chữ tiếng Anh:telex('Telex')ra “Telẽ”, và gõpascalquaReadTra “pácal”. Thư viện chưa có kiểm tra chính tả, nên trong ví dụ chữ “Telex” được để ngoài lời gọitelex().
Thư viện hiển thị tiếng Việt thế nào
Ở chế độ văn bản 80×25, màn hình là 2.000 ô, mỗi ô lưu một byte mã ký tự và một byte màu, ở địa chỉ B800:0000. Hình của từng mã ký tự lấy từ một bảng font 256 hình chữ trong card VGA. loadfont gọi ngắt 10h với AX = 1100h để nạp 256 hình chữ 8×16 của thư viện vào bảng đó. Các mã từ 128 tới 255 khi đó mang hình chữ Việt theo bảng mã TCVN3, nên chương trình chỉ cần in các byte TCVN3 là ra chữ Việt. unloadfont gọi AX = 1104h để nạp lại font 8×16 có sẵn của máy.
Font dài 4.096 byte (256 hình chữ × 16 byte), nằm trong tệp TCVN.OBJ được liên kết vào unit. Theo trí nhớ của mình, các hình chữ Việt trong font được trích từ VietRes, bộ gõ tiếng Việt cho DOS của Seatic. Bản VietRes đi kèm Turbo Pascal (With DOSBox) bị nén bằng PKLITE, nên chưa so được từng byte.
Trước khi nạp font, loadfont chuyển sang chế độ đồ hoạ 13h rồi về chế độ văn bản 03h. Trên Windows XP, chương trình DOS chuyển sang chế độ đồ hoạ thì cửa sổ dòng lệnh chuyển sang toàn màn hình; có lẽ vì vậy mà trợ giúp gốc ghi rằng loadfont “đưa về chế độ toàn màn hình (full screen)”. Trong DOSBox, font hiện trong cửa sổ như bình thường.
Dịch ngược TCVN.TPU, loadfont làm những việc sau (viết lại bằng Pascal, tên biến lấy từ bảng ký hiệu của unit):
function ReadChar(x, y: byte): char; { mem[$B800 : (y-1)*160 + (x-1)*2] }
function ReadLine(y: byte): string; { 79 ký tự của dòng y }
procedure Loadfont;
var regs: Registers; show_inf: boolean; i: byte;
begin
show_inf := false;
for i := 1 to 25 do
if Pos('author', ReadLine(i)) > 0 then begin show_inf := true; break; end;
{ int 10h với AX = 13h rồi AX = 03h: đặt lại chế độ văn bản 80x25 }
regs.ax := $1100; regs.bx := $1000; { nạp font, 16 byte mỗi hình chữ }
regs.cx := 256; regs.dx := 0; { 256 hình chữ, từ mã 0 }
regs.es := Seg(font); regs.bp := Ofs(font);
Intr($10, regs);
if show_inf then begin TCVNInf; ClrScr; end;
end;
Lệnh ẩn in thông tin tác giả
Có hai cách để thư viện in thông tin tác giả:
- Gọi thẳng
TCVNInf. Thủ tục này có trongTCVNHELP.EXE, nhưng bài giới thiệu thư viện trên diễn đàn và trang trợ giúp của Turbo Pascal (With DOSBox) đều không nhắc tới nó. - Để chữ
authorhiện ở bất kỳ đâu trên màn hình rồi gọiloadfont. Không tài liệu nào ghi cách này: nó chỉ nằm trong mã củaloadfontở trên.
program Author;
uses crt, tcvn;
begin
clrscr;
while keypressed do readkey; { bo phim con trong bo dem }
writeln('author');
loadfont; { thay "author" -> TCVNInf, roi xoa man hinh }
writeln(telex('Xin chafo, ddaay laf thuw vieejn TCVN.'));
readln;
unloadfont;
end.
loadfont thấy chữ "author" và gọi TCVNInf (ngày sinh và email được làm mờ trong ảnh).
loadfont xoá màn hình và chương trình chạy tiếp.Dòng while keypressed do readkey; để bỏ các phím còn sót trong bộ đệm bàn phím. Nếu bộ đệm còn một phím, ReadKey trong TCVNInf nhận phím đó, và màn hình thông tin tác giả biến mất trước khi kịp đọc.
Tìm lại bằng dịch ngược
Mình chỉ nhớ là đã giấu một lệnh in thông tin tác giả trong thư viện, không nhớ là lệnh gì. Claude tìm lại lệnh đó qua các bước dưới đây; mình chỉ đưa yêu cầu và trả lời vài câu hỏi (các prompt nằm ở cuối bài).
- Link tải trong bài giới thiệu cũ đã bị xoá. Bài “Một số điều có thể bạn chưa biết về Turbo Pascal” trên congnghevadoisong.vn (25/06/2012) còn link MediaFire của bản cài gốc, nhưng lúc đó máy của Claude bị chặn truy cập MediaFire. Sau khi mình mở chặn, Claude tải bản cài gốc về:
TCVN.TPUvàTcvnHelp.EXEtrong đó giống từng byte với hai tệp lấy từ Turbo Pascal (With DOSBox) ở bước 2. - Bản cài Turbo Pascal (With DOSBox) 7.3.5 là một tệp
.msi(tệp OLE compound file). Bên trong có một tệp cabinet nén kiểu MSZIP chứa 278 tệp, trong đó cóTCVN.TPUvàTCVNHELP.EXE. Scriptextract-tp7.pytrong bản lưu đọc cả hai định dạng này bằng thư viện chuẩn của Python. - Tệp
.TPUcủa Turbo Pascal 7.0 bắt đầu bằng chữ kýTPUQ, và giữ nguyên tên các ký hiệu. Phần interface có 7 tên:Loadfont,UnLoadfont,TCVNInf,telex,vni,ReadT,ReadV. Tiếp theo là các tên nội bộ nhưReadChar,ReadLine,font,show_inf. - Mã máy bắt đầu ở offset
0xC00. Mỗi thủ tục là một code segment riêng, theo một bảng 15 mục ở offset0x783. Mỗi lời gọi tới thủ tục khác được ghi trong một bảng fixup, 8 byte mỗi mục: unit, loại, đích, độ lệch, vị trí trong segment. - Segment của
loadfontmở đầu bằng hằng chuỗi Pascal06 'author'. Lời gọi cuối cùng trong segment này có fixup trỏ vào mục thứ 3 của bảng thủ tục, tứcTCVNInf. Các chuỗi thông tin tác giả nằm ở đầu segment củaTCVNInf, lưu bằng mã TCVN3. - Cuối cùng, Claude biên dịch hai ví dụ ở trên bằng
TPC.EXE7.0 và chạy trong DOSBox để kiểm tra.
Xem mã máy đầu tiên của loadfont
0007 55 push bp
0008 89 e5 mov bp, sp
...
0016 c6 46 ea 00 mov byte [bp-0x16], 0 ; show_inf := false
001a c6 46 eb 01 mov byte [bp-0x15], 1 ; i := 1
...
0023 bf 00 00 mov di, 0 ; fixup: hằng 'author' ở đầu segment
...
0032 e8 00 00 call ReadLine ; fixup: thủ tục nội bộ của TCVN
0035 9a 00 00 00 00 call far Pos ; fixup: System
003a 09 c0 or ax, ax
003c 7e 06 jle +6
003e c6 46 ea 01 mov byte [bp-0x16], 1 ; show_inf := true
...
0044 80 7e eb 19 cmp byte [bp-0x15], 25 ; hết 25 dòng?
004a b8 13 00 mov ax, 13h
004d cd 10 int 10h ; chế độ đồ hoạ 320x200
004f b8 03 00 mov ax, 03h
0052 cd 10 int 10h ; về chế độ văn bản 80x25
0054 c7 46 ec 00 11 mov word [bp-0x14], 1100h ; regs.ax: nạp font
...
007c 9a 00 00 00 00 call far Intr ; fixup: Dos
0081 80 7e ea 00 cmp byte [bp-0x16], 0 ; show_inf?
0085 74 09 je +9
0087 0e push cs
0088 e8 00 00 call TCVNInf ; fixup: mục 3 của bảng thủ tục
008b 9a 00 00 00 00 call far ClrScr ; fixup: Crt
Tải về
tcvn-pascal.zip (24 KB) gồm:
TCVN.TPU: thư viện, giống từng byte với tệp trong bản cài gốc năm 2011 và trong Turbo Pascal (With DOSBox) 7.3.5;TCVNHELP.EXE: chương trình trợ giúp gốc;VIDU.PAS,INFO.PAS,AUTHOR.PAS: ba ví dụ trong bài;tools/extract-tp7.py: chép Turbo Pascal 7.0 ra từ bản cài Turbo Pascal (With DOSBox);tools/tpudis.py: dịch ngược một code segment của tệp.TPU(cầnclangvàobjdump);README.txtvàSHA256SUMS.txt.
Gói không kèm Turbo Pascal 7.0, vì đó là phần mềm của Borland. TCVN.TPU chỉ dùng được với Turbo Pascal 7.0, nên cần lấy trình biên dịch từ bản cài Turbo Pascal (With DOSBox) như hướng dẫn dưới đây, hoặc từ bản Turbo Pascal 7.0 bạn đang có.
SHA-256 của tệp zip: e72f2d6e80a6066c03456fff973419e8aa3dc3fd51dc19b90b06e0a568d70020
Chạy thử bằng DOSBox
macOS
Claude đã chạy thử các bước này trên máy Mac của mình (macOS 26):
-
Cài DOSBox Staging:
brew install dosbox-staging -
Tải
TP(WDB)-7.3.5-Setup.msitừ trang SourceForge của Turbo Pascal (With DOSBox). -
Giải nén
tcvn-pascal.zip, mở Terminal trong thư mụctcvn-pascal, rồi chép Turbo Pascal 7.0 ra từ bản cài:python3 tools/extract-tp7.py ~/Downloads/TP\(WDB\)-7.3.5-Setup.msi -
Biên dịch và chạy ví dụ:
dosbox-staging -c "mount c ." -c "c:" -c "tpc vidu.pas" -c "vidu"Hoặc mở trình soạn thảo Turbo Pascal (Ctrl+F9 để chạy, Alt+X để thoát):
dosbox-staging -c "mount c ." -c "c:" -c "turbo vidu.pas"Xem trợ giúp gốc của thư viện:
dosbox-staging -c "mount c ." -c "c:" -c "tcvnhelp"
Windows
Các bước này chưa được thử trên Windows.
-
Cách đơn giản nhất: cài Turbo Pascal (With DOSBox) từ 7.3.4 trở lên. Bản này đã tích hợp thư viện TCVN, chỉ cần khai báo
uses tcvn;. -
Cách giống macOS: cài DOSBox Staging và Python 3, tải bản cài
.msinhư trên, rồi trong thư mụctcvn-pascalchạy:py tools\extract-tp7.py "%USERPROFILE%\Downloads\TP(WDB)-7.3.5-Setup.msi" dosbox -c "mount c ." -c "c:" -c "tpc vidu.pas" -c "vidu"dosbox.exenằm trong thư mục cài DOSBox Staging.
Liên quan
Mười tám năm sau, mình vẫn làm bộ gõ tiếng Việt, giờ là JOKey cho macOS: bài Làm bộ gõ tiếng Việt cho macOS kể về nó, từ engine tới cách gõ vào từng app.