crt.pp 15 KB

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