crt.pp 14 KB

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