crt.pp 15 KB

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