crt.pp 14 KB

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