crt.pp 14 KB

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