crt.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  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: Byte; Y: Byte);
  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: Byte;
  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: Byte;
  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. regs.realecx:=$90A;
  420. If VidSeg=$b800 then
  421. regs.realecx:=$90A
  422. else
  423. regs.realecx:=$b0d;
  424. realintr($10,regs);
  425. end;
  426. procedure cursoroff;
  427. var
  428. regs : trealregs;
  429. begin
  430. regs.realeax:=$0100;
  431. regs.realecx:=$ffff;
  432. realintr($10,regs);
  433. end;
  434. procedure cursorbig;
  435. var
  436. regs : trealregs;
  437. begin
  438. regs.realeax:=$0100;
  439. regs.realecx:=$10A;
  440. realintr($10,regs);
  441. end;
  442. {*****************************************************************************
  443. Read and Write routines
  444. *****************************************************************************}
  445. var
  446. CurrX,CurrY : longint;
  447. Procedure WriteChar(c:char);
  448. var
  449. regs : trealregs;
  450. begin
  451. case c of
  452. #10 : inc(CurrY);
  453. #13 : CurrX:=WinMinX;
  454. #8 : begin
  455. if CurrX>WinMinX then
  456. dec(CurrX);
  457. end;
  458. #7 : begin { beep }
  459. regs.dl:=7;
  460. regs.ah:=2;
  461. realintr($21,regs);
  462. end;
  463. else
  464. begin
  465. memw[VidSeg:((CurrY-1)*ScreenWidth+(CurrX-1))*2]:=(textattr shl 8) or byte(c);
  466. inc(CurrX);
  467. end;
  468. end;
  469. if CurrX>WinMaxX then
  470. begin
  471. CurrX:=WinMinX;
  472. inc(CurrY);
  473. end;
  474. while CurrY>WinMaxY do
  475. begin
  476. removeline(1);
  477. dec(CurrY);
  478. end;
  479. end;
  480. Function CrtWrite(var f : textrec):integer;
  481. var
  482. i : longint;
  483. begin
  484. GetScreenCursor(CurrX,CurrY);
  485. for i:=0 to f.bufpos-1 do
  486. WriteChar(f.buffer[i]);
  487. SetScreenCursor(CurrX,CurrY);
  488. f.bufpos:=0;
  489. CrtWrite:=0;
  490. end;
  491. Function CrtRead(Var F: TextRec): Integer;
  492. procedure BackSpace;
  493. begin
  494. if (f.bufpos>0) and (f.bufpos=f.bufend) then
  495. begin
  496. WriteChar(#8);
  497. WriteChar(' ');
  498. WriteChar(#8);
  499. dec(f.bufpos);
  500. dec(f.bufend);
  501. end;
  502. end;
  503. var
  504. ch : Char;
  505. Begin
  506. GetScreenCursor(CurrX,CurrY);
  507. f.bufpos:=0;
  508. f.bufend:=0;
  509. repeat
  510. if f.bufpos>f.bufend then
  511. f.bufend:=f.bufpos;
  512. SetScreenCursor(CurrX,CurrY);
  513. ch:=readkey;
  514. case ch of
  515. #0 : case readkey of
  516. #71 : while f.bufpos>0 do
  517. begin
  518. dec(f.bufpos);
  519. WriteChar(#8);
  520. end;
  521. #75 : if f.bufpos>0 then
  522. begin
  523. dec(f.bufpos);
  524. WriteChar(#8);
  525. end;
  526. #77 : if f.bufpos<f.bufend then
  527. begin
  528. WriteChar(f.bufptr^[f.bufpos]);
  529. inc(f.bufpos);
  530. end;
  531. #79 : while f.bufpos<f.bufend do
  532. begin
  533. WriteChar(f.bufptr^[f.bufpos]);
  534. inc(f.bufpos);
  535. end;
  536. end;
  537. ^S,
  538. #8 : BackSpace;
  539. ^Y,
  540. #27 : begin
  541. while f.bufpos<f.bufend do begin
  542. WriteChar(f.bufptr^[f.bufpos]);
  543. inc(f.bufpos);
  544. end;
  545. while f.bufend>0 do
  546. BackSpace;
  547. end;
  548. #13 : begin
  549. WriteChar(#13);
  550. WriteChar(#10);
  551. f.bufptr^[f.bufend]:=#13;
  552. f.bufptr^[f.bufend+1]:=#10;
  553. inc(f.bufend,2);
  554. break;
  555. end;
  556. #26 : if CheckEOF then
  557. begin
  558. f.bufptr^[f.bufend]:=#26;
  559. inc(f.bufend);
  560. break;
  561. end;
  562. else
  563. begin
  564. if f.bufpos<f.bufsize-2 then
  565. begin
  566. f.buffer[f.bufpos]:=ch;
  567. inc(f.bufpos);
  568. WriteChar(ch);
  569. end;
  570. end;
  571. end;
  572. until false;
  573. f.bufpos:=0;
  574. SetScreenCursor(CurrX,CurrY);
  575. CrtRead:=0;
  576. End;
  577. Function CrtReturn(Var F: TextRec): Integer;
  578. Begin
  579. CrtReturn:=0;
  580. end;
  581. Function CrtClose(Var F: TextRec): Integer;
  582. Begin
  583. F.Mode:=fmClosed;
  584. CrtClose:=0;
  585. End;
  586. Function CrtOpen(Var F: TextRec): Integer;
  587. Begin
  588. If F.Mode=fmOutput Then
  589. begin
  590. TextRec(F).InOutFunc:=@CrtWrite;
  591. TextRec(F).FlushFunc:=@CrtWrite;
  592. end
  593. Else
  594. begin
  595. F.Mode:=fmInput;
  596. TextRec(F).InOutFunc:=@CrtRead;
  597. TextRec(F).FlushFunc:=@CrtReturn;
  598. end;
  599. TextRec(F).CloseFunc:=@CrtClose;
  600. CrtOpen:=0;
  601. End;
  602. procedure AssignCrt(var F: Text);
  603. begin
  604. Assign(F,'');
  605. TextRec(F).OpenFunc:=@CrtOpen;
  606. end;
  607. { use the C version to avoid using dpmiexcp unit
  608. which makes sysutils and exceptions working incorrectly PM }
  609. function __djgpp_set_ctrl_c(enable : longint) : boolean;cdecl;external;
  610. var
  611. x,y : longint;
  612. begin
  613. { Load startup values }
  614. ScreenWidth:=GetScreenWidth;
  615. ScreenHeight:=GetScreenHeight;
  616. WindMax:=(ScreenWidth-1) or ((ScreenHeight-1) shl 8);
  617. { Load TextAttr }
  618. GetScreenCursor(x,y);
  619. lastmode := mem[$40:$49];
  620. if screenheight>25 then
  621. lastmode:=lastmode or $100;
  622. If not(lastmode=Mono) then
  623. VidSeg := $b800
  624. else
  625. VidSeg := $b000;
  626. TextAttr:=mem[VidSeg:((y-1)*ScreenWidth+(x-1))*2+1];
  627. { Redirect the standard output }
  628. assigncrt(Output);
  629. Rewrite(Output);
  630. TextRec(Output).Handle:=StdOutputHandle;
  631. assigncrt(Input);
  632. Reset(Input);
  633. TextRec(Input).Handle:=StdInputHandle;
  634. { Calculates delay calibration }
  635. initdelay;
  636. { Enable ctrl-c input (JM) }
  637. __djgpp_set_ctrl_c(0);
  638. end.