crt.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. Borland Pascal 7 Compatible CRT Unit - Go32V2 implementation
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit crt;
  13. interface
  14. {$i crth.inc}
  15. Var
  16. ScreenWidth,
  17. ScreenHeight : longint;
  18. implementation
  19. uses
  20. go32;
  21. {$ASMMODE ATT}
  22. var
  23. DelayCnt : Longint;
  24. VidSeg : Word;
  25. {
  26. definition of textrec is in textrec.inc
  27. }
  28. {$i textrec.inc}
  29. {****************************************************************************
  30. Low level Routines
  31. ****************************************************************************}
  32. procedure setscreenmode(mode : byte);
  33. var
  34. regs : trealregs;
  35. begin
  36. regs.realeax:=mode;
  37. realintr($10,regs);
  38. end;
  39. function GetScreenHeight : longint;
  40. begin
  41. getscreenheight:=mem[$40:$84]+1;
  42. If mem[$40:$84]=0 then
  43. getscreenheight := 25;
  44. end;
  45. function GetScreenWidth : longint;
  46. begin
  47. getscreenwidth:=memw[$40:$4a];
  48. end;
  49. procedure SetScreenCursor(x,y : longint);
  50. var
  51. regs : trealregs;
  52. begin
  53. regs.realeax:=$0200;
  54. regs.realebx:=0;
  55. regs.realedx:=(y-1) shl 8+(x-1);
  56. realintr($10,regs);
  57. end;
  58. procedure GetScreenCursor(var x,y : longint);
  59. begin
  60. x:=mem[$40:$50]+1;
  61. y:=mem[$40:$51]+1;
  62. end;
  63. {****************************************************************************
  64. Helper Routines
  65. ****************************************************************************}
  66. Function WinMinX: Byte;
  67. {
  68. Current Minimum X coordinate
  69. }
  70. Begin
  71. WinMinX:=(WindMin and $ff)+1;
  72. End;
  73. Function WinMinY: Byte;
  74. {
  75. Current Minimum Y Coordinate
  76. }
  77. Begin
  78. WinMinY:=(WindMin shr 8)+1;
  79. End;
  80. Function WinMaxX: Byte;
  81. {
  82. Current Maximum X coordinate
  83. }
  84. Begin
  85. WinMaxX:=(WindMax and $ff)+1;
  86. End;
  87. Function WinMaxY: Byte;
  88. {
  89. Current Maximum Y coordinate;
  90. }
  91. Begin
  92. WinMaxY:=(WindMax shr 8) + 1;
  93. End;
  94. Function FullWin:boolean;
  95. {
  96. Full Screen 80x25? Window(1,1,80,25) is used, allows faster routines
  97. }
  98. begin
  99. FullWin:=(WinMinX=1) and (WinMinY=1) and
  100. (WinMaxX=ScreenWidth) and (WinMaxY=ScreenHeight);
  101. end;
  102. {****************************************************************************
  103. Public Crt Functions
  104. ****************************************************************************}
  105. procedure textmode(mode : integer);
  106. var
  107. regs : trealregs;
  108. begin
  109. lastmode:=mode;
  110. mode:=mode and $ff;
  111. setscreenmode(mode);
  112. { set 8x8 font }
  113. if (lastmode and $100)<>0 then
  114. begin
  115. regs.realeax:=$1112;
  116. regs.realebx:=$0;
  117. realintr($10,regs);
  118. end;
  119. screenwidth:=getscreenwidth;
  120. screenheight:=getscreenheight;
  121. windmin:=0;
  122. windmax:=(screenwidth-1) or ((screenheight-1) shl 8);
  123. end;
  124. Procedure TextColor(Color: Byte);
  125. {
  126. Switch foregroundcolor
  127. }
  128. Begin
  129. TextAttr:=(Color and $f) or (TextAttr and $70);
  130. If (Color>15) Then TextAttr:=TextAttr Or Blink;
  131. End;
  132. Procedure TextBackground(Color: Byte);
  133. {
  134. Switch backgroundcolor
  135. }
  136. Begin
  137. TextAttr:=((Color shl 4) and ($f0 and not Blink)) or (TextAttr and ($0f OR Blink) );
  138. End;
  139. Procedure HighVideo;
  140. {
  141. Set highlighted output.
  142. }
  143. Begin
  144. TextColor(TextAttr Or $08);
  145. End;
  146. Procedure LowVideo;
  147. {
  148. Set normal output
  149. }
  150. Begin
  151. TextColor(TextAttr And $77);
  152. End;
  153. Procedure NormVideo;
  154. {
  155. Set normal back and foregroundcolors.
  156. }
  157. Begin
  158. TextColor(7);
  159. TextBackGround(0);
  160. End;
  161. Procedure GotoXy(X: Byte; Y: Byte);
  162. {
  163. Go to coordinates X,Y in the current window.
  164. }
  165. Begin
  166. If (X>0) and (X<=WinMaxX- WinMinX+1) and
  167. (Y>0) and (Y<=WinMaxY-WinMinY+1) Then
  168. Begin
  169. Inc(X,WinMinX-1);
  170. Inc(Y,WinMinY-1);
  171. SetScreenCursor(x,y);
  172. End;
  173. End;
  174. Procedure Window(X1, Y1, X2, Y2: Byte);
  175. {
  176. Set screen window to the specified coordinates.
  177. }
  178. Begin
  179. if (X1>X2) or (X2>ScreenWidth) or
  180. (Y1>Y2) or (Y2>ScreenHeight) then
  181. exit;
  182. WindMin:=((Y1-1) Shl 8)+(X1-1);
  183. WindMax:=((Y2-1) Shl 8)+(X2-1);
  184. GoToXY(1,1);
  185. End;
  186. Procedure ClrScr;
  187. {
  188. Clear the current window, and set the cursor on 1,1
  189. }
  190. var
  191. fil : word;
  192. y : longint;
  193. begin
  194. fil:=32 or (textattr shl 8);
  195. if FullWin then
  196. DosmemFillWord(VidSeg,0,ScreenHeight*ScreenWidth,fil)
  197. else
  198. begin
  199. for y:=WinMinY to WinMaxY do
  200. DosmemFillWord(VidSeg,((y-1)*ScreenWidth+(WinMinX-1))*2,WinMaxX-WinMinX+1,fil);
  201. end;
  202. Gotoxy(1,1);
  203. end;
  204. Procedure ClrEol;
  205. {
  206. Clear from current position to end of line.
  207. }
  208. var
  209. x,y : longint;
  210. fil : word;
  211. Begin
  212. GetScreenCursor(x,y);
  213. fil:=32 or (textattr shl 8);
  214. if x<=WinMaxX then
  215. DosmemFillword(VidSeg,((y-1)*ScreenWidth+(x-1))*2,WinMaxX-x+1,fil);
  216. End;
  217. Function WhereX: Byte;
  218. {
  219. Return current X-position of cursor.
  220. }
  221. var
  222. x,y : longint;
  223. Begin
  224. GetScreenCursor(x,y);
  225. WhereX:=x-WinMinX+1;
  226. End;
  227. Function WhereY: Byte;
  228. {
  229. Return current Y-position of cursor.
  230. }
  231. var
  232. x,y : longint;
  233. Begin
  234. GetScreenCursor(x,y);
  235. WhereY:=y-WinMinY+1;
  236. End;
  237. {*************************************************************************
  238. KeyBoard
  239. *************************************************************************}
  240. var
  241. is_last : boolean;
  242. last : char;
  243. function readkey : char;
  244. var
  245. char2 : char;
  246. char1 : char;
  247. regs : trealregs;
  248. begin
  249. if is_last then
  250. begin
  251. is_last:=false;
  252. readkey:=last;
  253. end
  254. else
  255. begin
  256. regs.ah:=$10;
  257. realintr($16,regs);
  258. if (regs.al=$e0) and (regs.ah<>0) then
  259. regs.al:=0;
  260. char1:=chr(regs.al);
  261. char2:=chr(regs.ah);
  262. if char1=#0 then
  263. begin
  264. is_last:=true;
  265. last:=char2;
  266. end;
  267. readkey:=char1;
  268. end;
  269. end;
  270. function keypressed : boolean;
  271. var
  272. regs : trealregs;
  273. begin
  274. if is_last then
  275. begin
  276. keypressed:=true;
  277. exit;
  278. end
  279. else
  280. begin
  281. regs.ah:=$11;
  282. realintr($16,regs);
  283. keypressed:=((regs.realflags and zeroflag) = 0);
  284. end;
  285. end;
  286. {*************************************************************************
  287. Delay
  288. *************************************************************************}
  289. procedure Delayloop;assembler;
  290. asm
  291. .LDelayLoop1:
  292. subl $1,%eax
  293. jc .LDelayLoop2
  294. cmpl %fs:(%edi),%ebx
  295. je .LDelayLoop1
  296. .LDelayLoop2:
  297. end;
  298. procedure initdelay;assembler;
  299. asm
  300. pushl %ebx
  301. pushl %edi
  302. { for some reason, using int $31/ax=$901 doesn't work here }
  303. { and interrupts are always disabled at this point when }
  304. { running a program inside gdb(pas). Web bug 1345 (JM) }
  305. sti
  306. movl $0x46c,%edi
  307. movl $-28,%edx
  308. movl %fs:(%edi),%ebx
  309. .LInitDel1:
  310. cmpl %fs:(%edi),%ebx
  311. je .LInitDel1
  312. movl %fs:(%edi),%ebx
  313. movl %edx,%eax
  314. call DelayLoop
  315. notl %eax
  316. xorl %edx,%edx
  317. movl $55,%ecx
  318. divl %ecx
  319. movl %eax,DelayCnt
  320. popl %edi
  321. popl %ebx
  322. end;
  323. procedure Delay(MS: Word);assembler;
  324. asm
  325. pushl %ebx
  326. pushl %edi
  327. movzwl MS,%ecx
  328. jecxz .LDelay2
  329. movl $0x400,%edi
  330. movl DelayCnt,%edx
  331. movl %fs:(%edi),%ebx
  332. .LDelay1:
  333. movl %edx,%eax
  334. call DelayLoop
  335. loop .LDelay1
  336. .LDelay2:
  337. popl %edi
  338. popl %ebx
  339. end;
  340. procedure sound(hz : word);
  341. begin
  342. if hz=0 then
  343. begin
  344. nosound;
  345. exit;
  346. end;
  347. asm
  348. movzwl hz,%ecx
  349. movl $1193046,%eax
  350. cltd
  351. divl %ecx
  352. movl %eax,%ecx
  353. inb $0x61,%al
  354. testb $0x3,%al
  355. jnz .Lsound_next
  356. orb $0x3,%al
  357. outb %al,$0x61
  358. movb $0xb6,%al
  359. outb %al,$0x43
  360. .Lsound_next:
  361. movb %cl,%al
  362. outb %al,$0x42
  363. movb %ch,%al
  364. outb %al,$0x42
  365. end ['EAX','ECX','EDX'];
  366. end;
  367. procedure nosound;
  368. begin
  369. asm
  370. inb $0x61,%al
  371. andb $0xfc,%al
  372. outb %al,$0x61
  373. end ['EAX'];
  374. end;
  375. {****************************************************************************
  376. HighLevel Crt Functions
  377. ****************************************************************************}
  378. procedure removeline(y : longint);
  379. var
  380. fil : word;
  381. begin
  382. fil:=32 or (textattr shl 8);
  383. y:=WinMinY+y-1;
  384. While (y<WinMaxY) do
  385. begin
  386. dosmemmove(VidSeg,(y*ScreenWidth+(WinMinX-1))*2,
  387. VidSeg,((y-1)*ScreenWidth+(WinMinX-1))*2,(WinMaxX-WinMinX+1)*2);
  388. inc(y);
  389. end;
  390. dosmemfillword(VidSeg,((WinMaxY-1)*ScreenWidth+(WinMinX-1))*2,(WinMaxX-WinMinX+1),fil);
  391. end;
  392. procedure delline;
  393. begin
  394. removeline(wherey);
  395. end;
  396. procedure insline;
  397. var
  398. my,y : longint;
  399. fil : word;
  400. begin
  401. fil:=32 or (textattr shl 8);
  402. y:=WhereY;
  403. my:=WinMaxY-WinMinY;
  404. while (my>=y) do
  405. begin
  406. dosmemmove(VidSeg,(((WinMinY+my-1)-1)*ScreenWidth+(WinMinX-1))*2,
  407. VidSeg,(((WinMinY+my)-1)*ScreenWidth+(WinMinX-1))*2,(WinMaxX-WinMinX+1)*2);
  408. dec(my);
  409. end;
  410. dosmemfillword(VidSeg,(((WinMinY+y-1)-1)*ScreenWidth+(WinMinX-1))*2,(WinMaxX-WinMinX+1),fil);
  411. end;
  412. {****************************************************************************
  413. Extra Crt Functions
  414. ****************************************************************************}
  415. procedure cursoron;
  416. var
  417. regs : trealregs;
  418. begin
  419. regs.realeax:=$0100;
  420. regs.realecx:=$90A;
  421. If VidSeg=$b800 then
  422. regs.realecx:=$90A
  423. else
  424. regs.realecx:=$b0d;
  425. realintr($10,regs);
  426. end;
  427. procedure cursoroff;
  428. var
  429. regs : trealregs;
  430. begin
  431. regs.realeax:=$0100;
  432. regs.realecx:=$ffff;
  433. realintr($10,regs);
  434. end;
  435. procedure cursorbig;
  436. var
  437. regs : trealregs;
  438. begin
  439. regs.realeax:=$0100;
  440. regs.realecx:=$10A;
  441. realintr($10,regs);
  442. end;
  443. {*****************************************************************************
  444. Read and Write routines
  445. *****************************************************************************}
  446. var
  447. CurrX,CurrY : longint;
  448. Procedure WriteChar(c:char);
  449. var
  450. regs : trealregs;
  451. begin
  452. case c of
  453. #10 : inc(CurrY);
  454. #13 : CurrX:=WinMinX;
  455. #8 : begin
  456. if CurrX>WinMinX then
  457. dec(CurrX);
  458. end;
  459. #7 : begin { beep }
  460. regs.dl:=7;
  461. regs.ah:=2;
  462. realintr($21,regs);
  463. end;
  464. else
  465. begin
  466. memw[VidSeg:((CurrY-1)*ScreenWidth+(CurrX-1))*2]:=(textattr shl 8) or byte(c);
  467. inc(CurrX);
  468. end;
  469. end;
  470. if CurrX>WinMaxX then
  471. begin
  472. CurrX:=WinMinX;
  473. inc(CurrY);
  474. end;
  475. while CurrY>WinMaxY do
  476. begin
  477. removeline(1);
  478. dec(CurrY);
  479. end;
  480. end;
  481. Function CrtWrite(var f : textrec):integer;
  482. var
  483. i : longint;
  484. begin
  485. GetScreenCursor(CurrX,CurrY);
  486. for i:=0 to f.bufpos-1 do
  487. WriteChar(f.buffer[i]);
  488. SetScreenCursor(CurrX,CurrY);
  489. f.bufpos:=0;
  490. CrtWrite:=0;
  491. end;
  492. Function CrtRead(Var F: TextRec): Integer;
  493. procedure BackSpace;
  494. begin
  495. if (f.bufpos>0) and (f.bufpos=f.bufend) then
  496. begin
  497. WriteChar(#8);
  498. WriteChar(' ');
  499. WriteChar(#8);
  500. dec(f.bufpos);
  501. dec(f.bufend);
  502. end;
  503. end;
  504. var
  505. ch : Char;
  506. Begin
  507. GetScreenCursor(CurrX,CurrY);
  508. f.bufpos:=0;
  509. f.bufend:=0;
  510. repeat
  511. if f.bufpos>f.bufend then
  512. f.bufend:=f.bufpos;
  513. SetScreenCursor(CurrX,CurrY);
  514. ch:=readkey;
  515. case ch of
  516. #0 : case readkey of
  517. #71 : while f.bufpos>0 do
  518. begin
  519. dec(f.bufpos);
  520. WriteChar(#8);
  521. end;
  522. #75 : if f.bufpos>0 then
  523. begin
  524. dec(f.bufpos);
  525. WriteChar(#8);
  526. end;
  527. #77 : if f.bufpos<f.bufend then
  528. begin
  529. WriteChar(f.bufptr^[f.bufpos]);
  530. inc(f.bufpos);
  531. end;
  532. #79 : while f.bufpos<f.bufend do
  533. begin
  534. WriteChar(f.bufptr^[f.bufpos]);
  535. inc(f.bufpos);
  536. end;
  537. end;
  538. ^S,
  539. #8 : BackSpace;
  540. ^Y,
  541. #27 : begin
  542. while f.bufpos<f.bufend do begin
  543. WriteChar(f.bufptr^[f.bufpos]);
  544. inc(f.bufpos);
  545. end;
  546. while f.bufend>0 do
  547. BackSpace;
  548. end;
  549. #13 : begin
  550. WriteChar(#13);
  551. WriteChar(#10);
  552. f.bufptr^[f.bufend]:=#13;
  553. f.bufptr^[f.bufend+1]:=#10;
  554. inc(f.bufend,2);
  555. break;
  556. end;
  557. #26 : if CheckEOF then
  558. begin
  559. f.bufptr^[f.bufend]:=#26;
  560. inc(f.bufend);
  561. break;
  562. end;
  563. else
  564. begin
  565. if f.bufpos<f.bufsize-2 then
  566. begin
  567. f.buffer[f.bufpos]:=ch;
  568. inc(f.bufpos);
  569. WriteChar(ch);
  570. end;
  571. end;
  572. end;
  573. until false;
  574. f.bufpos:=0;
  575. SetScreenCursor(CurrX,CurrY);
  576. CrtRead:=0;
  577. End;
  578. Function CrtReturn(Var F: TextRec): Integer;
  579. Begin
  580. CrtReturn:=0;
  581. end;
  582. Function CrtClose(Var F: TextRec): Integer;
  583. Begin
  584. F.Mode:=fmClosed;
  585. CrtClose:=0;
  586. End;
  587. Function CrtOpen(Var F: TextRec): Integer;
  588. Begin
  589. If F.Mode=fmOutput Then
  590. begin
  591. TextRec(F).InOutFunc:=@CrtWrite;
  592. TextRec(F).FlushFunc:=@CrtWrite;
  593. end
  594. Else
  595. begin
  596. F.Mode:=fmInput;
  597. TextRec(F).InOutFunc:=@CrtRead;
  598. TextRec(F).FlushFunc:=@CrtReturn;
  599. end;
  600. TextRec(F).CloseFunc:=@CrtClose;
  601. CrtOpen:=0;
  602. End;
  603. procedure AssignCrt(var F: Text);
  604. begin
  605. Assign(F,'');
  606. TextRec(F).OpenFunc:=@CrtOpen;
  607. end;
  608. { use the C version to avoid using dpmiexcp unit
  609. which makes sysutils and exceptions working incorrectly PM }
  610. function __djgpp_set_ctrl_c(enable : longint) : boolean;cdecl;external;
  611. var
  612. x,y : longint;
  613. begin
  614. { Load startup values }
  615. ScreenWidth:=GetScreenWidth;
  616. ScreenHeight:=GetScreenHeight;
  617. WindMax:=(ScreenWidth-1) or ((ScreenHeight-1) shl 8);
  618. { Load TextAttr }
  619. GetScreenCursor(x,y);
  620. lastmode := mem[$40:$49];
  621. if screenheight>25 then
  622. lastmode:=lastmode or $100;
  623. If not(lastmode=Mono) then
  624. VidSeg := $b800
  625. else
  626. VidSeg := $b000;
  627. TextAttr:=mem[VidSeg:((y-1)*ScreenWidth+(x-1))*2+1];
  628. { Redirect the standard output }
  629. assigncrt(Output);
  630. Rewrite(Output);
  631. TextRec(Output).Handle:=StdOutputHandle;
  632. assigncrt(Input);
  633. Reset(Input);
  634. TextRec(Input).Handle:=StdInputHandle;
  635. { Calculates delay calibration }
  636. initdelay;
  637. { Enable ctrl-c input (JM) }
  638. __djgpp_set_ctrl_c(0);
  639. end.
  640. {
  641. $Log$
  642. Revision 1.11 2004-02-08 16:22:20 michael
  643. + Moved CRT interface to common include file
  644. Revision 1.10 2003/10/03 21:56:36 peter
  645. * stdcall fixes
  646. Revision 1.9 2003/03/17 18:13:13 peter
  647. * exported ScreenHeight, ScreenWidth
  648. Revision 1.8 2002/12/15 20:22:24 peter
  649. * fix making string empty in readln when cursor is not at the end
  650. Revision 1.7 2002/09/10 10:38:04 pierre
  651. * merged from fixes: fix bug report 1974
  652. Revision 1.6 2002/09/07 16:01:18 peter
  653. * old logs removed and tabs fixed
  654. }