crt.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. {****************************************************************************
  2. Standard CRT unit.
  3. FPK-Pascal runtime library for OS/2.
  4. Copyright (c) 1997 Dani‰l Mantione.
  5. This file may be reproduced and modified under the same conditions
  6. as all other FPK-Pascal source code.
  7. ****************************************************************************}
  8. unit crt;
  9. {History:
  10. 3 june 1997 - Creation.
  11. 9 june 1997 - Now runs under OS/2.
  12. 12 june 1997 - Now runs under DOS.}
  13. interface
  14. uses dos;
  15. const _40cols=0;
  16. _80cols=1;
  17. _132cols=2;
  18. _25rows=0;
  19. _28rows=16;
  20. _43rows=32;
  21. _50rows=48;
  22. font8x8=_50rows;
  23. black =0;
  24. blue =1;
  25. green =2;
  26. cyan =3;
  27. red =4;
  28. magenta =5;
  29. brown =6;
  30. lightgray =7;
  31. darkgray =8;
  32. lightblue =9;
  33. lightgreen =10;
  34. lightcyan =11;
  35. lightred =12;
  36. lightmagenta =13;
  37. yellow =14;
  38. white =15;
  39. blink =128;
  40. {cemodeset means that the procedure textmode has failed to set up a mode.}
  41. type cexxxx=(cenoerror,cemodeset);
  42. var textattr:byte; {Text attribute. RW}
  43. windmin,windmax:word; {Window coordinates. R-}
  44. lastmode:word; {Last videomode. R-}
  45. crt_error:cexxxx; {Crt-status. RW}
  46. function keypressed:boolean;
  47. function readkey:char;
  48. procedure clrscr;
  49. function whereX:byte;
  50. function whereY:byte;
  51. procedure gotoXY(x,y:byte);
  52. procedure window(left,top,right,bottom : byte);
  53. procedure textmode(mode:integer);
  54. procedure textcolor(colour:byte);
  55. procedure textbackground(colour:byte);
  56. procedure insline;
  57. procedure delline;
  58. procedure lowvideo;
  59. procedure normvideo;
  60. procedure highvideo;
  61. procedure assigncrt(var f:text);
  62. procedure delay(ms:word);
  63. procedure sound(hz:word);
  64. procedure nosound;
  65. {***************************************************************************}
  66. {***************************************************************************}
  67. implementation
  68. const extkeycode:char=#0;
  69. var maxrows,maxcols:word;
  70. calibration:longint;
  71. type Tkbdkeyinfo=record
  72. charcode,scancode:char;
  73. fbstatus,bnlsshift:byte;
  74. fsstate:word;
  75. time:longint;
  76. end;
  77. {if you have information on the folowing datastructure, please
  78. send them to me at [email protected]}
  79. {This datastructure is needed when we ask in what video mode we are,
  80. or we want to set up a new mode.}
  81. viomodeinfo=record
  82. cb:word; { length of the entire data
  83. structure }
  84. fbtype, { bit mask of mode being set}
  85. color: byte; { number of colors (power of 2) }
  86. col, { number of text columns }
  87. row, { number of text rows }
  88. hres, { horizontal resolution }
  89. vres: word; { vertical resolution }
  90. fmt_ID, { attribute format
  91. ! more info wanted !}
  92. attrib: byte; { number of attributes }
  93. buf_addr, { physical address of
  94. videobuffer, e.g. $0b800}
  95. buf_length, { length of a videopage (bytes)}
  96. full_length, { total video-memory on video-
  97. card (bytes)}
  98. partial_length:longint; { ????? info wanted !}
  99. ext_data_addr:pointer; { ????? info wanted !}
  100. end;
  101. Pviomodeinfo=^viomodeinfo;
  102. {EMXWRAP.DLL has strange calling conventions: All parameters must have
  103. a 4 byte size.}
  104. function _KbdCharIn(var Akeyrec:Tkbdkeyinfo;wait,kbdhandle:longint):word;[C];
  105. function _KbdPeek(var Akeyrec:TkbdkeyInfo;kbdhandle:word):word;[C];
  106. function _DosSleep(time:longint):word;[C];
  107. function _VioScrollUp(top,left,bottom,right,lines:longint;
  108. var screl:word;viohandle:longint):word;[C];
  109. function _VioScrollDn(top,left,bottom,right,lines:longint;
  110. var screl:word;viohandle:longint):word;[C];
  111. function _VioGetCurPos(var row,column:word;viohandle:longint):word;[C];
  112. function _VioSetCurPos(row,column,viohandle:longint):word;[C];
  113. function _VioWrtTTY(s:Pchar;len,viohandle:longint):word;[C];
  114. function _VioWrtCharStrAtt(var s:char;len,row,col:longint;var attr:byte;
  115. viohandle:longint):word;[C];
  116. function _VioGetMode (var Amodeinfo:viomodeinfo;viohandle:longint):word;[C];
  117. function _VioSetMode (var Amodeinfo:viomodeinfo;viohandle:longint):word;[C];
  118. procedure setscreenmode(mode:word);
  119. { This procedure sets a new videomode. Note that the constants passes to
  120. this procedure are different than in the dos mode.}
  121. const modecols:array[0..2] of word=(40,80,132);
  122. moderows:array[0..3] of word=(25,28,43,50);
  123. var newmode:viomodeinfo;
  124. begin
  125. if os_mode=osOS2 then
  126. begin
  127. newmode.cb:=8;
  128. newmode.fbtype:=1; {Non graphics colour mode.}
  129. newmode.color:=4; {We want 16 colours, 2^4=16.}
  130. newmode.col:=modecols[mode and 15];
  131. newmode.row:=moderows[mode shr 4];
  132. if _viosetmode(newmode,0)=0 then
  133. crt_error:=cenoerror
  134. else
  135. crt_error:=cemodeset;
  136. maxcols:=newmode.col;
  137. maxrows:=newmode.row;
  138. end
  139. else
  140. begin
  141. maxcols:=modecols[mode and 15];
  142. maxrows:=moderows[mode shr 4];
  143. crt_error:=cenoerror;
  144. {Set correct vertical resolution.}
  145. asm
  146. movw $0x1202,%ax
  147. movw 8(%ebp),%bx
  148. shrw $4,%bx
  149. cmpb $2,%bl
  150. jne crtsetmode_a1
  151. decw %ax
  152. crtsetmode_a1:
  153. mov $0x30,%bl
  154. int $0x10
  155. end;
  156. {132 column mode in DOS is videocard dependend.}
  157. if mode and 15=2 then
  158. begin
  159. crt_error:=cemodeset;
  160. exit;
  161. end;
  162. {Switch to correct mode.}
  163. asm
  164. mov 8(%ebp),%bx
  165. and $15,%bl
  166. mov $1,%ax
  167. cmp $1,%bl
  168. jne crtsetmode_b1
  169. mov $3,%al
  170. crtsetmode_b1:
  171. int $0x10
  172. {Use alternate print-screen function.}
  173. mov $0x12,%ah
  174. mov $0x20,%bl
  175. int $0x10
  176. end;
  177. {Set correct font.}
  178. case mode shr 4 of
  179. 1:
  180. {Set 8x14 font.}
  181. asm
  182. mov $0x1111,%ax
  183. mov $0,%bl
  184. int $0x10
  185. end;
  186. 2,3:
  187. {Set 8x8 font.}
  188. asm
  189. mov $0x1112,%ax
  190. mov $0,%bl
  191. int $0x10
  192. end;
  193. end;
  194. end;
  195. end;
  196. procedure getcursor(var y,x:word);
  197. {Get the cursor position.}
  198. begin
  199. if os_mode=osOS2 then
  200. _viogetcurpos(y,x,0)
  201. else
  202. asm
  203. movb $3,%ah
  204. movb $0,%bh
  205. int $0x10
  206. movl y,%eax
  207. movl x,%ebx
  208. movb %dh,(%eax)
  209. movb %dl,(%ebx)
  210. end;
  211. end;
  212. procedure setcursor(y,x:word);
  213. {Set the cursor position.}
  214. begin
  215. if os_mode=osOS2 then
  216. _viosetcurpos(y,x,0)
  217. else
  218. asm
  219. movb $2,%ah
  220. movb $0,%bh
  221. movb y,%dh
  222. movb x,%dl
  223. int $0x10
  224. end;
  225. end;
  226. procedure scroll_up(top,left,bottom,right,lines:word;var screl:word);
  227. begin
  228. if os_mode=osOS2 then
  229. _vioscrollup(top,left,bottom,right,lines,screl,0)
  230. else
  231. asm
  232. movb $6,%ah
  233. movb lines,%al
  234. movl screl,%edi
  235. movb 1(%edi),%bh
  236. movb top,%ch
  237. movb left,%cl
  238. movb bottom,%dh
  239. movb right,%dl
  240. int $0x10
  241. end;
  242. end;
  243. procedure scroll_dn(top,left,bottom,right,lines:word;var screl:word);
  244. begin
  245. if os_mode=osOS2 then
  246. _vioscrolldn(top,left,bottom,right,lines,screl,0)
  247. else
  248. asm
  249. movb $7,%ah
  250. movb lines,%al
  251. movl screl,%edi
  252. movb 1(%edi),%bh
  253. movb top,%ch
  254. movb left,%cl
  255. movb bottom,%dh
  256. movb right,%dl
  257. int $0x10
  258. end;
  259. end;
  260. function keypressed:boolean;
  261. {Checks if a key is pressed.}
  262. var Akeyrec:Tkbdkeyinfo;
  263. begin
  264. if os_mode=osOS2 then
  265. begin
  266. _kbdpeek(Akeyrec,0);
  267. keypressed:=(extkeycode<>#0) or ((Akeyrec.fbstatus and $40)<>0);
  268. end
  269. else
  270. begin
  271. if extkeycode<>#0 then
  272. begin
  273. keypressed:=true;
  274. exit
  275. end
  276. else
  277. asm
  278. movb $1,%ah
  279. int $0x16
  280. setnz %al
  281. movb %al,__RESULT
  282. end;
  283. end;
  284. end;
  285. function readkey:char;
  286. {Reads the next character from the keyboard.}
  287. var Akeyrec:Tkbdkeyinfo;
  288. c,s:char;
  289. begin
  290. if extkeycode<>#0 then
  291. begin
  292. readkey:=extkeycode;
  293. extkeycode:=#0
  294. end
  295. else
  296. begin
  297. if os_mode=osOS2 then
  298. begin
  299. _kbdcharin(Akeyrec,0,0);
  300. c:=Akeyrec.charcode;
  301. s:=Akeyrec.scancode;
  302. end
  303. else
  304. begin
  305. asm
  306. movb $0,%ah
  307. int $0x16
  308. movb %al,c
  309. movb %ah,s
  310. end;
  311. end;
  312. if c=#0 then
  313. extkeycode:=s;
  314. readkey:=c;
  315. end;
  316. end;
  317. procedure clrscr;
  318. {Clears the current window.}
  319. var screl:word;
  320. begin
  321. screl:=$20+textattr shl 8;
  322. scroll_up(hi(windmin),lo(windmin),
  323. hi(windmax),lo(windmax),
  324. hi(windmax)-hi(windmin)+1,
  325. screl);
  326. gotoXY(1,1);
  327. end;
  328. procedure gotoXY(x,y:byte);
  329. {Positions the cursor on (x,y) relative to the window origin.}
  330. begin
  331. if x<1 then
  332. x:=1;
  333. if y<1 then
  334. y:=1;
  335. if y+hi(windmin)-2>=hi(windmax) then
  336. y:=hi(windmax)-hi(windmin)+1;
  337. if x+lo(windmin)-2>=lo(windmax) then
  338. x:=lo(windmax)-lo(windmin)+1;
  339. setcursor(y+hi(windmin)-1,x+lo(windmin)-1);
  340. end;
  341. function whereX:byte;
  342. {Returns the x position of the cursor.}
  343. var x,y:word;
  344. begin
  345. getcursor(y,x);
  346. whereX:=x-lo(windmin)+1;
  347. end;
  348. function whereY:byte;
  349. {Returns the y position of the cursor.}
  350. var x,y:word;
  351. begin
  352. getcursor(y,x);
  353. whereY:=y-hi(windmin)+1;
  354. end;
  355. procedure delline;
  356. {Deletes the line at the cursor.}
  357. var row,left,right,bot:longint;
  358. fil:word;
  359. begin
  360. row:=whereY;
  361. left:=lo(windmin)+1;
  362. right:=lo(windmax)+1;
  363. bot:=hi(windmax)+1;
  364. fil:=$20 or (textattr shl 8);
  365. scroll_up(row+1,left,bot,right,1,fil);
  366. end;
  367. procedure insline;
  368. {Inserts a line at the cursor position.}
  369. var row,left,right,bot:longint;
  370. fil:word;
  371. begin
  372. row:=whereY;
  373. left:=lo(windmin)+1;
  374. right:=lo(windmax)+1;
  375. bot:=hi(windmax);
  376. fil:=$20 or (textattr shl 8);
  377. scroll_dn(row,left,bot-1,right,1,fil);
  378. end;
  379. procedure textmode(mode:integer);
  380. { Use this procedure to set-up a specific text-mode.}
  381. begin
  382. textattr:=$07;
  383. lastmode:=mode;
  384. mode:=mode and $ff;
  385. setscreenmode(mode);
  386. windmin:=0;
  387. windmax:=(maxcols-1) or ((maxrows-1) shl 8);
  388. clrscr;
  389. end;
  390. procedure textcolor(colour:byte);
  391. {All text written after calling this will have color as foreground colour.}
  392. begin
  393. textattr:=(textattr and $70) or (colour and $f)+colour and 128;
  394. end;
  395. procedure textbackground(colour:byte);
  396. {All text written after calling this will have colour as background colour.}
  397. begin
  398. textattr:=(textattr and $8f) or ((colour and $7) shl 4);
  399. end;
  400. procedure normvideo;
  401. {Changes the text-background to black and the foreground to white.}
  402. begin
  403. textattr:=$7;
  404. end;
  405. procedure lowvideo;
  406. {All text written after this will have low intensity.}
  407. begin
  408. textattr:=textattr and $f7;
  409. end;
  410. procedure highvideo;
  411. {All text written after this will have high intensity.}
  412. begin
  413. textattr:=textattr or $8;
  414. end;
  415. procedure delay(ms:word);
  416. var i,j:longint;
  417. {Waits ms microseconds. The DOS code is copied from the DOS rtl.}
  418. begin
  419. {Under OS/2 we could also calibrate like under DOS. But this is
  420. unreliable, because OS/2 can hold our programs while calibrating,
  421. if it needs the processor for other things.}
  422. if os_mode=osOS2 then
  423. _dossleep(ms)
  424. else
  425. begin
  426. for i:=1 to ms do
  427. for j:=1 to calibration do
  428. begin
  429. end;
  430. end;
  431. end;
  432. procedure window(left,top,right,bottom:byte);
  433. {Change the write window to the given coordinates.}
  434. begin
  435. if (left<1) or
  436. (top<1) or
  437. (right>maxcols) or
  438. (bottom>maxrows) or
  439. (left>right) or
  440. (top>bottom) then
  441. exit;
  442. windmin:=(left-1) or ((top-1) shl 8);
  443. windmax:=(right-1) or ((bottom-1) shl 8);
  444. gotoXY(1,1);
  445. end;
  446. procedure writePchar(s:Pchar;len:word);
  447. {Write a series of characters to the screen.
  448. Not very fast, but is just text-mode isn't it?}
  449. var x,y:word;
  450. c:char;
  451. i:integer;
  452. screl:word;
  453. begin
  454. for i:=0 to len-1 do
  455. begin
  456. getcursor(y,x);
  457. case s[i] of
  458. #8:
  459. x:=(x-lo(windmin)) and $fff8+8;
  460. #10:
  461. begin
  462. end;
  463. #13:
  464. begin
  465. x:=lo(windmin);
  466. inc(y);
  467. end;
  468. else
  469. begin
  470. if os_mode=osOS2 then
  471. _viowrtcharstratt(s[i],1,y,x,textattr,0)
  472. else
  473. asm
  474. movl s,%eax
  475. movswl i,%ebx
  476. movb (%eax,%ebx),%al
  477. movb $9,%ah
  478. movb $0,%bh
  479. movb U_CRT_TEXTATTR,%bl
  480. movw $1,%cx
  481. int $0x10
  482. end;
  483. inc(x);
  484. end;
  485. end;
  486. if x>lo(windmax) then
  487. begin
  488. x:=lo(windmin);
  489. inc(y);
  490. end;
  491. if y>hi(windmax) then
  492. begin
  493. screl:=$20+textattr shl 8;
  494. scroll_up(hi(windmin),lo(windmin),
  495. hi(windmax),lo(windmax),
  496. 1,screl);
  497. y:=hi(windmax);
  498. end;
  499. setcursor(y,x);
  500. end;
  501. end;
  502. function crtread(var f:text):word;
  503. {Read a series of characters from the console.}
  504. var max,curpos,i:integer;
  505. c:char;
  506. clist:array[0..2] of char;
  507. begin
  508. max:=textrec(f).bufsize-2;
  509. curpos:=0;
  510. repeat
  511. c:=readkey;
  512. case c of
  513. #8:
  514. if curpos>0 then
  515. begin
  516. clist:=#8' '#8;
  517. writePchar(@clist,3);
  518. dec(curpos);
  519. end;
  520. #13:
  521. begin
  522. textrec(f).bufptr^[curpos]:=#13;
  523. inc(curpos);
  524. textrec(f).bufptr^[curpos]:=#10;
  525. inc(curpos);
  526. textrec(f).bufpos:=0;
  527. textrec(f).bufend:=curpos;
  528. break;
  529. end;
  530. #32..#255:
  531. if curpos<max then
  532. begin
  533. textrec(f).bufptr^[curpos]:=c;
  534. inc(curpos);
  535. writePchar(@c,1);
  536. end;
  537. end;
  538. until false;
  539. crtread:=0;
  540. end;
  541. function crtwrite(var f:text):word;
  542. {Write a series of characters to the console.}
  543. begin
  544. writePchar(Pchar(textrec(f).bufptr),textrec(f).bufpos);
  545. textrec(f).bufpos:=0;
  546. crtwrite:=0;
  547. end;
  548. function crtreturn(var f:text):word;
  549. {Dummy: return zero.}
  550. begin
  551. crtreturn:=0;
  552. end;
  553. function crtopen(var f:text):word;
  554. {Opens a file that is assigned to the crt console.}
  555. var inout,flush,close:pointer;
  556. begin
  557. if textrec(f).mode=fminput then
  558. begin
  559. inout:=@crtread;
  560. flush:=@crtreturn;
  561. close:=@crtreturn;
  562. end
  563. else
  564. begin
  565. textrec(f).mode:=fmoutput;
  566. inout:=@crtwrite;
  567. flush:=@crtwrite;
  568. close:=@crtreturn;
  569. end;
  570. textrec(f).inoutfunc:=inout;
  571. textrec(f).flushfunc:=flush;
  572. textrec(f).closefunc:=close;
  573. crtopen:=0;
  574. end;
  575. procedure assigncrt(var f:text);
  576. {Assigns a file to the crt console.}
  577. begin
  578. textrec(f).mode:=fmclosed;
  579. textrec(f).bufsize:=128;
  580. textrec(f).bufptr:=@textrec(f).buffer;
  581. textrec(f).openfunc:=@crtopen;
  582. end;
  583. procedure sound(hz:word);
  584. {sound and nosound are not implemented because the OS/2 API supports a freq/
  585. duration procedure instead of start/stop procedures.}
  586. begin
  587. end;
  588. procedure nosound;
  589. begin
  590. end;
  591. function get_ticks:word;
  592. type Pword=^word;
  593. begin
  594. get_ticks:=Pword(longint(first_page)+$46c)^;
  595. end;
  596. procedure initdelay;
  597. {Calibrate the delay procedure. Copied from DOS rtl.}
  598. var first:word;
  599. begin
  600. calibration:=0;
  601. { wait for new tick }
  602. first:=get_ticks;
  603. while get_ticks=first do
  604. begin
  605. end;
  606. first:=get_ticks;
  607. { this estimates calibration }
  608. while get_ticks=first do
  609. inc(calibration);
  610. { calculate this to ms }
  611. calibration:=calibration div 70;
  612. while true do
  613. begin
  614. first:=get_ticks;
  615. while get_ticks=first do
  616. begin
  617. end;
  618. first:=get_ticks;
  619. delay(55);
  620. if first=get_ticks then
  621. exit
  622. else
  623. begin
  624. { decrement calibration two percent }
  625. calibration:=calibration-calibration div 50;
  626. dec(calibration);
  627. end;
  628. end;
  629. end;
  630. {Initialization.}
  631. type Pbyte=^byte;
  632. var curmode:viomodeinfo;
  633. mode:byte;
  634. begin
  635. textattr:=lightgray;
  636. if os_mode=osOS2 then
  637. begin
  638. curmode.cb:=sizeof(curmode);
  639. _viogetmode(curmode,0);
  640. maxcols:=curmode.col;
  641. maxrows:=curmode.row;
  642. lastmode:=0;
  643. case maxcols of
  644. 40:
  645. lastmode:=0;
  646. 80:
  647. lastmode:=1;
  648. 132:
  649. lastmode:=2;
  650. end;
  651. case maxrows of
  652. 25:;
  653. 28:
  654. inc(lastmode,16);
  655. 43:
  656. inc(lastmode,32);
  657. 50:
  658. inc(lastmode,48);
  659. end
  660. end
  661. else
  662. begin
  663. {Request video mode to determine columns.}
  664. asm
  665. mov $0x0f,%ah
  666. int $0x10
  667. mov %al,_MODE
  668. end;
  669. case mode of
  670. 0,1:
  671. begin
  672. lastmode:=0;
  673. maxcols:=40;
  674. end;
  675. else
  676. begin
  677. lastmode:=1;
  678. maxcols:=80;
  679. end;
  680. end;
  681. {Get number of rows from realmode $0040:$0084.}
  682. maxrows:=Pbyte(longint(first_page)+$484)^;
  683. case maxrows of
  684. 25:;
  685. 28:
  686. inc(lastmode,16);
  687. 43:
  688. inc(lastmode,32);
  689. 50:
  690. inc(lastmode,48);
  691. end
  692. end;
  693. window(1,1,maxcols,maxrows);
  694. if os_mode=osDOS then
  695. initdelay;
  696. crt_error:=cenoerror;
  697. assigncrt(input);
  698. reset(Input);
  699. assigncrt(output);
  700. rewrite(output);
  701. end.