14
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
15
**********************************************************************}
21
{*****************************************************************************}
23
{*****************************************************************************}
26
BaseUnix, Strings, TermInfo, termio;
27
type Tencoding=(cp437, {Codepage 437}
31
koi8r, {KOI8-R codepage}
46
const {Contains all code pages that can be considered a normal vga font.
47
Note: KOI8-R has line drawing characters in wrong place. Support
48
can perhaps be added, for now we'll let it rest.}
49
vga_codepages=[cp437,cp850,cp852,cp866];
50
iso_codepages=[iso01,iso02,iso03,iso04,iso05,iso06,iso07,iso08,
51
iso09,iso10,iso13,iso14,iso15];
53
var internal_codepage,external_codepage:Tencoding;
56
{*****************************************************************************}
58
{*****************************************************************************}
60
uses baseunix,termio,strings
61
{$ifdef linux},linuxvcs{$endif};
31
Type TConsoleType = (ttyNetwork,ttyLinux,ttyFreeBSD,ttyNetBSD);
66
type Tconsole_type=(ttyNetwork
67
{$ifdef linux},ttyLinux{$endif}
74
cv_linuxlowascii_to_vga);
77
enter_alt_charset_mode,
78
exit_alt_charset_mode,
82
cursor_visible_underline,
90
Ttermcodes=array[Ttermcode] of Pchar;
91
Ptermcodes=^Ttermcodes;
93
const term_codes_ansi:Ttermcodes=
94
(#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
95
#$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
96
#$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
97
#$1B#$5B#$48, {cursor_home}
99
nil, {cursor visible, underline}
100
nil, {cursor visible, block}
101
nil, {cursor_invisible}
107
term_codes_freebsd:Ttermcodes=
108
(nil, {enter_alt_charset_mode}
109
nil, {exit_alt_charset_mode}
110
#$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
111
#$1B#$5B#$48, {cursor_home}
112
#$1B#$5B#$3D#$30#$43, {cursor_normal}
113
#$1B#$5B#$3D#$31#$43, {cursor visible, underline}
114
#$1B#$5B#$3D#$31#$43, {cursor visible, block}
115
nil, {cursor_invisible}
121
term_codes_linux:Ttermcodes=
122
(#$1B#$5B#$31#$31#$6D, {enter_alt_charset_mode}
123
#$1B#$5B#$31#$30#$6D, {exit_alt_charset_mode}
124
#$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
125
#$1B#$5B#$48, {cursor_home}
126
#$1B'[?25h'#$1B'[?0c', {cursor_normal}
127
#$1B'[?0c', {cursor visible, underline}
128
#$1B'[?17;0;127c', {cursor visible, block}
129
#$1B'[?1c', {cursor_invisible}
135
term_codes_vt100:Ttermcodes=
136
(#$0E, {enter_alt_charset_mode}
137
#$0F, {exit_alt_charset_mode}
138
#$1B#$5B#$48#$1B#$5B#$4A{#$24#$3C#$35#$30#$3E}, {clear_screen}
139
#$1B#$5B#$48, {cursor_home}
141
nil, {cursor visible, underline}
142
nil, {cursor visible, block}
143
nil, {cursor_invisible}
146
#$1B#$5B#$3F#$37#$6C, {exit_am_mode}
147
#$1B#$28#$42#$1B#$29#$30); {ena_acs}
149
term_codes_vt220:Ttermcodes=
150
(#$1B#$28#$30{#$24#$3C#$32#$3E}, {enter_alt_charset_mode}
151
#$1B#$28#$42{#$24#$3C#$34#$3E}, {exit_alt_charset_mode}
152
#$1B#$5B#$48#$1B#$5B#$4A, {clear_screen}
153
#$1B#$5B#$48, {cursor_home}
155
nil, {cursor visible, underline}
156
nil, {cursor visible, block}
157
nil, {cursor_invisible}
160
#$1B#$5B#$3F#$37#$6C, {exit_am_mode}
161
#$1B#$29#$30); {ena_acs}
163
term_codes_xterm:Ttermcodes=
164
(#$0E, {enter_alt_charset_mode}
165
#$0F, {exit_alt_charset_mode}
166
#$1B#$5B#$48#$1B#$5B#$32#$4A, {clear_screen}
167
#$1B#$5B#$48, {cursor_home}
168
#$1B#$5B#$3F#$31#$32#$6C#$1B#$5B#$3F#$32#$35#$68, {cursor_normal}
169
#$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, underline}
170
#$1B#$5B#$3F#$31#$32#$3B#$32#$35#$68, {cursor visible, block}
171
#$1B#$5B#$3F#$32#$35#$6C, {cursor_invisible}
172
#$1B#$5B#$3F#$31#$30#$34#$39#$68, {enter_ca_mode}
173
#$1B#$5B#$3F#$31#$30#$34#$39#$6C, {exit_ca_mode}
174
#$1B#$5B#$3F#$37#$6C, {exit_am_mode}
175
#$1B#$28#$42#$1B#$29#$30); {ena_acs}
178
const terminal_names:array[0..8] of string[7]=(
188
terminal_data:array[0..8] of Ptermcodes=(
199
const convert:Tconversion=cv_none;
34
202
LastCursorType : byte;
36
Console: TConsoleType;
204
Console: Tconsole_type;
205
cur_term_strings:Ptermcodes;
52
can_delete_term : boolean = false;
221
{ can_delete_term : boolean = false;}
53
222
ACSIn : string = '';
54
223
ACSOut : string = '';
55
InACS : boolean =false;
57
function IsACS(var ch,ACSchar : char): boolean;
224
in_ACS : boolean =false;
226
function convert_vga_to_acs(ch:char):word;
228
{Ch contains a character in the VGA character set (i.e. codepage 437).
229
This routine tries to convert some VGA symbols as well as possible to the
230
xterm alternate character set.
232
Return type is word to allow expanding to UCS-2 characters in the
238
convert_vga_to_acs:=word('|');
240
convert_vga_to_acs:=word('^');
242
convert_vga_to_acs:=word('v');
65
243
#26, #16: {Never introduce a ctrl-Z ... }
67
{#27,needed in Escape sequences} #17: {}
244
convert_vga_to_acs:=word('>');
246
convert_vga_to_acs:=word('<');
69
247
#176, #177, #178: {���}
248
convert_vga_to_acs:=$f800+word('a');
74
249
#180, #181, #182, #185: {����}
250
convert_vga_to_acs:=$f800+word('u');
79
251
#183, #184, #187, #191: {����}
252
convert_vga_to_acs:=$f800+word('k');
84
253
#188, #189, #190, #217: {����}
254
convert_vga_to_acs:=$f800+word('j');
89
255
#192, #200, #211, #212: {����}
256
convert_vga_to_acs:=$f800+word('m');
94
257
#193, #202, #207, #208: {����}
258
convert_vga_to_acs:=$f800+word('v');
99
259
#194, #203, #209, #210: {����}
260
convert_vga_to_acs:=$f800+word('w');
104
261
#195, #198, #199, #204: {����}
262
convert_vga_to_acs:=$f800+word('t');
264
convert_vga_to_acs:=$f800+word('q');
266
convert_vga_to_acs:=$f800+word('x');
119
267
#197, #206, #215, #216: {����}
268
convert_vga_to_acs:=$f800+word('n');
124
269
#201, #213, #214, #218: {����}
270
convert_vga_to_acs:=$f800+word('l');
272
convert_vga_to_acs:=word('*');
133
273
{ Shadows for Buttons }
276
convert_vga_to_acs:=$f800+word('a');
278
convert_vga_to_acs:=word(ch);
148
function SendEscapeSeqNdx(Ndx: Word) : boolean;
283
procedure SendEscapeSeqNdx(ndx:Ttermcode);
152
SendEscapeSeqNdx:=false;
288
{ Always true because of vt100 default.
153
289
if not assigned(cur_term_Strings) then
155
P:=cur_term_Strings^[Ndx];
157
begin { Do not transmit the delays }
158
pdelay:=strpos(p,'$<');
159
if assigned(pdelay) then
161
fpWrite(stdoutputhandle, P^, StrLen(P));
162
SendEscapeSeqNdx:=true;
163
if assigned(pdelay) then
290
exit}{RunError(219)};
291
p:=cur_term_strings^[ndx];
293
fpwrite(stdoutputhandle,p^,strlen(p));
319
490
p,pold : pvideocell;
320
491
LastLineWidth : Longint;
322
procedure TransformUsingACS(var st : string);
329
for i:=1 to length(st) do
332
if IsACS(ch,ACSch) then
493
function transform_cp437_to_iso01(const st:string):string;
500
transform_cp437_to_iso01:='';
501
for i:=1 to length(st) do
506
converted:=convert_lowascii_to_iso01[c];
508
converted:=convert_cp437_to_iso01[c];
512
if converted and $ff00=$f800 then
516
transform_cp437_to_iso01:=transform_cp437_to_iso01+ACSIn;
519
c:=char(converted and $ff);
524
transform_cp437_to_iso01:=transform_cp437_to_iso01+ACSOut+
525
Attr2Ansi(LastAttr,0);
528
transform_cp437_to_iso01:=transform_cp437_to_iso01+c;
532
function transform_cp850_to_iso01(const st:string):string;
539
transform_cp850_to_iso01:='';
540
for i:=1 to length(st) do
545
converted:=convert_lowascii_to_iso01[c];
547
converted:=convert_cp850_to_iso01[c];
551
if converted and $ff00=$f800 then
555
transform_cp850_to_iso01:=transform_cp850_to_iso01+ACSIn;
562
transform_cp850_to_iso01:=transform_cp850_to_iso01+ACSOut+
563
Attr2Ansi(LastAttr,0);
566
c:=char(converted and $ff);
567
transform_cp850_to_iso01:=transform_cp850_to_iso01+c;
571
function transform_linuxlowascii_to_vga(const st:string):string;
578
transform_linuxlowascii_to_vga:='';
579
for i:=1 to length(st) do
584
converted:=convert_linuxlowascii_to_vga[c];
588
c:=char(converted and $ff);
589
transform_linuxlowascii_to_vga:=transform_linuxlowascii_to_vga+c;
593
function transform(const hstr:string):string;
597
cv_linuxlowascii_to_vga:
598
transform:=transform_linuxlowascii_to_vga(hstr);
600
transform:=transform_cp437_to_iso01(hstr);
602
transform:=transform_cp850_to_iso01(hstr);
345
res:=res+ACSOut+Attr2Ansi(LastAttr,0);
356
608
procedure outdata(hstr:string);
358
611
If Length(HStr)>0 Then
531
796
blockwrite(f,nl,1);
533
798
fpWrite(stdoutputhandle,outbuf,outptr);
535
SendEscapeSeqNdx(exit_alt_charset_mode);
536
799
{turn autowrap on}
537
800
// SendEscapeSeq(#27'[?7h');
804
procedure update_vcsa(force:boolean);
806
const max_updates=64;
808
label update,update_all,equal_loop,unequal_loop;
810
var position,update_count,i:word;
811
update_positions:array[0..max_updates-1] of word;
812
update_lengths:array[0..max_updates-1] of word;
823
if videobuf^[i]<>oldvideobuf^[i] then
826
until i>videobufsize div 2;
830
if update_count>=max_updates then
832
update_positions[update_count]:=i;
833
update_lengths[update_count]:=0;
836
if videobuf^[i]=oldvideobuf^[i] then
839
inc(update_lengths[update_count-1]);
840
until i>videobufsize div 2;
843
for i:=1 to update_count do
845
position:=update_positions[i-1];
846
fppwrite(ttyfd,videobuf^[position],update_lengths[i-1]*2,4+position*2);
850
fppwrite(ttyfd,videobuf^,videobufsize,4);
541
855
preInitVideoTio, postInitVideoTio: termio.termios;
542
856
inputRaw, outputRaw: boolean;
544
858
procedure saveRawSettings(const tio: termio.termios);
578
893
TCSetAttr(1,TCSANOW,tio);
896
procedure decide_codepages;
901
if external_codepage in vga_codepages then
903
{Possible override...}
904
s:=upcase(fpgetenv('CONSOLEFONT_CP'));
906
external_codepage:=cp437
907
else if s='CP850' then
908
external_codepage:=cp850;
910
{A non-vcsa Linux console can display most control characters, but not all.}
911
if {$ifdef linux}(console<>ttyLinux) and{$endif}
912
(cur_term_strings=@term_codes_linux) then
913
convert:=cv_linuxlowascii_to_vga;
914
case external_codepage of
917
internal_codepage:=cp850;
918
convert:=cv_cp850_to_iso01;
921
internal_codepage:=cp852;
923
internal_codepage:=cp866;
925
if internal_codepage in vga_codepages then
926
internal_codepage:=external_codepage
928
{We don't know how to convert to the external codepage. Use codepage
929
437 in the hope that the actual font has similarity to codepage 437.}
930
internal_codepage:=cp437;
582
935
procedure prepareInitVideo;
608
961
procedure SysInitVideo;
610
fontstr : string[3]=#27'(K';
614
964
WS: packed record
615
965
ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
618
prev_term : TerminalCommon_ptr1;
968
{ prev_term : TerminalCommon_ptr1;}
978
const font_vga:array[0..11] of char=#15#27'%@'#27'(U'#27'[3h';
979
font_custom:array[0..2] of char=#27'(K';
623
982
{ check for tty }
624
ThisTTY:=TTYName(stdinputhandle);
625
if (IsATTY(stdinputhandle)<>-1) then
983
if (IsATTY(stdinputhandle)=1) then
627
985
{ save current terminal characteristics and remove rawness }
628
986
prepareInitVideo;
629
{ write code to set a correct font }
630
fpWrite(stdoutputhandle,fontstr[1],length(fontstr));
631
987
{ running on a tty, find out whether locally or remotely }
633
Console:=TTyNetwork; {Default: Network or other vtxxx tty}
634
if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
635
not (ThisTTY[9] IN ['p'..'u','P']) then // FreeBSD has these
637
{ running on the console }
639
'0'..'9' : begin { running Linux on native console or native-emulation }
640
FName:='/dev/vcsa' + ThisTTY[9];
641
{ open console, $1b6=rw-rw-rw- }
642
TTYFd:=fpOpen(FName, $1b6, O_RdWr);
646
'v' : { check for (Free?)BSD native}
647
If (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
648
Console:=ttyFreeBSD; {TTYFd ?}
651
If (Copy(fpGetEnv('TERM'),1,4)='cons') Then // cons<lines>
653
If Console<>ttylinux Then
989
Console:=TTyNetwork; {Default: Network or other vtxxx tty}
990
cur_term_strings:=@term_codes_vt100; {Default: vt100}
991
external_codepage:=iso01; {Default: ISO-8859-1}
993
if vcs_device>=0 then
996
fname:='/dev/vcsa'+s;
997
{ open console, $1b6=rw-rw-rw- }
998
ttyfd:=fpopen(fname,$1b6,O_RDWR);
1002
external_codepage:=cp437; {VCSA defaults to codepage 437.}
1005
if try_grab_vcsa then
1007
ttyfd:=fpopen(fname,$1b6,O_RDWR);
1011
external_codepage:=cp437; {VCSA defaults to codepage 437.}
1017
ThisTTY:=TTYName(stdinputhandle);
1018
if copy(ThisTTY, 1, 9) = '/dev/ttyv' then {FreeBSD has these}
1020
{ check for (Free?)BSD native}
1021
if (ThisTTY[10]>='0') and (ThisTTY[10]<='9') Then
1022
Console:=ttyFreeBSD; {TTYFd ?}
1025
term:=fpgetenv('TERM');
1026
for i:=low(terminal_names) to high(terminal_names) do
1027
if copy(term,1,length(terminal_names[i]))=terminal_names[i] then
1028
cur_term_strings:=terminal_data[i];
1029
if cur_term_strings=@term_codes_freebsd then
1030
console:=ttyFreeBSD;
1032
if (console<>ttylinux) then
1035
if cur_term_strings=@term_codes_linux then
1037
{Executed in case ttylinux is false (i.e. no vcsa), but
1039
{Enable the VGA character set (codepage 437,850,....)}
1040
fpwrite(stdoutputhandle,font_vga,sizeof(font_vga));
1041
external_codepage:=cp437; {Now default to codepage 437.}
1045
fpwrite(stdoutputhandle,font_custom,sizeof(font_vga));
655
1046
{ running on a remote terminal, no error with /dev/vcsa }
657
//TTYFd:=stdoutputhandle;
659
1050
fpioctl(stdinputhandle, TIOCGWINSZ, @WS);
660
1051
if WS.ws_Col=0 then
672
1063
LastCursorType:=$ff;
673
1064
ScreenColor:=True;
674
1065
{ Start with a clear screen }
675
1067
if Console<>ttylinux then
678
setupterm(nil, stdoutputhandle, err);
679
can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
680
1070
SendEscapeSeqNdx(cursor_home);
681
1071
SendEscapeSeqNdx(cursor_normal);
682
SendEscapeSeqNdx(cursor_visible);
1072
SendEscapeSeqNdx(cursor_visible_underline);
683
1073
SendEscapeSeqNdx(enter_ca_mode);
684
1074
SetCursorType(crUnderLine);
685
1075
If Console=ttyFreeBSD Then
686
1076
SendEscapeSeqNdx(exit_am_mode);
688
else if not assigned(cur_term) then
690
setupterm(nil, stdoutputhandle, err);
691
can_delete_term:=false;
693
if assigned(cur_term_Strings) then
695
ACSIn:=StrPas(cur_term_Strings^[enter_alt_charset_mode]);
696
ACSOut:=StrPas(cur_term_Strings^[exit_alt_charset_mode]);
1080
{ Always true because of vt100 default...
1081
if assigned(cur_term_Strings) then
1083
ACSIn:=StrPas(cur_term_strings^[enter_alt_charset_mode]);
1084
ACSOut:=StrPas(cur_term_strings^[exit_alt_charset_mode]);
697
1085
if (ACSIn<>'') and (ACSOut<>'') then
698
1086
SendEscapeSeqNdx(ena_acs);
699
if pos('$<',ACSIn)>0 then
700
ACSIn:=Copy(ACSIn,1,Pos('$<',ACSIn)-1);
701
if pos('$<',ACSOut)>0 then
702
ACSOut:=Copy(ACSOut,1,Pos('$<',ACSOut)-1);
703
If fpGetEnv('TERM')='xterm' then
704
NoExtendedFrame := true; {use of acs for xterm is ok}
1087
(* If fpGetEnv('TERM')='xterm' then
1088
convert:=cv_vga_to_acs; {use of acs for xterm is ok}*)
711
1095
{$ifdef logging}
712
1096
assign(f,'video.log');
714
1098
{$endif logging}
715
1099
{ save new terminal characteristics and possible restore rawness }
719
1105
ErrorCode:=errVioInit; { not a TTY }
722
1108
procedure SysDoneVideo;
1110
var font_custom:array[0..2] of char=#27'(K';
724
1113
prepareDoneVideo;
1114
SetCursorType(crUnderLine);
725
1116
if Console=ttylinux then
726
1117
SetCursorPos(0,0)
729
1121
SendEscapeSeqNdx(exit_ca_mode);
730
1122
SendEscapeSeqNdx(cursor_home);
731
1123
SendEscapeSeqNdx(cursor_normal);
732
SendEscapeSeqNdx(cursor_visible);
733
SetCursorType(crUnderLine);
1124
SendEscapeSeqNdx(cursor_visible_underline);
734
1125
SendEscapeSeq(#27'[H');
1126
if cur_term_strings=@term_codes_linux then
1128
{Executed in case ttylinux is false (i.e. no vcsa), but
1130
{Enable the character set set through setfont}
1131
fpwrite(stdoutputhandle,font_custom,3);
739
{ FreeBSD gives an error here.
740
According to Pierre this could be more a NCurses version thing that
741
a FreeBSD one. FreeBSD 4.4 has ncurses 5.
742
MvdV102003: Since I ran 1.1 with newer FreeBSD without problem, I let it be for now}
743
if can_delete_term then
745
del_curterm(cur_term);
746
can_delete_term:=false;
748
1139
{$ifdef logging}
750
1141
{$endif logging}