video.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. {
  2. System independent low-level video interface for linux
  3. $Id$
  4. }
  5. uses
  6. Linux, Strings, FileCtrl, TermInfo;
  7. var
  8. LastCursorType : byte;
  9. TtyFd: Longint;
  10. Console: Boolean;
  11. OldVideoBuf: PVideoBuf;
  12. {$ifdef logging}
  13. f: file;
  14. const
  15. logstart: string = '';
  16. nl: char = #10;
  17. logend: string = #10#10;
  18. {$endif logging}
  19. {$ASMMODE ATT}
  20. const
  21. can_delete_term : boolean = false;
  22. procedure SendEscapeSeqNdx(Ndx: Word);
  23. var
  24. P,pdelay: PChar;
  25. begin
  26. if not assigned(cur_term_Strings) then
  27. RunError(219);
  28. P:=cur_term_Strings^[Ndx];
  29. if assigned(p) then
  30. begin { Do not transmit the delays }
  31. pdelay:=strpos(p,'$<');
  32. if assigned(pdelay) then
  33. pdelay^:=#0;
  34. fdWrite(TTYFd, P^, StrLen(P));
  35. if assigned(pdelay) then
  36. pdelay^:='$';
  37. end;
  38. end;
  39. procedure SendEscapeSeq(const S: String);
  40. begin
  41. fdWrite(TTYFd, S[1], Length(S));
  42. end;
  43. Function IntStr(l:longint):string;
  44. var
  45. s : string;
  46. begin
  47. Str(l,s);
  48. IntStr:=s;
  49. end;
  50. Function XY2Ansi(x,y,ox,oy:longint):String;
  51. {
  52. Returns a string with the escape sequences to go to X,Y on the screen
  53. }
  54. Begin
  55. if y=oy then
  56. begin
  57. if x=ox then
  58. begin
  59. XY2Ansi:='';
  60. exit;
  61. end;
  62. if x=1 then
  63. begin
  64. XY2Ansi:=#13;
  65. exit;
  66. end;
  67. if x>ox then
  68. begin
  69. XY2Ansi:=#27'['+IntStr(x-ox)+'C';
  70. exit;
  71. end
  72. else
  73. begin
  74. XY2Ansi:=#27'['+IntStr(ox-x)+'D';
  75. exit;
  76. end;
  77. end;
  78. if x=ox then
  79. begin
  80. if y>oy then
  81. begin
  82. XY2Ansi:=#27'['+IntStr(y-oy)+'B';
  83. exit;
  84. end
  85. else
  86. begin
  87. XY2Ansi:=#27'['+IntStr(oy-y)+'A';
  88. exit;
  89. end;
  90. end;
  91. if (x=1) and (oy+1=y) then
  92. XY2Ansi:=#13#10
  93. else
  94. XY2Ansi:=#27'['+IntStr(y)+';'+IntStr(x)+'H';
  95. End;
  96. const
  97. AnsiTbl : string[8]='04261537';
  98. Function Attr2Ansi(Attr,OAttr:longint):string;
  99. {
  100. Convert Attr to an Ansi String, the Optimal code is calculate
  101. with use of the old OAttr
  102. }
  103. var
  104. hstr : string[16];
  105. OFg,OBg,Fg,Bg : longint;
  106. procedure AddSep(ch:char);
  107. begin
  108. if length(hstr)>0 then
  109. hstr:=hstr+';';
  110. hstr:=hstr+ch;
  111. end;
  112. begin
  113. if Attr=OAttr then
  114. begin
  115. Attr2Ansi:='';
  116. exit;
  117. end;
  118. Hstr:='';
  119. Fg:=Attr and $f;
  120. Bg:=Attr shr 4;
  121. OFg:=OAttr and $f;
  122. OBg:=OAttr shr 4;
  123. if (OFg<>7) or (Fg=7) or ((OFg>7) and (Fg<8)) or ((OBg>7) and (Bg<8)) then
  124. begin
  125. hstr:='0';
  126. OFg:=7;
  127. OBg:=0;
  128. end;
  129. if (Fg>7) and (OFg<8) then
  130. begin
  131. AddSep('1');
  132. OFg:=OFg or 8;
  133. end;
  134. if (Bg and 8)<>(OBg and 8) then
  135. begin
  136. AddSep('5');
  137. OBg:=OBg or 8;
  138. end;
  139. if (Fg<>OFg) then
  140. begin
  141. AddSep('3');
  142. hstr:=hstr+AnsiTbl[(Fg and 7)+1];
  143. end;
  144. if (Bg<>OBg) then
  145. begin
  146. AddSep('4');
  147. hstr:=hstr+AnsiTbl[(Bg and 7)+1];
  148. end;
  149. if hstr='0' then
  150. hstr:='';
  151. Attr2Ansi:=#27'['+hstr+'m';
  152. end;
  153. procedure UpdateTTY(Force:boolean);
  154. type
  155. tchattr=packed record
  156. ch : char;
  157. attr : byte;
  158. end;
  159. var
  160. outbuf : array[0..1023+255] of char;
  161. chattr : tchattr;
  162. skipped : boolean;
  163. outptr,
  164. spaces,
  165. eol,
  166. LastX,LastY,
  167. x,y,
  168. SpaceAttr,
  169. LastAttr : longint;
  170. p,pold : pvideocell;
  171. procedure outdata(hstr:string);
  172. begin
  173. while (eol>0) do
  174. begin
  175. hstr:=#13#10+hstr;
  176. dec(eol);
  177. end;
  178. move(hstr[1],outbuf[outptr],length(hstr));
  179. inc(outptr,length(hstr));
  180. if outptr>=1024 then
  181. begin
  182. {$ifdef logging}
  183. blockwrite(f,logstart[1],length(logstart));
  184. blockwrite(f,nl,1);
  185. blockwrite(f,outptr,sizeof(outptr));
  186. blockwrite(f,nl,1);
  187. blockwrite(f,outbuf,outptr);
  188. blockwrite(f,nl,1);
  189. {$endif logging}
  190. fdWrite(TTYFd,outbuf,outptr);
  191. outptr:=0;
  192. end;
  193. end;
  194. procedure OutClr(c:byte);
  195. begin
  196. if c=LastAttr then
  197. exit;
  198. OutData(Attr2Ansi(c,LastAttr));
  199. LastAttr:=c;
  200. end;
  201. procedure OutSpaces;
  202. begin
  203. if (Spaces=0) then
  204. exit;
  205. OutClr(SpaceAttr);
  206. OutData(Space(Spaces));
  207. LastX:=x;
  208. LastY:=y;
  209. Spaces:=0;
  210. end;
  211. begin
  212. OutPtr:=0;
  213. Eol:=0;
  214. skipped:=true;
  215. p:=PVideoCell(VideoBuf);
  216. pold:=PVideoCell(OldVideoBuf);
  217. { init Attr and X,Y }
  218. OutData(#27'[m'#27'[H');
  219. LastAttr:=7;
  220. LastX:=1;
  221. LastY:=1;
  222. for y:=1 to ScreenHeight do
  223. begin
  224. SpaceAttr:=0;
  225. Spaces:=0;
  226. for x:=1 to ScreenWidth do
  227. begin
  228. if (not force) and (p^=pold^) then
  229. begin
  230. if (Spaces>0) then
  231. OutSpaces;
  232. skipped:=true;
  233. end
  234. else
  235. begin
  236. if skipped then
  237. begin
  238. OutData(XY2Ansi(x,y,LastX,LastY));
  239. LastX:=x;
  240. LastY:=y;
  241. skipped:=false;
  242. end;
  243. chattr:=tchattr(p^);
  244. if chattr.ch in [#0,#255] then
  245. chattr.ch:=' ';
  246. if chattr.ch=' ' then
  247. begin
  248. if Spaces=0 then
  249. SpaceAttr:=chattr.Attr;
  250. if (chattr.attr and $f0)=(spaceattr and $f0) then
  251. chattr.Attr:=SpaceAttr
  252. else
  253. begin
  254. OutSpaces;
  255. SpaceAttr:=chattr.Attr;
  256. end;
  257. inc(Spaces);
  258. end
  259. else
  260. begin
  261. if (Spaces>0) then
  262. OutSpaces;
  263. if ord(chattr.ch)<32 then
  264. begin
  265. Chattr.Attr:= $ff xor Chattr.Attr;
  266. ChAttr.ch:= chr(ord(chattr.ch)+$30);
  267. end;
  268. if LastAttr<>chattr.Attr then
  269. OutClr(chattr.Attr);
  270. OutData(chattr.ch);
  271. LastX:=x+1;
  272. LastY:=y;
  273. end;
  274. p^:=tvideocell(chattr);
  275. end;
  276. inc(p);
  277. inc(pold);
  278. end;
  279. if (Spaces>0) then
  280. OutSpaces;
  281. if force then
  282. inc(eol);
  283. end;
  284. eol:=0;
  285. OutData(XY2Ansi(CursorX,CursorY,LastX,LastY));
  286. {$ifdef logging}
  287. blockwrite(f,logstart[1],length(logstart));
  288. blockwrite(f,nl,1);
  289. blockwrite(f,outptr,sizeof(outptr));
  290. blockwrite(f,nl,1);
  291. blockwrite(f,outbuf,outptr);
  292. blockwrite(f,nl,1);
  293. {$endif logging}
  294. fdWrite(TTYFd,outbuf,outptr);
  295. end;
  296. var
  297. InitialVideoTio, preInitVideoTio, postInitVideoTio: linux.termios;
  298. inputRaw, outputRaw: boolean;
  299. procedure saveRawSettings(const tio: linux.termios);
  300. Begin
  301. with tio do
  302. begin
  303. inputRaw :=
  304. ((c_iflag and (IGNBRK or BRKINT or PARMRK or ISTRIP or
  305. INLCR or IGNCR or ICRNL or IXON)) = 0) and
  306. ((c_lflag and (ECHO or ECHONL or ICANON or ISIG or IEXTEN)) = 0);
  307. outPutRaw :=
  308. ((c_oflag and OPOST) = 0) and
  309. ((c_cflag and (CSIZE or PARENB)) = 0) and
  310. ((c_cflag and CS8) <> 0);
  311. end;
  312. end;
  313. procedure restoreRawSettings(tio: linux.termios);
  314. begin
  315. with tio do
  316. begin
  317. if inputRaw then
  318. begin
  319. c_iflag := c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  320. INLCR or IGNCR or ICRNL or IXON));
  321. c_lflag := c_lflag and
  322. (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  323. end;
  324. if outPutRaw then
  325. begin
  326. c_oflag := c_oflag and not(OPOST);
  327. c_cflag := c_cflag and not(CSIZE or PARENB) or CS8;
  328. end;
  329. end;
  330. TCSetAttr(1,TCSANOW,tio);
  331. end;
  332. procedure TargetEntry;
  333. begin
  334. TCGetAttr(1,InitialVideoTio);
  335. end;
  336. procedure TargetExit;
  337. begin
  338. TCSetAttr(1,TCSANOW,InitialVideoTio);
  339. end;
  340. procedure prepareInitVideo;
  341. begin
  342. TCGetAttr(1,preInitVideoTio);
  343. saveRawSettings(preInitVideoTio);
  344. end;
  345. procedure videoInitDone;
  346. begin
  347. TCGetAttr(1,postInitVideoTio);
  348. restoreRawSettings(postInitVideoTio);
  349. end;
  350. procedure prepareDoneVideo;
  351. var
  352. tio: linux.termios;
  353. begin
  354. TCGetAttr(1,tio);
  355. saveRawSettings(tio);
  356. TCSetAttr(1,TCSANOW,postInitVideoTio);
  357. end;
  358. procedure doneVideoDone;
  359. begin
  360. restoreRawSettings(preInitVideoTio);
  361. end;
  362. procedure InitVideo;
  363. const
  364. fontstr : string[3]=#27'(K';
  365. var
  366. ThisTTY: String[30];
  367. FName: String;
  368. WS: packed record
  369. ws_row, ws_col, ws_xpixel, ws_ypixel: Word;
  370. end;
  371. Err: Longint;
  372. prev_term : TerminalCommon_ptr1;
  373. begin
  374. {$ifndef CPUI386}
  375. LowAscii:=false;
  376. {$endif CPUI386}
  377. if VideoBufSize<>0 then
  378. begin
  379. clearscreen;
  380. if Console then
  381. SetCursorPos(1,1)
  382. else
  383. begin
  384. SendEscapeSeqNdx(cursor_home);
  385. SendEscapeSeq(#27'[H');
  386. end;
  387. exit;
  388. end;
  389. { check for tty }
  390. ThisTTY:=TTYName(stdin);
  391. if IsATTY(stdin) then
  392. begin
  393. { save current terminal characteristics and remove rawness }
  394. prepareInitVideo;
  395. { write code to set a correct font }
  396. fdWrite(stdout,fontstr[1],length(fontstr));
  397. { running on a tty, find out whether locally or remotely }
  398. if (Copy(ThisTTY, 1, 8) = '/dev/tty') and
  399. (ThisTTY[9] >= '0') and (ThisTTY[9] <= '9') then
  400. begin
  401. { running on the console }
  402. FName:='/dev/vcsa' + ThisTTY[9];
  403. TTYFd:=OpenFile(FName, filReadWrite); { open console }
  404. end
  405. else
  406. TTYFd:=-1;
  407. if TTYFd<>-1 then
  408. Console:=true
  409. else
  410. begin
  411. { running on a remote terminal, no error with /dev/vcsa }
  412. Console:=False;
  413. LowAscii:=false;
  414. TTYFd:=stdout;
  415. end;
  416. ioctl(stdin, TIOCGWINSZ, @WS);
  417. if WS.ws_Col=0 then
  418. WS.ws_Col:=80;
  419. if WS.ws_Row=0 then
  420. WS.ws_Row:=25;
  421. ScreenWidth:=WS.ws_Col;
  422. { TDrawBuffer only has FVMaxWidth elements
  423. larger values lead to crashes }
  424. if ScreenWidth> FVMaxWidth then
  425. ScreenWidth:=FVMaxWidth;
  426. ScreenHeight:=WS.ws_Row;
  427. CursorX:=1;
  428. CursorY:=1;
  429. ScreenColor:=True;
  430. { allocate pmode memory buffer }
  431. VideoBufSize:=ScreenWidth*ScreenHeight*2;
  432. GetMem(VideoBuf,VideoBufSize);
  433. GetMem(OldVideoBuf,VideoBufSize);
  434. { Start with a clear screen }
  435. if not Console then
  436. begin
  437. prev_term:=cur_term;
  438. setupterm(nil, stdout, err);
  439. can_delete_term:=assigned(prev_term) and (prev_term<>cur_term);
  440. SendEscapeSeqNdx(cursor_home);
  441. SendEscapeSeqNdx(cursor_normal);
  442. SendEscapeSeqNdx(cursor_visible);
  443. SendEscapeSeqNdx(enter_ca_mode);
  444. SetCursorType(crUnderLine);
  445. end
  446. else if not assigned(cur_term) then
  447. begin
  448. setupterm(nil, stdout, err);
  449. can_delete_term:=false;
  450. end;
  451. ClearScreen;
  452. {$ifdef logging}
  453. assign(f,'video.log');
  454. rewrite(f,1);
  455. {$endif logging}
  456. { save new terminal characteristics and possible restore rawness }
  457. videoInitDone;
  458. end
  459. else
  460. ErrorCode:=errVioInit; { not a TTY }
  461. end;
  462. procedure DoneVideo;
  463. begin
  464. if VideoBufSize=0 then
  465. exit;
  466. prepareDoneVideo;
  467. ClearScreen;
  468. if Console then
  469. SetCursorPos(1,1)
  470. else
  471. begin
  472. SendEscapeSeqNdx(exit_ca_mode);
  473. SendEscapeSeqNdx(cursor_home);
  474. SendEscapeSeqNdx(cursor_normal);
  475. SendEscapeSeqNdx(cursor_visible);
  476. SetCursorType(crUnderLine);
  477. SendEscapeSeq(#27'[H');
  478. end;
  479. FreeMem(VideoBuf,VideoBufSize);
  480. FreeMem(OldVideoBuf,VideoBufSize);
  481. VideoBufSize:=0;
  482. doneVideoDone;
  483. if can_delete_term then
  484. begin
  485. del_curterm(cur_term);
  486. can_delete_term:=false;
  487. end;
  488. {$ifdef logging}
  489. close(f);
  490. {$endif logging}
  491. end;
  492. procedure ClearScreen;
  493. begin
  494. FillWord(VideoBuf^,VideoBufSize shr 1,$0720);
  495. if Console then
  496. UpdateScreen(true)
  497. else
  498. begin
  499. SendEscapeSeq(#27'[0m');
  500. SendEscapeSeqNdx(clear_screen);
  501. end;
  502. end;
  503. procedure UpdateScreen(Force: Boolean);
  504. var
  505. DoUpdate : boolean;
  506. begin
  507. if LockUpdateScreen<>0 then
  508. exit;
  509. if not force then
  510. begin
  511. {$ifdef i386}
  512. asm
  513. movl VideoBuf,%esi
  514. movl OldVideoBuf,%edi
  515. movl VideoBufSize,%ecx
  516. shrl $2,%ecx
  517. repe
  518. cmpsl
  519. orl %ecx,%ecx
  520. setne DoUpdate
  521. end;
  522. {$endif i386}
  523. end
  524. else
  525. DoUpdate:=true;
  526. if not DoUpdate then
  527. exit;
  528. if Console then
  529. begin
  530. fdSeek(TTYFd, 4, skBeg);
  531. fdWrite(TTYFd, VideoBuf^,VideoBufSize);
  532. end
  533. else
  534. begin
  535. UpdateTTY(force);
  536. end;
  537. Move(VideoBuf^, OldVideoBuf^, VideoBufSize);
  538. end;
  539. function GetCapabilities: Word;
  540. begin
  541. { about cpColor... we should check the terminfo database... }
  542. GetCapabilities:=cpUnderLine + cpBlink + cpColor;
  543. end;
  544. procedure SetCursorPos(NewCursorX, NewCursorY: Word);
  545. var
  546. Pos : array [1..2] of Byte;
  547. begin
  548. if Console then
  549. begin
  550. fdSeek(TTYFd, 2, skBeg);
  551. Pos[1]:=NewCursorX;
  552. Pos[2]:=NewCursorY;
  553. fdWrite(TTYFd, Pos, 2);
  554. end
  555. else
  556. begin
  557. { newcursorx,y is 0 based ! }
  558. SendEscapeSeq(XY2Ansi(NewCursorX+1,NewCursorY+1,0,0));
  559. end;
  560. CursorX:=NewCursorX+1;
  561. CursorY:=NewCursorY+1;
  562. end;
  563. function GetCursorType: Word;
  564. begin
  565. GetCursorType:=LastCursorType;
  566. end;
  567. procedure SetCursorType(NewType: Word);
  568. begin
  569. LastCursorType:=NewType;
  570. case NewType of
  571. crBlock :
  572. SendEscapeSeq(#27'[?17;0;64c');
  573. crHidden :
  574. SendEscapeSeq(#27'[?1c');
  575. else
  576. SendEscapeSeq(#27'[?2c');
  577. end;
  578. end;
  579. function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
  580. begin
  581. DefaultVideoModeSelector:=false;
  582. end;
  583. procedure RegisterVideoModes;
  584. begin
  585. end;
  586. {
  587. $Log$
  588. Revision 1.2 2000-10-26 23:08:48 peter
  589. * merged freebsd from fixes
  590. Revision 1.1.2.1 2000/10/25 12:23:20 marco
  591. * Linux dir split up
  592. Revision 1.1.2.11 2000/10/19 07:28:18 pierre
  593. * do not transmit the delay part in terminfo strings
  594. Revision 1.1.2.10 2000/10/13 15:09:40 pierre
  595. * Handle zero size for term correctly
  596. Revision 1.1.2.9 2000/10/10 16:39:44 pierre
  597. + transform low ascii chars by changing their colors and adding 48
  598. Revision 1.1.2.8 2000/10/10 15:34:58 pierre
  599. * fixe a bug in Attr2Ansi
  600. Revision 1.1.2.7 2000/10/10 10:52:56 pierre
  601. + FVMaxWidth to avoid too wide screens
  602. Revision 1.1.2.6 2000/10/09 21:57:42 pierre
  603. * Set LowAscii to false only if not on a local tty
  604. Revision 1.1.2.5 2000/10/09 16:29:15 pierre
  605. * more linux terminal fixes
  606. Revision 1.1.2.4 2000/10/04 11:44:33 pierre
  607. add TargetEntry and TargetExit procedures (needed for linux)
  608. Revision 1.1.2.3 2000/10/03 22:31:29 pierre
  609. * avoid invalid cur_term var
  610. Revision 1.1.2.2 2000/09/25 13:21:19 jonas
  611. + added preserving of rawness of terminal when going though
  612. init/donevideo
  613. * del_term() is now called in donevideo
  614. * if initvideo is called while the video is already iniialized, the
  615. screen is cleared and the cursor is set home, instead of going
  616. through the whole donevideo and then initvideo
  617. Revision 1.1.2.1 2000/08/02 12:29:06 jonas
  618. * fixed crashes under ncurses 4 by adding auto-detection for ncurses 4/5
  619. * cur_term is not directly usable anymore for the largest part because
  620. of a different record layout in ncurses 4/5, therefore the pointers
  621. cur_term_booleans, cur_term_numbers, cur_term_strings and
  622. cur_term_common are now available
  623. * adapted video.inc to use the new naming convention
  624. Revision 1.1 2000/07/13 06:29:39 michael
  625. + Initial import
  626. Revision 1.3 2000/06/30 12:28:57 jonas
  627. * fixed termtype structure
  628. Revision 1.2 2000/03/12 15:02:10 peter
  629. * removed unused var
  630. Revision 1.1 2000/01/06 01:20:31 peter
  631. * moved out of packages/ back to topdir
  632. Revision 1.1 1999/11/24 23:36:38 peter
  633. * moved to packages dir
  634. Revision 1.5 1999/07/05 21:38:19 peter
  635. * works now also on not /dev/tty* units
  636. * if col,row is 0,0 then take 80x25 by default
  637. Revision 1.4 1999/02/22 12:46:16 peter
  638. + lowascii boolean if ascii < #32 is handled correctly
  639. Revision 1.3 1999/02/08 10:34:26 peter
  640. * cursortype futher implemented
  641. Revision 1.2 1998/12/12 19:13:03 peter
  642. * keyboard updates
  643. * make test target, make all only makes units
  644. Revision 1.1 1998/12/04 12:48:30 peter
  645. * moved some dirs
  646. Revision 1.6 1998/12/03 10:18:07 peter
  647. * tty fixed
  648. Revision 1.5 1998/12/01 15:08:17 peter
  649. * fixes for linux
  650. Revision 1.4 1998/11/01 20:29:12 peter
  651. + lockupdatescreen counter to not let updatescreen() update
  652. Revision 1.3 1998/10/29 12:49:50 peter
  653. * more fixes
  654. Revision 1.1 1998/10/26 11:31:47 peter
  655. + inital include files
  656. }