2
0

system.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Carl Eric Codere
  5. member of the Free Pascal development team
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$define ATARI}
  13. unit {$ifdef VER1_0}sysatari{$else}{$ifdef VER0_99}sysatari{$ELSE}system{$endif}{$ENDIF};
  14. {--------------------------------------------------------------------}
  15. { LEFT TO DO: }
  16. {--------------------------------------------------------------------}
  17. { o SBrk }
  18. { o Implement truncate }
  19. { o Implement paramstr(0) }
  20. {--------------------------------------------------------------------}
  21. {$I os.inc}
  22. interface
  23. {$I systemh.inc}
  24. type
  25. THandle = longint;
  26. {$I heaph.inc}
  27. {Platform specific information}
  28. const
  29. LineEnding = #10;
  30. LFNSupport = true;
  31. DirectorySeparator = '/';
  32. DriveSeparator = ':';
  33. PathSeparator = ';';
  34. FileNameCaseSensitive = false;
  35. maxExitCode = 255;
  36. sLineBreak: string [1] = LineEnding;
  37. { used for single computations }
  38. const BIAS4 = $7f-1;
  39. const
  40. UnusedHandle = $ffff;
  41. StdInputHandle = 0;
  42. StdOutputHandle = 1;
  43. StdErrorHandle = $ffff;
  44. implementation
  45. {$I system.inc}
  46. {$I lowmath.inc}
  47. const
  48. argc : longint = 0;
  49. var
  50. errno : integer;
  51. {$S-}
  52. procedure Stack_Check; assembler;
  53. { Check for local variable allocation }
  54. { On Entry -> d0 : size of local stack we are trying to allocate }
  55. asm
  56. XDEF STACKCHECK
  57. move.l sp,d1 { get value of stack pointer }
  58. sub.l d0,d1 { sp - stack_size }
  59. sub.l #2048,d1
  60. cmp.l __BREAK,d1
  61. bgt @st1nosweat
  62. move.l #202,d0
  63. jsr HALT_ERROR
  64. @st1nosweat:
  65. end;
  66. Procedure Error2InOut;
  67. Begin
  68. if (errno <= -2) and (errno >= -11) then
  69. InOutRes:=150-errno { 150+errno }
  70. else
  71. Begin
  72. case errno of
  73. -32 : InOutRes:=1;
  74. -33 : InOutRes:=2;
  75. -34 : InOutRes:=3;
  76. -35 : InOutRes:=4;
  77. -36 : InOutRes:=5;
  78. -37 : InOutRes:=8;
  79. -39 : InOutRes:=8;
  80. -40 : InOutRes:=9;
  81. -46 : InOutRes:=15;
  82. -67..-64 : InOutRes:=153;
  83. -15 : InOutRes:=151;
  84. -13 : InOutRes:=150;
  85. else
  86. InOutres := word(errno);
  87. end;
  88. end;
  89. errno:=0;
  90. end;
  91. procedure halt(errnum : byte);
  92. begin
  93. do_exit;
  94. flush(stderr);
  95. asm
  96. clr.l d0
  97. move.b errnum,d0
  98. move.w d0,-(sp)
  99. move.w #$4c,-(sp)
  100. trap #1
  101. end;
  102. end;
  103. function args : pointer; assembler;
  104. asm
  105. move.l __ARGS,d0
  106. end;
  107. Function GetParamCount(const p: pchar): longint;
  108. var
  109. i: word;
  110. count: word;
  111. Begin
  112. i:=0;
  113. count:=0;
  114. while p[count] <> #0 do
  115. Begin
  116. if (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) then
  117. Begin
  118. i:=i+1;
  119. while (p[count] <> ' ') and (p[count] <> #9) and (p[count] <> #0) do
  120. count:=count+1;
  121. end;
  122. if p[count] = #0 then break;
  123. count:=count+1;
  124. end;
  125. GetParamCount:=longint(i);
  126. end;
  127. Function GetParam(index: word; const p : pchar): string;
  128. { On Entry: index = string index to correct parameter }
  129. { On exit: = correct character index into pchar array }
  130. { Returns correct index to command line argument }
  131. var
  132. count: word;
  133. localindex: word;
  134. l: byte;
  135. temp: string;
  136. Begin
  137. temp:='';
  138. count := 0;
  139. { first index is one }
  140. localindex := 1;
  141. l:=0;
  142. While p[count] <> #0 do
  143. Begin
  144. if (p[count] <> ' ') and (p[count] <> #9) then
  145. Begin
  146. if localindex = index then
  147. Begin
  148. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) and (l < 256) do
  149. Begin
  150. temp:=temp+p[count];
  151. l:=l+1;
  152. count:=count+1;
  153. end;
  154. temp[0]:=char(l);
  155. GetParam:=temp;
  156. exit;
  157. end;
  158. { Point to next argument in list }
  159. while (p[count] <> #0) and (p[count] <> ' ') and (p[count] <> #9) do
  160. Begin
  161. count:=count+1;
  162. end;
  163. localindex:=localindex+1;
  164. end;
  165. if p[count] = #0 then break;
  166. count:=count+1;
  167. end;
  168. GetParam:=temp;
  169. end;
  170. function paramstr(l : longint) : string;
  171. var
  172. p : pchar;
  173. s1 : string;
  174. begin
  175. if l = 0 then
  176. Begin
  177. s1 := '';
  178. end
  179. else
  180. if (l>0) and (l<=paramcount) then
  181. begin
  182. p:=args;
  183. paramstr:=GetParam(word(l),p);
  184. end
  185. else paramstr:='';
  186. end;
  187. function paramcount : longint;
  188. Begin
  189. paramcount := argc;
  190. end;
  191. procedure randomize;
  192. var
  193. hl : longint;
  194. begin
  195. asm
  196. movem.l d2/d3/a2/a3, -(sp) { save OS registers }
  197. move.w #17,-(sp)
  198. trap #14 { call xbios - random number }
  199. add.l #2,sp
  200. movem.l (sp)+,d2/d3/a2/a3
  201. move.l d0,hl { result in d0 }
  202. end;
  203. randseed:=hl;
  204. end;
  205. function getheapstart:pointer;assembler;
  206. asm
  207. lea.l HEAP,a0
  208. move.l a0,d0
  209. end;
  210. function getheapsize:longint;assembler;
  211. asm
  212. move.l HEAP_SIZE,d0
  213. end ['D0'];
  214. { This routine is used to grow the heap. }
  215. { But here we do a trick, we say that the }
  216. { heap cannot be regrown! }
  217. function sbrk( size: longint): pointer;
  218. { on exit nil = if fails. }
  219. Begin
  220. sbrk:=nil;
  221. end;
  222. {$I heap.inc}
  223. {****************************************************************************
  224. Low Level File Routines
  225. ****************************************************************************}
  226. procedure AllowSlash(p:pchar);
  227. var
  228. i : longint;
  229. begin
  230. { allow slash as backslash }
  231. for i:=0 to strlen(p) do
  232. if p[i]='/' then p[i]:='\';
  233. end;
  234. procedure do_close(h : longint);
  235. begin
  236. asm
  237. movem.l d2/d3/a2/a3,-(sp)
  238. move.l h,d0
  239. move.w d0,-(sp)
  240. move.w #$3e,-(sp)
  241. trap #1
  242. add.l #4,sp { restore stack ... }
  243. movem.l (sp)+,d2/d3/a2/a3
  244. end;
  245. end;
  246. procedure do_erase(p : pchar);
  247. begin
  248. AllowSlash(p);
  249. asm
  250. move.l d2,d6 { save d2 }
  251. movem.l d3/a2/a3,-(sp) { save regs }
  252. move.l p,-(sp)
  253. move.w #$41,-(sp)
  254. trap #1
  255. add.l #6,sp
  256. move.l d6,d2 { restore d2 }
  257. movem.l (sp)+,d3/a2/a3
  258. tst.w d0
  259. beq @doserend
  260. move.w d0,errno
  261. @doserend:
  262. end;
  263. if errno <> 0 then
  264. Error2InOut;
  265. end;
  266. procedure do_rename(p1,p2 : pchar);
  267. begin
  268. AllowSlash(p1);
  269. AllowSlash(p2);
  270. asm
  271. move.l d2,d6 { save d2 }
  272. movem.l d3/a2/a3,-(sp)
  273. move.l p1,-(sp)
  274. move.l p2,-(sp)
  275. clr.w -(sp)
  276. move.w #$56,-(sp)
  277. trap #1
  278. lea 12(sp),sp
  279. move.l d6,d2 { restore d2 }
  280. movem.l (sp)+,d3/a2/a3
  281. tst.w d0
  282. beq @dosreend
  283. move.w d0,errno { error ... }
  284. @dosreend:
  285. end;
  286. if errno <> 0 then
  287. Error2InOut;
  288. end;
  289. function do_isdevice(handle:word):boolean;
  290. begin
  291. if (handle=stdoutputhandle) or (handle=stdinputhandle) or
  292. (handle=stderrorhandle) then
  293. do_isdevice:=FALSE
  294. else
  295. do_isdevice:=TRUE;
  296. end;
  297. function do_write(h,addr,len : longint) : longint;
  298. begin
  299. asm
  300. move.l d2,d6 { save d2 }
  301. movem.l d3/a2/a3,-(sp)
  302. move.l addr,-(sp)
  303. move.l len,-(sp)
  304. move.l h,d0
  305. move.w d0,-(sp)
  306. move.w #$40,-(sp)
  307. trap #1
  308. lea 12(sp),sp
  309. move.l d6,d2 { restore d2 }
  310. movem.l (sp)+,d3/a2/a3
  311. tst.l d0
  312. bpl @doswrend
  313. move.w d0,errno { error ... }
  314. @doswrend:
  315. move.l d0,@RESULT
  316. end;
  317. if errno <> 0 then
  318. Error2InOut;
  319. end;
  320. function do_read(h,addr,len : longint) : longint;
  321. begin
  322. asm
  323. move.l d2,d6 { save d2 }
  324. movem.l d3/a2/a3,-(sp)
  325. move.l addr,-(sp)
  326. move.l len,-(sp)
  327. move.l h,d0
  328. move.w d0,-(sp)
  329. move.w #$3f,-(sp)
  330. trap #1
  331. lea 12(sp),sp
  332. move.l d6,d2 { restore d2 }
  333. movem.l (sp)+,d3/a2/a3
  334. tst.l d0
  335. bpl @dosrdend
  336. move.w d0,errno { error ... }
  337. @dosrdend:
  338. move.l d0,@Result
  339. end;
  340. if errno <> 0 then
  341. Error2InOut;
  342. end;
  343. function do_filepos(handle : longint) : longint;
  344. begin
  345. asm
  346. move.l d2,d6 { save d2 }
  347. movem.l d3/a2/a3,-(sp)
  348. move.w #1,-(sp) { seek from current position }
  349. move.l handle,d0
  350. move.w d0,-(sp)
  351. move.l #0,-(sp) { with a seek offset of zero }
  352. move.w #$42,-(sp)
  353. trap #1
  354. lea 10(sp),sp
  355. move.l d6,d2 { restore d2 }
  356. movem.l (sp)+,d3/a2/a3
  357. move.l d0,@Result
  358. end;
  359. end;
  360. procedure do_seek(handle,pos : longint);
  361. begin
  362. asm
  363. move.l d2,d6 { save d2 }
  364. movem.l d3/a2/a3,-(sp)
  365. move.w #0,-(sp) { seek from start of file }
  366. move.l handle,d0
  367. move.w d0,-(sp)
  368. move.l pos,-(sp)
  369. move.w #$42,-(sp)
  370. trap #1
  371. lea 10(sp),sp
  372. move.l d6,d2 { restore d2 }
  373. movem.l (sp)+,d3/a2/a3
  374. end;
  375. end;
  376. function do_seekend(handle:longint):longint;
  377. var
  378. t: longint;
  379. begin
  380. asm
  381. move.l d2,d6 { save d2 }
  382. movem.l d3/a2/a3,-(sp)
  383. move.w #2,-(sp) { seek from end of file }
  384. move.l handle,d0
  385. move.w d0,-(sp)
  386. move.l #0,-(sp) { with an offset of 0 from end }
  387. move.w #$42,-(sp)
  388. trap #1
  389. lea 10(sp),sp
  390. move.l d6,d2 { restore d2 }
  391. movem.l (sp)+,d3/a2/a3
  392. move.l d0,t
  393. end;
  394. do_seekend:=t;
  395. end;
  396. function do_filesize(handle : longint) : longint;
  397. var
  398. aktfilepos : longint;
  399. begin
  400. aktfilepos:=do_filepos(handle);
  401. do_filesize:=do_seekend(handle);
  402. do_seek(handle,aktfilepos);
  403. end;
  404. procedure do_truncate (handle,pos:longint);
  405. begin
  406. do_seek(handle,pos);
  407. {!!!!!!!!!!!!}
  408. end;
  409. procedure do_open(var f;p:pchar;flags:longint);
  410. {
  411. filerec and textrec have both handle and mode as the first items so
  412. they could use the same routine for opening/creating.
  413. when (flags and $100) the file will be append
  414. when (flags and $1000) the file will be truncate/rewritten
  415. when (flags and $10000) there is no check for close (needed for textfiles)
  416. }
  417. var
  418. i : word;
  419. oflags: longint;
  420. begin
  421. AllowSlash(p);
  422. { close first if opened }
  423. if ((flags and $10000)=0) then
  424. begin
  425. case filerec(f).mode of
  426. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  427. fmclosed : ;
  428. else
  429. begin
  430. inoutres:=102; {not assigned}
  431. exit;
  432. end;
  433. end;
  434. end;
  435. { reset file handle }
  436. filerec(f).handle:=UnusedHandle;
  437. oflags:=$02; { read/write mode }
  438. { convert filemode to filerec modes }
  439. case (flags and 3) of
  440. 0 : begin
  441. filerec(f).mode:=fminput;
  442. oflags:=$00; { read mode only }
  443. end;
  444. 1 : filerec(f).mode:=fmoutput;
  445. 2 : filerec(f).mode:=fminout;
  446. end;
  447. if (flags and $1000)<>0 then
  448. begin
  449. filerec(f).mode:=fmoutput;
  450. oflags:=$04; { read/write with create }
  451. end
  452. else
  453. if (flags and $100)<>0 then
  454. begin
  455. filerec(f).mode:=fmoutput;
  456. oflags:=$02; { read/write }
  457. end;
  458. { empty name is special }
  459. if p[0]=#0 then
  460. begin
  461. case filerec(f).mode of
  462. fminput : filerec(f).handle:=StdInputHandle;
  463. fmappend,
  464. fmoutput : begin
  465. filerec(f).handle:=StdOutputHandle;
  466. filerec(f).mode:=fmoutput; {fool fmappend}
  467. end;
  468. end;
  469. exit;
  470. end;
  471. asm
  472. movem.l d2/d3/a2/a3,-(sp) { save used registers }
  473. cmp.l #4,oflags { check if rewrite mode ... }
  474. bne @opencont2
  475. { rewrite mode - create new file }
  476. move.w #0,-(sp)
  477. move.l p,-(sp)
  478. move.w #$3c,-(sp)
  479. trap #1
  480. add.l #8,sp { restore stack of os call }
  481. bra @end
  482. { reset - open existing files }
  483. @opencont2:
  484. move.l oflags,d0 { use flag as source ... }
  485. @opencont1:
  486. move.w d0,-(sp)
  487. move.l p,-(sp)
  488. move.w #$3d,-(sp)
  489. trap #1
  490. add.l #8,sp { restore stack of os call }
  491. @end:
  492. movem.l (sp)+,d2/d3/a2/a3
  493. tst.w d0
  494. bpl @opennoerr { if positive return values then ok }
  495. cmp.w #-1,d0 { if handle is -1 CON: }
  496. beq @opennoerr
  497. cmp.w #-2,d0 { if handle is -2 AUX: }
  498. beq @opennoerr
  499. cmp.w #-3,d0 { if handle is -3 PRN: }
  500. beq @opennoerr
  501. move.w d0,errno { otherwise normal error }
  502. @opennoerr:
  503. move.w d0,i { get handle as SIGNED VALUE... }
  504. end;
  505. if errno <> 0 then
  506. Error2InOut;
  507. filerec(f).handle:=i;
  508. if ((flags and $100) <> 0) and
  509. (FileRec (F).Handle <> UnusedHandle) then
  510. do_seekend(filerec(f).handle);
  511. end;
  512. {*****************************************************************************
  513. UnTyped File Handling
  514. *****************************************************************************}
  515. {$i file.inc}
  516. {*****************************************************************************
  517. Typed File Handling
  518. *****************************************************************************}
  519. {$i typefile.inc}
  520. {*****************************************************************************
  521. Text File Handling
  522. *****************************************************************************}
  523. {$i text.inc}
  524. {*****************************************************************************
  525. Directory Handling
  526. *****************************************************************************}
  527. procedure DosDir(func:byte;const s:string);
  528. var
  529. buffer : array[0..255] of char;
  530. c : word;
  531. begin
  532. move(s[1],buffer,length(s));
  533. buffer[length(s)]:=#0;
  534. AllowSlash(pchar(@buffer));
  535. c:=word(func);
  536. asm
  537. move.l d2,d6 { save d2 }
  538. movem.l d3/a2/a3,-(sp)
  539. pea buffer
  540. move.w c,-(sp)
  541. trap #1
  542. add.l #6,sp
  543. move.l d6,d2 { restore d2 }
  544. movem.l (sp)+,d3/a2/a3
  545. tst.w d0
  546. beq @dosdirend
  547. move.w d0,errno
  548. @dosdirend:
  549. end;
  550. if errno <> 0 then
  551. Error2InOut;
  552. end;
  553. procedure mkdir(const s : string);[IOCheck];
  554. begin
  555. If InOutRes <> 0 then exit;
  556. DosDir($39,s);
  557. end;
  558. procedure rmdir(const s : string);[IOCheck];
  559. begin
  560. If InOutRes <> 0 then exit;
  561. DosDir($3a,s);
  562. end;
  563. procedure chdir(const s : string);[IOCheck];
  564. begin
  565. If InOutRes <> 0 then exit;
  566. DosDir($3b,s);
  567. end;
  568. function GetDirIO (DriveNr: byte; var Dir: ShortString): word;
  569. [public, alias: 'FPC_GETDIRIO'];
  570. var
  571. temp : array[0..255] of char;
  572. i : longint;
  573. j: byte;
  574. drv: word;
  575. begin
  576. GetDirIO := 0;
  577. drv:=word(drivenr);
  578. asm
  579. move.l d2,d6 { save d2 }
  580. movem.l d3/a2/a3,-(sp)
  581. { Get dir from drivenr : 0=default, 1=A etc... }
  582. move.w drv,-(sp)
  583. { put (previously saved) offset in si }
  584. { move.l temp,-(sp)}
  585. pea temp
  586. { call attos function 47H : Get dir }
  587. move.w #$47,-(sp)
  588. { make the call }
  589. trap #1
  590. add.l #8,sp
  591. move.l d6,d2 { restore d2 }
  592. movem.l (sp)+,d3/a2/a3
  593. end;
  594. { conversion to pascal string }
  595. i:=0;
  596. while (temp[i]<>#0) do
  597. begin
  598. if temp[i]='/' then
  599. temp[i]:='\';
  600. dir[i+3]:=temp[i];
  601. inc(i);
  602. end;
  603. dir[2]:=':';
  604. dir[3]:='\';
  605. dir[0]:=char(i+2);
  606. { upcase the string (FPC Pascal function) }
  607. dir:=upcase(dir);
  608. if drivenr<>0 then { Drive was supplied. We know it }
  609. dir[1]:=chr(65+drivenr-1)
  610. else
  611. begin
  612. asm
  613. move.l d2,d6 { save d2 }
  614. movem.l d3/a2/a3,-(sp)
  615. move.w #$19,-(sp)
  616. trap #1
  617. add.l #2,sp
  618. move.w d0,drv
  619. move.l d6,d2 { restore d2 }
  620. movem.l (sp)+,d3/a2/a3
  621. end;
  622. dir[1]:=chr(byte(drv)+ord('A'));
  623. end;
  624. end;
  625. procedure GetDir (DriveNr: byte; var Dir: ShortString);
  626. begin
  627. InOutRes := GetDirIO (DriveNr, Dir);
  628. end;
  629. {*****************************************************************************
  630. System Dependent Exit code
  631. *****************************************************************************}
  632. Procedure system_exit;
  633. begin
  634. end;
  635. {*****************************************************************************
  636. SystemUnit Initialization
  637. *****************************************************************************}
  638. begin
  639. { Initialize ExitProc }
  640. ExitProc:=Nil;
  641. { Setup heap }
  642. InitHeap;
  643. { Setup stdin, stdout and stderr }
  644. OpenStdIO(Input,fmInput,StdInputHandle);
  645. OpenStdIO(Output,fmOutput,StdOutputHandle);
  646. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  647. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  648. { Reset IO Error }
  649. InOutRes:=0;
  650. (* This should be changed to a real value during *)
  651. (* thread driver initialization if appropriate. *)
  652. ThreadID := 1;
  653. errno := 0;
  654. { Setup command line arguments }
  655. argc:=GetParamCount(args);
  656. {$ifdef HASVARIANT}
  657. initvariantmanager;
  658. {$endif HASVARIANT}
  659. end.
  660. {
  661. $Log$
  662. Revision 1.11 2004-09-03 19:25:21 olle
  663. + added maxExitCode to all System.pp
  664. * constrained error code to be below maxExitCode in RunError et. al.
  665. Revision 1.10 2004/01/20 23:05:31 hajny
  666. * ExecuteProcess fixes, ProcessID and ThreadID added
  667. Revision 1.9 2003/10/25 23:42:35 hajny
  668. * THandle in sysutils common using System.THandle
  669. Revision 1.8 2003/09/29 18:52:36 hajny
  670. * append fix applied to Amiga, Atari, EMX, GO32v2, OS/2 and Watcom
  671. Revision 1.7 2003/09/27 11:52:35 peter
  672. * sbrk returns pointer
  673. Revision 1.6 2002/10/20 12:00:52 carl
  674. - remove objinc.inc (unused file)
  675. * update makefiles accordingly
  676. Revision 1.5 2002/10/13 09:25:23 florian
  677. + call to initvariantmanager inserted
  678. Revision 1.4 2002/09/07 16:01:16 peter
  679. * old logs removed and tabs fixed
  680. }