system.pp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit system;
  12. interface
  13. { two debug conditionnals can be used
  14. - SYSTEMDEBUG
  15. -for STACK checks
  16. -for non closed files at exit (or at any time with GDB)
  17. - SYSTEM_DEBUG_STARTUP
  18. specifically for
  19. - proxy command line (DJGPP feature)
  20. - list of args
  21. - list of env variables (PM) }
  22. {$ifndef NO_EXCEPTIONS_IN_SYSTEM}
  23. {$define EXCEPTIONS_IN_SYSTEM}
  24. {$endif NO_EXCEPTIONS_IN_SYSTEM}
  25. { include system-independent routine headers }
  26. {$I systemh.inc}
  27. { include heap support headers }
  28. {$I heaph.inc}
  29. const
  30. { Default filehandles }
  31. UnusedHandle = -1;
  32. StdInputHandle = 0;
  33. StdOutputHandle = 1;
  34. StdErrorHandle = 2;
  35. FileNameCaseSensitive : boolean = false;
  36. { Default memory segments (Tp7 compatibility) }
  37. seg0040 = $0040;
  38. segA000 = $A000;
  39. segB000 = $B000;
  40. segB800 = $B800;
  41. var
  42. { Mem[] support }
  43. mem : array[0..$7fffffff] of byte absolute $0:$0;
  44. memw : array[0..$7fffffff] of word absolute $0:$0;
  45. meml : array[0..$7fffffff] of longint absolute $0:$0;
  46. { C-compatible arguments and environment }
  47. argc : longint;
  48. argv : ppchar;
  49. envp : ppchar;
  50. dos_argv0 : pchar;
  51. {$ifndef RTLLITE}
  52. { System info }
  53. LFNSupport : boolean;
  54. {$endif RTLLITE}
  55. type
  56. { Dos Extender info }
  57. p_stub_info = ^t_stub_info;
  58. t_stub_info = packed record
  59. magic : array[0..15] of char;
  60. size : longint;
  61. minstack : longint;
  62. memory_handle : longint;
  63. initial_size : longint;
  64. minkeep : word;
  65. ds_selector : word;
  66. ds_segment : word;
  67. psp_selector : word;
  68. cs_selector : word;
  69. env_size : word;
  70. basename : array[0..7] of char;
  71. argv0 : array [0..15] of char;
  72. dpmi_server : array [0..15] of char;
  73. end;
  74. p_go32_info_block = ^t_go32_info_block;
  75. t_go32_info_block = packed record
  76. size_of_this_structure_in_bytes : longint; {offset 0}
  77. linear_address_of_primary_screen : longint; {offset 4}
  78. linear_address_of_secondary_screen : longint; {offset 8}
  79. linear_address_of_transfer_buffer : longint; {offset 12}
  80. size_of_transfer_buffer : longint; {offset 16}
  81. pid : longint; {offset 20}
  82. master_interrupt_controller_base : byte; {offset 24}
  83. slave_interrupt_controller_base : byte; {offset 25}
  84. selector_for_linear_memory : word; {offset 26}
  85. linear_address_of_stub_info_structure : longint; {offset 28}
  86. linear_address_of_original_psp : longint; {offset 32}
  87. run_mode : word; {offset 36}
  88. run_mode_info : word; {offset 38}
  89. end;
  90. var
  91. stub_info : p_stub_info;
  92. go32_info_block : t_go32_info_block;
  93. {$ifdef SYSTEMDEBUG}
  94. const
  95. accept_sbrk : boolean = true;
  96. {$endif}
  97. {
  98. necessary for objects.pas, should be removed (at least from the interface
  99. to the implementation)
  100. }
  101. type
  102. trealregs=record
  103. realedi,realesi,realebp,realres,
  104. realebx,realedx,realecx,realeax : longint;
  105. realflags,
  106. reales,realds,realfs,realgs,
  107. realip,realcs,realsp,realss : word;
  108. end;
  109. function do_write(h,addr,len : longint) : longint;
  110. function do_read(h,addr,len : longint) : longint;
  111. procedure syscopyfromdos(addr : longint; len : longint);
  112. procedure syscopytodos(addr : longint; len : longint);
  113. procedure sysrealintr(intnr : word;var regs : trealregs);
  114. function tb : longint;
  115. implementation
  116. { include system independent routines }
  117. {$I system.inc}
  118. const
  119. carryflag = 1;
  120. type
  121. tseginfo=packed record
  122. offset : pointer;
  123. segment : word;
  124. end;
  125. var
  126. doscmd : string[128]; { Dos commandline copied from PSP, max is 128 chars }
  127. old_int00 : tseginfo;cvar;
  128. old_int75 : tseginfo;cvar;
  129. {$asmmode ATT}
  130. {*****************************************************************************
  131. Go32 Helpers
  132. *****************************************************************************}
  133. function far_strlen(selector : word;linear_address : longint) : longint;assembler;
  134. asm
  135. movl linear_address,%edx
  136. movl %edx,%ecx
  137. movw selector,%gs
  138. .Larg19:
  139. movb %gs:(%edx),%al
  140. testb %al,%al
  141. je .Larg20
  142. incl %edx
  143. jmp .Larg19
  144. .Larg20:
  145. movl %edx,%eax
  146. subl %ecx,%eax
  147. end;
  148. function tb : longint;
  149. begin
  150. tb:=go32_info_block.linear_address_of_transfer_buffer;
  151. end;
  152. function tb_segment : longint;
  153. begin
  154. tb_segment:=go32_info_block.linear_address_of_transfer_buffer shr 4;
  155. end;
  156. function tb_offset : longint;
  157. begin
  158. tb_offset:=go32_info_block.linear_address_of_transfer_buffer and $f;
  159. end;
  160. function tb_size : longint;
  161. begin
  162. tb_size:=go32_info_block.size_of_transfer_buffer;
  163. end;
  164. function dos_selector : word;
  165. begin
  166. dos_selector:=go32_info_block.selector_for_linear_memory;
  167. end;
  168. function get_ds : word;assembler;
  169. asm
  170. movw %ds,%ax
  171. end;
  172. function get_cs : word;assembler;
  173. asm
  174. movw %cs,%ax
  175. end;
  176. procedure sysseg_move(sseg : word;source : longint;dseg : word;dest : longint;count : longint);
  177. begin
  178. if count=0 then
  179. exit;
  180. if (sseg<>dseg) or ((sseg=dseg) and (source>dest)) then
  181. asm
  182. pushw %es
  183. pushw %ds
  184. cld
  185. movl count,%ecx
  186. movl source,%esi
  187. movl dest,%edi
  188. movw dseg,%ax
  189. movw %ax,%es
  190. movw sseg,%ax
  191. movw %ax,%ds
  192. movl %ecx,%eax
  193. shrl $2,%ecx
  194. rep
  195. movsl
  196. movl %eax,%ecx
  197. andl $3,%ecx
  198. rep
  199. movsb
  200. popw %ds
  201. popw %es
  202. end ['ESI','EDI','ECX','EAX']
  203. else if (source<dest) then
  204. { copy backward for overlapping }
  205. asm
  206. pushw %es
  207. pushw %ds
  208. std
  209. movl count,%ecx
  210. movl source,%esi
  211. movl dest,%edi
  212. movw dseg,%ax
  213. movw %ax,%es
  214. movw sseg,%ax
  215. movw %ax,%ds
  216. addl %ecx,%esi
  217. addl %ecx,%edi
  218. movl %ecx,%eax
  219. andl $3,%ecx
  220. orl %ecx,%ecx
  221. jz .LSEG_MOVE1
  222. { calculate esi and edi}
  223. decl %esi
  224. decl %edi
  225. rep
  226. movsb
  227. incl %esi
  228. incl %edi
  229. .LSEG_MOVE1:
  230. subl $4,%esi
  231. subl $4,%edi
  232. movl %eax,%ecx
  233. shrl $2,%ecx
  234. rep
  235. movsl
  236. cld
  237. popw %ds
  238. popw %es
  239. end ['ESI','EDI','ECX'];
  240. end;
  241. var
  242. _args : ppchar;external name '_args';
  243. procedure setup_arguments;
  244. function atohex(s : pchar) : longint;
  245. var
  246. rv : longint;
  247. v : byte;
  248. begin
  249. rv:=0;
  250. while (s^<>#0) do
  251. begin
  252. v:=byte(s^)-byte('0');
  253. if (v > 9) then
  254. dec(v,7);
  255. v:=v and 15; { in case it's lower case }
  256. rv:=(rv shl 4) or v;
  257. inc(longint(s));
  258. end;
  259. atohex:=rv;
  260. end;
  261. type
  262. arrayword = array [0..255] of word;
  263. var
  264. psp : word;
  265. i,j : longint;
  266. quote : char;
  267. proxy_s : string[50];
  268. al,proxy_argc,proxy_seg,proxy_ofs,lin : longint;
  269. largs : array[0..127] of pchar;
  270. rm_argv : ^arrayword;
  271. argv0len : longint;
  272. useproxy : boolean;
  273. hp : ppchar;
  274. begin
  275. fillchar(largs,sizeof(largs),0);
  276. psp:=stub_info^.psp_selector;
  277. largs[0]:=dos_argv0;
  278. argc := 1;
  279. sysseg_move(psp, 128, get_ds, longint(@doscmd), 128);
  280. {$IfDef SYSTEM_DEBUG_STARTUP}
  281. Writeln(stderr,'Dos command line is #',doscmd,'# size = ',length(doscmd));
  282. {$EndIf }
  283. { setup cmdline variable }
  284. argv0len:=strlen(dos_argv0);
  285. cmdline:=sysgetmem(argv0len+length(doscmd)+1);
  286. move(dos_argv0^,cmdline^,argv0len);
  287. move(doscmd[1],cmdline[argv0len],length(doscmd));
  288. cmdline[argv0len+length(doscmd)]:=#0;
  289. j := 1;
  290. quote := #0;
  291. for i:=1 to length(doscmd) do
  292. Begin
  293. if doscmd[i] = quote then
  294. begin
  295. quote := #0;
  296. if (i>1) and ((doscmd[i-1]='''') or (doscmd[i-1]='"')) then
  297. begin
  298. j := i+1;
  299. doscmd[i] := #0;
  300. continue;
  301. end;
  302. doscmd[i] := #0;
  303. largs[argc]:=@doscmd[j];
  304. inc(argc);
  305. j := i+1;
  306. end
  307. else
  308. if (quote = #0) and ((doscmd[i] = '''') or (doscmd[i]='"')) then
  309. begin
  310. quote := doscmd[i];
  311. j := i + 1;
  312. end else
  313. if (quote = #0) and ((doscmd[i] = ' ')
  314. or (doscmd[i] = #9) or (doscmd[i] = #10) or
  315. (doscmd[i] = #12) or (doscmd[i] = #9)) then
  316. begin
  317. doscmd[i]:=#0;
  318. if j<i then
  319. begin
  320. largs[argc]:=@doscmd[j];
  321. inc(argc);
  322. j := i+1;
  323. end else inc(j);
  324. end else
  325. if (i = length(doscmd)) then
  326. begin
  327. doscmd[i+1]:=#0;
  328. largs[argc]:=@doscmd[j];
  329. inc(argc);
  330. end;
  331. end;
  332. hp:=envp;
  333. useproxy:=false;
  334. while assigned(hp^) do
  335. begin
  336. if (hp^[0]=' ') then
  337. begin
  338. proxy_s:=strpas(hp^);
  339. if Copy(proxy_s,1,7)=' !proxy' then
  340. begin
  341. proxy_s[13]:=#0;
  342. proxy_s[18]:=#0;
  343. proxy_s[23]:=#0;
  344. largs[2]:=@proxy_s[9];
  345. largs[3]:=@proxy_s[14];
  346. largs[4]:=@proxy_s[19];
  347. useproxy:=true;
  348. break;
  349. end;
  350. end;
  351. inc(hp);
  352. end;
  353. if (not useproxy) and
  354. (argc > 1) and (far_strlen(get_ds,longint(largs[1])) = 6) then
  355. begin
  356. move(largs[1]^,proxy_s[1],6);
  357. proxy_s[0] := #6;
  358. if (proxy_s = '!proxy') then
  359. useproxy:=true;
  360. end;
  361. if useproxy then
  362. begin
  363. proxy_argc := atohex(largs[2]);
  364. proxy_seg := atohex(largs[3]);
  365. proxy_ofs := atohex(largs[4]);
  366. {$IfDef SYSTEM_DEBUG_STARTUP}
  367. Writeln(stderr,'proxy command line found');
  368. writeln(stderr,'argc: ',proxy_argc,' seg: ',proxy_seg,' ofs: ',proxy_ofs);
  369. {$EndIf SYSTEM_DEBUG_STARTUP}
  370. if proxy_argc>128 then
  371. proxy_argc:=128;
  372. rm_argv := sysgetmem(proxy_argc*sizeof(word));
  373. sysseg_move(dos_selector,proxy_seg*16+proxy_ofs, get_ds,longint(rm_argv),proxy_argc*sizeof(word));
  374. for i:=0 to proxy_argc - 1 do
  375. begin
  376. lin := proxy_seg*16 + rm_argv^[i];
  377. al :=far_strlen(dos_selector, lin);
  378. largs[i] := sysgetmem(al+1);
  379. sysseg_move(dos_selector, lin, get_ds,longint(largs[i]), al+1);
  380. {$IfDef SYSTEM_DEBUG_STARTUP}
  381. Writeln(stderr,'arg ',i,' #',rm_argv^[i],'#',al,'#',largs[i],'#');
  382. {$EndIf SYSTEM_DEBUG_STARTUP}
  383. end;
  384. sysfreemem(rm_argv);
  385. argc := proxy_argc;
  386. end;
  387. argv := sysgetmem(argc shl 2);
  388. for i := 0 to argc-1 do
  389. argv[i]:=largs[i];
  390. _args:=argv;
  391. end;
  392. function strcopy(dest,source : pchar) : pchar;
  393. begin
  394. asm
  395. cld
  396. movl 12(%ebp),%edi
  397. movl $0xffffffff,%ecx
  398. xorb %al,%al
  399. repne
  400. scasb
  401. not %ecx
  402. movl 8(%ebp),%edi
  403. movl 12(%ebp),%esi
  404. movl %ecx,%eax
  405. shrl $2,%ecx
  406. rep
  407. movsl
  408. movl %eax,%ecx
  409. andl $3,%ecx
  410. rep
  411. movsb
  412. movl 8(%ebp),%eax
  413. leave
  414. ret $8
  415. end;
  416. end;
  417. var
  418. __stubinfo : p_stub_info;external name '__stubinfo';
  419. ___dos_argv0 : pchar;external name '___dos_argv0';
  420. procedure setup_environment;
  421. var env_selector : word;
  422. env_count : longint;
  423. dos_env,cp : pchar;
  424. begin
  425. stub_info:=__stubinfo;
  426. dos_env := sysgetmem(stub_info^.env_size);
  427. env_count:=0;
  428. sysseg_move(stub_info^.psp_selector,$2c, get_ds, longint(@env_selector), 2);
  429. sysseg_move(env_selector, 0, get_ds, longint(dos_env), stub_info^.env_size);
  430. cp:=dos_env;
  431. while cp ^ <> #0 do
  432. begin
  433. inc(env_count);
  434. while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
  435. inc(longint(cp)); { skip to next character }
  436. end;
  437. envp := sysgetmem((env_count+1) * sizeof(pchar));
  438. if (envp = nil) then exit;
  439. cp:=dos_env;
  440. env_count:=0;
  441. while cp^ <> #0 do
  442. begin
  443. envp[env_count] := sysgetmem(strlen(cp)+1);
  444. strcopy(envp[env_count], cp);
  445. {$IfDef SYSTEM_DEBUG_STARTUP}
  446. Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
  447. {$EndIf SYSTEM_DEBUG_STARTUP}
  448. inc(env_count);
  449. while (cp^ <> #0) do
  450. inc(longint(cp)); { skip to NUL }
  451. inc(longint(cp)); { skip to next character }
  452. end;
  453. envp[env_count]:=nil;
  454. longint(cp):=longint(cp)+3;
  455. dos_argv0 := sysgetmem(strlen(cp)+1);
  456. if (dos_argv0 = nil) then halt;
  457. strcopy(dos_argv0, cp);
  458. { update ___dos_argv0 also }
  459. ___dos_argv0:=dos_argv0
  460. end;
  461. procedure syscopytodos(addr : longint; len : longint);
  462. begin
  463. if len > tb_size then
  464. HandleError(217);
  465. sysseg_move(get_ds,addr,dos_selector,tb,len);
  466. end;
  467. procedure syscopyfromdos(addr : longint; len : longint);
  468. begin
  469. if len > tb_size then
  470. HandleError(217);
  471. sysseg_move(dos_selector,tb,get_ds,addr,len);
  472. end;
  473. procedure sysrealintr(intnr : word;var regs : trealregs);
  474. begin
  475. regs.realsp:=0;
  476. regs.realss:=0;
  477. asm
  478. movw intnr,%bx
  479. xorl %ecx,%ecx
  480. movl regs,%edi
  481. movw $0x300,%ax
  482. int $0x31
  483. end;
  484. end;
  485. procedure set_pm_interrupt(vector : byte;const intaddr : tseginfo);
  486. begin
  487. asm
  488. movl intaddr,%eax
  489. movl (%eax),%edx
  490. movw 4(%eax),%cx
  491. movl $0x205,%eax
  492. movb vector,%bl
  493. int $0x31
  494. end;
  495. end;
  496. procedure get_pm_interrupt(vector : byte;var intaddr : tseginfo);
  497. begin
  498. asm
  499. movb vector,%bl
  500. movl $0x204,%eax
  501. int $0x31
  502. movl intaddr,%eax
  503. movl %edx,(%eax)
  504. movw %cx,4(%eax)
  505. end;
  506. end;
  507. procedure getinoutres(def : word);
  508. var
  509. regs : trealregs;
  510. begin
  511. regs.realeax:=$5900;
  512. regs.realebx:=$0;
  513. sysrealintr($21,regs);
  514. InOutRes:=lo(regs.realeax);
  515. case InOutRes of
  516. 19 : InOutRes:=150;
  517. 21 : InOutRes:=152;
  518. end;
  519. if InOutRes=0 then
  520. InOutRes:=Def;
  521. end;
  522. { Keep Track of open files }
  523. const
  524. max_files = 50;
  525. var
  526. openfiles : array [0..max_files-1] of boolean;
  527. {$ifdef SYSTEMDEBUG}
  528. opennames : array [0..max_files-1] of pchar;
  529. const
  530. free_closed_names : boolean = true;
  531. {$endif SYSTEMDEBUG}
  532. {*****************************************************************************
  533. System Dependent Exit code
  534. *****************************************************************************}
  535. procedure ___exit(exitcode:longint);cdecl;external name '___exit';
  536. procedure do_close(handle : longint);forward;
  537. Procedure system_exit;
  538. var
  539. h : byte;
  540. begin
  541. for h:=0 to max_files-1 do
  542. if openfiles[h] then
  543. begin
  544. {$ifdef SYSTEMDEBUG}
  545. writeln(stderr,'file ',opennames[h],' not closed at exit');
  546. {$endif SYSTEMDEBUG}
  547. if h>=5 then
  548. do_close(h);
  549. end;
  550. { halt is not allways called !! }
  551. { not on normal exit !! PM }
  552. set_pm_interrupt($00,old_int00);
  553. {$ifndef EXCEPTIONS_IN_SYSTEM}
  554. set_pm_interrupt($75,old_int75);
  555. {$endif EXCEPTIONS_IN_SYSTEM}
  556. ___exit(exitcode);
  557. end;
  558. procedure new_int00;
  559. begin
  560. HandleError(200);
  561. end;
  562. {$ifndef EXCEPTIONS_IN_SYSTEM}
  563. procedure new_int75;
  564. begin
  565. asm
  566. xorl %eax,%eax
  567. outb %al,$0x0f0
  568. movb $0x20,%al
  569. outb %al,$0x0a0
  570. outb %al,$0x020
  571. end;
  572. HandleError(200);
  573. end;
  574. {$endif EXCEPTIONS_IN_SYSTEM}
  575. var
  576. __stkbottom : longint;external name '__stkbottom';
  577. procedure int_stackcheck(stack_size:longint);[public,alias:'FPC_STACKCHECK'];
  578. {
  579. called when trying to get local stack if the compiler directive $S
  580. is set this function must preserve esi !!!! because esi is set by
  581. the calling proc for methods it must preserve all registers !!
  582. With a 2048 byte safe area used to write to StdIo without crossing
  583. the stack boundary
  584. }
  585. begin
  586. asm
  587. pushl %eax
  588. pushl %ebx
  589. movl stack_size,%ebx
  590. addl $2048,%ebx
  591. movl %esp,%eax
  592. subl %ebx,%eax
  593. {$ifdef SYSTEMDEBUG}
  594. movl loweststack,%ebx
  595. cmpl %eax,%ebx
  596. jb .L_is_not_lowest
  597. movl %eax,loweststack
  598. .L_is_not_lowest:
  599. {$endif SYSTEMDEBUG}
  600. movl __stkbottom,%ebx
  601. cmpl %eax,%ebx
  602. jae .L__short_on_stack
  603. popl %ebx
  604. popl %eax
  605. leave
  606. ret $4
  607. .L__short_on_stack:
  608. { can be usefull for error recovery !! }
  609. popl %ebx
  610. popl %eax
  611. end['EAX','EBX'];
  612. HandleError(202);
  613. end;
  614. {*****************************************************************************
  615. ParamStr/Randomize
  616. *****************************************************************************}
  617. function paramcount : longint;
  618. begin
  619. paramcount := argc - 1;
  620. end;
  621. function paramstr(l : longint) : string;
  622. begin
  623. if (l>=0) and (l+1<=argc) then
  624. paramstr:=strpas(argv[l])
  625. else
  626. paramstr:='';
  627. end;
  628. procedure randomize;
  629. var
  630. hl : longint;
  631. regs : trealregs;
  632. begin
  633. regs.realeax:=$2c00;
  634. sysrealintr($21,regs);
  635. hl:=lo(regs.realedx);
  636. randseed:=hl*$10000+ lo(regs.realecx);
  637. end;
  638. {*****************************************************************************
  639. Heap Management
  640. *****************************************************************************}
  641. var
  642. int_heap : longint;external name 'HEAP';
  643. int_heapsize : longint;external name 'HEAPSIZE';
  644. function getheapstart:pointer;
  645. begin
  646. getheapstart:=@int_heap;
  647. end;
  648. function getheapsize:longint;
  649. begin
  650. getheapsize:=int_heapsize;
  651. end;
  652. function ___sbrk(size:longint):longint;cdecl;external name '___sbrk';
  653. function Sbrk(size : longint):longint;assembler;
  654. asm
  655. {$ifdef SYSTEMDEBUG}
  656. cmpb $1,accept_sbrk
  657. je .Lsbrk
  658. movl $-1,%eax
  659. jmp .Lsbrk_fail
  660. .Lsbrk:
  661. {$endif}
  662. movl size,%eax
  663. pushl %eax
  664. call ___sbrk
  665. addl $4,%esp
  666. {$ifdef SYSTEMDEBUG}
  667. .Lsbrk_fail:
  668. {$endif}
  669. end;
  670. { include standard heap management }
  671. {$I heap.inc}
  672. {****************************************************************************
  673. Low level File Routines
  674. ****************************************************************************}
  675. procedure AllowSlash(p:pchar);
  676. var
  677. i : longint;
  678. begin
  679. { allow slash as backslash }
  680. for i:=0 to strlen(p) do
  681. if p[i]='/' then p[i]:='\';
  682. end;
  683. procedure do_close(handle : longint);
  684. var
  685. regs : trealregs;
  686. begin
  687. if Handle<=4 then
  688. exit;
  689. regs.realebx:=handle;
  690. if handle<max_files then
  691. begin
  692. openfiles[handle]:=false;
  693. {$ifdef SYSTEMDEBUG}
  694. if assigned(opennames[handle]) and free_closed_names then
  695. begin
  696. sysfreememsize(opennames[handle],strlen(opennames[handle])+1);
  697. opennames[handle]:=nil;
  698. end;
  699. {$endif SYSTEMDEBUG}
  700. end;
  701. regs.realeax:=$3e00;
  702. sysrealintr($21,regs);
  703. if (regs.realflags and carryflag) <> 0 then
  704. GetInOutRes(lo(regs.realeax));
  705. end;
  706. procedure do_erase(p : pchar);
  707. var
  708. regs : trealregs;
  709. begin
  710. AllowSlash(p);
  711. syscopytodos(longint(p),strlen(p)+1);
  712. regs.realedx:=tb_offset;
  713. regs.realds:=tb_segment;
  714. {$ifndef RTLLITE}
  715. if LFNSupport then
  716. regs.realeax:=$7141
  717. else
  718. {$endif RTLLITE}
  719. regs.realeax:=$4100;
  720. regs.realesi:=0;
  721. regs.realecx:=0;
  722. sysrealintr($21,regs);
  723. if (regs.realflags and carryflag) <> 0 then
  724. GetInOutRes(lo(regs.realeax));
  725. end;
  726. procedure do_rename(p1,p2 : pchar);
  727. var
  728. regs : trealregs;
  729. begin
  730. AllowSlash(p1);
  731. AllowSlash(p2);
  732. if strlen(p1)+strlen(p2)+3>tb_size then
  733. HandleError(217);
  734. sysseg_move(get_ds,longint(p2),dos_selector,tb,strlen(p2)+1);
  735. sysseg_move(get_ds,longint(p1),dos_selector,tb+strlen(p2)+2,strlen(p1)+1);
  736. regs.realedi:=tb_offset;
  737. regs.realedx:=tb_offset + strlen(p2)+2;
  738. regs.realds:=tb_segment;
  739. regs.reales:=tb_segment;
  740. {$ifndef RTLLITE}
  741. if LFNSupport then
  742. regs.realeax:=$7156
  743. else
  744. {$endif RTLLITE}
  745. regs.realeax:=$5600;
  746. regs.realecx:=$ff; { attribute problem here ! }
  747. sysrealintr($21,regs);
  748. if (regs.realflags and carryflag) <> 0 then
  749. GetInOutRes(lo(regs.realeax));
  750. end;
  751. function do_write(h,addr,len : longint) : longint;
  752. var
  753. regs : trealregs;
  754. size,
  755. writesize : longint;
  756. begin
  757. writesize:=0;
  758. while len > 0 do
  759. begin
  760. if len>tb_size then
  761. size:=tb_size
  762. else
  763. size:=len;
  764. syscopytodos(addr+writesize,size);
  765. regs.realecx:=size;
  766. regs.realedx:=tb_offset;
  767. regs.realds:=tb_segment;
  768. regs.realebx:=h;
  769. regs.realeax:=$4000;
  770. sysrealintr($21,regs);
  771. if (regs.realflags and carryflag) <> 0 then
  772. begin
  773. GetInOutRes(lo(regs.realeax));
  774. exit(writesize);
  775. end;
  776. inc(writesize,lo(regs.realeax));
  777. dec(len,lo(regs.realeax));
  778. { stop when not the specified size is written }
  779. if lo(regs.realeax)<size then
  780. break;
  781. end;
  782. Do_Write:=WriteSize;
  783. end;
  784. function do_read(h,addr,len : longint) : longint;
  785. var
  786. regs : trealregs;
  787. size,
  788. readsize : longint;
  789. begin
  790. readsize:=0;
  791. while len > 0 do
  792. begin
  793. if len>tb_size then
  794. size:=tb_size
  795. else
  796. size:=len;
  797. regs.realecx:=size;
  798. regs.realedx:=tb_offset;
  799. regs.realds:=tb_segment;
  800. regs.realebx:=h;
  801. regs.realeax:=$3f00;
  802. sysrealintr($21,regs);
  803. if (regs.realflags and carryflag) <> 0 then
  804. begin
  805. GetInOutRes(lo(regs.realeax));
  806. do_read:=0;
  807. exit;
  808. end;
  809. syscopyfromdos(addr+readsize,lo(regs.realeax));
  810. inc(readsize,lo(regs.realeax));
  811. dec(len,lo(regs.realeax));
  812. { stop when not the specified size is read }
  813. if lo(regs.realeax)<size then
  814. break;
  815. end;
  816. do_read:=readsize;
  817. end;
  818. function do_filepos(handle : longint) : longint;
  819. var
  820. regs : trealregs;
  821. begin
  822. regs.realebx:=handle;
  823. regs.realecx:=0;
  824. regs.realedx:=0;
  825. regs.realeax:=$4201;
  826. sysrealintr($21,regs);
  827. if (regs.realflags and carryflag) <> 0 then
  828. Begin
  829. GetInOutRes(lo(regs.realeax));
  830. do_filepos:=0;
  831. end
  832. else
  833. do_filepos:=lo(regs.realedx) shl 16+lo(regs.realeax);
  834. end;
  835. procedure do_seek(handle,pos : longint);
  836. var
  837. regs : trealregs;
  838. begin
  839. regs.realebx:=handle;
  840. regs.realecx:=pos shr 16;
  841. regs.realedx:=pos and $ffff;
  842. regs.realeax:=$4200;
  843. sysrealintr($21,regs);
  844. if (regs.realflags and carryflag) <> 0 then
  845. GetInOutRes(lo(regs.realeax));
  846. end;
  847. function do_seekend(handle:longint):longint;
  848. var
  849. regs : trealregs;
  850. begin
  851. regs.realebx:=handle;
  852. regs.realecx:=0;
  853. regs.realedx:=0;
  854. regs.realeax:=$4202;
  855. sysrealintr($21,regs);
  856. if (regs.realflags and carryflag) <> 0 then
  857. Begin
  858. GetInOutRes(lo(regs.realeax));
  859. do_seekend:=0;
  860. end
  861. else
  862. do_seekend:=lo(regs.realedx) shl 16+lo(regs.realeax);
  863. end;
  864. function do_filesize(handle : longint) : longint;
  865. var
  866. aktfilepos : longint;
  867. begin
  868. aktfilepos:=do_filepos(handle);
  869. do_filesize:=do_seekend(handle);
  870. do_seek(handle,aktfilepos);
  871. end;
  872. { truncate at a given position }
  873. procedure do_truncate (handle,pos:longint);
  874. var
  875. regs : trealregs;
  876. begin
  877. do_seek(handle,pos);
  878. regs.realecx:=0;
  879. regs.realedx:=tb_offset;
  880. regs.realds:=tb_segment;
  881. regs.realebx:=handle;
  882. regs.realeax:=$4000;
  883. sysrealintr($21,regs);
  884. if (regs.realflags and carryflag) <> 0 then
  885. GetInOutRes(lo(regs.realeax));
  886. end;
  887. {$ifndef RTLLITE}
  888. const
  889. FileHandleCount : longint = 20;
  890. function Increase_file_handle_count : boolean;
  891. var
  892. regs : trealregs;
  893. begin
  894. Inc(FileHandleCount,10);
  895. regs.realebx:=FileHandleCount;
  896. regs.realeax:=$6700;
  897. sysrealintr($21,regs);
  898. if (regs.realflags and carryflag) <> 0 then
  899. begin
  900. Increase_file_handle_count:=false;
  901. Dec (FileHandleCount, 10);
  902. end
  903. else
  904. Increase_file_handle_count:=true;
  905. end;
  906. {$endif not RTLLITE}
  907. procedure do_open(var f;p:pchar;flags:longint);
  908. {
  909. filerec and textrec have both handle and mode as the first items so
  910. they could use the same routine for opening/creating.
  911. when (flags and $100) the file will be append
  912. when (flags and $1000) the file will be truncate/rewritten
  913. when (flags and $10000) there is no check for close (needed for textfiles)
  914. }
  915. var
  916. regs : trealregs;
  917. action : longint;
  918. begin
  919. AllowSlash(p);
  920. { close first if opened }
  921. if ((flags and $10000)=0) then
  922. begin
  923. case filerec(f).mode of
  924. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  925. fmclosed : ;
  926. else
  927. begin
  928. inoutres:=102; {not assigned}
  929. exit;
  930. end;
  931. end;
  932. end;
  933. { reset file handle }
  934. filerec(f).handle:=UnusedHandle;
  935. action:=$1;
  936. { convert filemode to filerec modes }
  937. case (flags and 3) of
  938. 0 : filerec(f).mode:=fminput;
  939. 1 : filerec(f).mode:=fmoutput;
  940. 2 : filerec(f).mode:=fminout;
  941. end;
  942. if (flags and $1000)<>0 then
  943. action:=$12; {create file function}
  944. { empty name is special }
  945. if p[0]=#0 then
  946. begin
  947. case FileRec(f).mode of
  948. fminput :
  949. FileRec(f).Handle:=StdInputHandle;
  950. fminout, { this is set by rewrite }
  951. fmoutput :
  952. FileRec(f).Handle:=StdOutputHandle;
  953. fmappend :
  954. begin
  955. FileRec(f).Handle:=StdOutputHandle;
  956. FileRec(f).mode:=fmoutput; {fool fmappend}
  957. end;
  958. end;
  959. exit;
  960. end;
  961. { real dos call }
  962. syscopytodos(longint(p),strlen(p)+1);
  963. {$ifndef RTLLITE}
  964. if LFNSupport then
  965. regs.realeax:=$716c
  966. else
  967. {$endif RTLLITE}
  968. regs.realeax:=$6c00;
  969. regs.realedx:=action;
  970. regs.realds:=tb_segment;
  971. regs.realesi:=tb_offset;
  972. regs.realebx:=$2000+(flags and $ff);
  973. regs.realecx:=$20;
  974. sysrealintr($21,regs);
  975. {$ifndef RTLLITE}
  976. if (regs.realflags and carryflag) <> 0 then
  977. if lo(regs.realeax)=4 then
  978. if Increase_file_handle_count then
  979. begin
  980. { Try again }
  981. if LFNSupport then
  982. regs.realeax:=$716c
  983. else
  984. regs.realeax:=$6c00;
  985. regs.realedx:=action;
  986. regs.realds:=tb_segment;
  987. regs.realesi:=tb_offset;
  988. regs.realebx:=$2000+(flags and $ff);
  989. regs.realecx:=$20;
  990. sysrealintr($21,regs);
  991. end;
  992. {$endif RTLLITE}
  993. if (regs.realflags and carryflag) <> 0 then
  994. begin
  995. GetInOutRes(lo(regs.realeax));
  996. exit;
  997. end
  998. else
  999. begin
  1000. filerec(f).handle:=lo(regs.realeax);
  1001. {$ifndef RTLLITE}
  1002. { for systems that have more then 20 by default ! }
  1003. if lo(regs.realeax)>FileHandleCount then
  1004. FileHandleCount:=lo(regs.realeax);
  1005. {$endif RTLLITE}
  1006. end;
  1007. if lo(regs.realeax)<max_files then
  1008. begin
  1009. {$ifdef SYSTEMDEBUG}
  1010. if openfiles[lo(regs.realeax)] and
  1011. assigned(opennames[lo(regs.realeax)]) then
  1012. begin
  1013. Writeln(stderr,'file ',opennames[lo(regs.realeax)],'(',lo(regs.realeax),') not closed but handle reused!');
  1014. sysfreememsize(opennames[lo(regs.realeax)],strlen(opennames[lo(regs.realeax)])+1);
  1015. end;
  1016. {$endif SYSTEMDEBUG}
  1017. openfiles[lo(regs.realeax)]:=true;
  1018. {$ifdef SYSTEMDEBUG}
  1019. opennames[lo(regs.realeax)] := sysgetmem(strlen(p)+1);
  1020. move(p^,opennames[lo(regs.realeax)]^,strlen(p)+1);
  1021. {$endif SYSTEMDEBUG}
  1022. end;
  1023. { append mode }
  1024. if (flags and $100)<>0 then
  1025. begin
  1026. do_seekend(filerec(f).handle);
  1027. filerec(f).mode:=fmoutput; {fool fmappend}
  1028. end;
  1029. end;
  1030. function do_isdevice(handle:longint):boolean;
  1031. var
  1032. regs : trealregs;
  1033. begin
  1034. regs.realebx:=handle;
  1035. regs.realeax:=$4400;
  1036. sysrealintr($21,regs);
  1037. do_isdevice:=(regs.realedx and $80)<>0;
  1038. if (regs.realflags and carryflag) <> 0 then
  1039. GetInOutRes(lo(regs.realeax));
  1040. end;
  1041. {*****************************************************************************
  1042. UnTyped File Handling
  1043. *****************************************************************************}
  1044. {$i file.inc}
  1045. {*****************************************************************************
  1046. Typed File Handling
  1047. *****************************************************************************}
  1048. {$i typefile.inc}
  1049. {*****************************************************************************
  1050. Text File Handling
  1051. *****************************************************************************}
  1052. {$DEFINE EOF_CTRLZ}
  1053. {$i text.inc}
  1054. {*****************************************************************************
  1055. Generic Handling
  1056. *****************************************************************************}
  1057. {$ifdef TEST_GENERIC}
  1058. {$i generic.inc}
  1059. {$endif TEST_GENERIC}
  1060. {*****************************************************************************
  1061. Directory Handling
  1062. *****************************************************************************}
  1063. procedure DosDir(func:byte;const s:string);
  1064. var
  1065. buffer : array[0..255] of char;
  1066. regs : trealregs;
  1067. begin
  1068. move(s[1],buffer,length(s));
  1069. buffer[length(s)]:=#0;
  1070. AllowSlash(pchar(@buffer));
  1071. { True DOS does not like backslashes at end
  1072. Win95 DOS accepts this !!
  1073. but "\" and "c:\" should still be kept and accepted hopefully PM }
  1074. if (length(s)>0) and (buffer[length(s)-1]='\') and
  1075. Not ((length(s)=1) or ((length(s)=3) and (s[2]=':'))) then
  1076. buffer[length(s)-1]:=#0;
  1077. syscopytodos(longint(@buffer),length(s)+1);
  1078. regs.realedx:=tb_offset;
  1079. regs.realds:=tb_segment;
  1080. {$ifndef RTLLITE}
  1081. if LFNSupport then
  1082. regs.realeax:=$7100+func
  1083. else
  1084. {$endif RTLLITE}
  1085. regs.realeax:=func shl 8;
  1086. sysrealintr($21,regs);
  1087. if (regs.realflags and carryflag) <> 0 then
  1088. GetInOutRes(lo(regs.realeax));
  1089. end;
  1090. procedure mkdir(const s : string);[IOCheck];
  1091. begin
  1092. If InOutRes <> 0 then
  1093. exit;
  1094. DosDir($39,s);
  1095. end;
  1096. procedure rmdir(const s : string);[IOCheck];
  1097. begin
  1098. If InOutRes <> 0 then
  1099. exit;
  1100. DosDir($3a,s);
  1101. end;
  1102. procedure chdir(const s : string);[IOCheck];
  1103. var
  1104. regs : trealregs;
  1105. begin
  1106. If InOutRes <> 0 then
  1107. exit;
  1108. { First handle Drive changes }
  1109. if (length(s)>=2) and (s[2]=':') then
  1110. begin
  1111. regs.realedx:=(ord(s[1]) and (not 32))-ord('A');
  1112. regs.realeax:=$0e00;
  1113. sysrealintr($21,regs);
  1114. regs.realeax:=$1900;
  1115. sysrealintr($21,regs);
  1116. if byte(regs.realeax)<>byte(regs.realedx) then
  1117. begin
  1118. Inoutres:=15;
  1119. exit;
  1120. end;
  1121. { DosDir($3b,'c:') give Path not found error on
  1122. pure DOS PM }
  1123. if length(s)=2 then
  1124. exit;
  1125. end;
  1126. { do the normal dos chdir }
  1127. DosDir($3b,s);
  1128. end;
  1129. procedure getdir(drivenr : byte;var dir : shortstring);
  1130. var
  1131. temp : array[0..255] of char;
  1132. i : longint;
  1133. regs : trealregs;
  1134. begin
  1135. regs.realedx:=drivenr;
  1136. regs.realesi:=tb_offset;
  1137. regs.realds:=tb_segment;
  1138. {$ifndef RTLLITE}
  1139. if LFNSupport then
  1140. regs.realeax:=$7147
  1141. else
  1142. {$endif RTLLITE}
  1143. regs.realeax:=$4700;
  1144. sysrealintr($21,regs);
  1145. if (regs.realflags and carryflag) <> 0 then
  1146. Begin
  1147. GetInOutRes(lo(regs.realeax));
  1148. exit;
  1149. end
  1150. else
  1151. syscopyfromdos(longint(@temp),251);
  1152. { conversion to Pascal string including slash conversion }
  1153. i:=0;
  1154. while (temp[i]<>#0) do
  1155. begin
  1156. if temp[i]='/' then
  1157. temp[i]:='\';
  1158. dir[i+4]:=temp[i];
  1159. inc(i);
  1160. end;
  1161. dir[2]:=':';
  1162. dir[3]:='\';
  1163. dir[0]:=char(i+3);
  1164. { upcase the string }
  1165. if not FileNameCaseSensitive then
  1166. dir:=upcase(dir);
  1167. if drivenr<>0 then { Drive was supplied. We know it }
  1168. dir[1]:=char(65+drivenr-1)
  1169. else
  1170. begin
  1171. { We need to get the current drive from DOS function 19H }
  1172. { because the drive was the default, which can be unknown }
  1173. regs.realeax:=$1900;
  1174. sysrealintr($21,regs);
  1175. i:= (regs.realeax and $ff) + ord('A');
  1176. dir[1]:=chr(i);
  1177. end;
  1178. end;
  1179. {*****************************************************************************
  1180. SystemUnit Initialization
  1181. *****************************************************************************}
  1182. {$ifndef RTLLITE}
  1183. function CheckLFN:boolean;
  1184. var
  1185. regs : TRealRegs;
  1186. RootName : pchar;
  1187. begin
  1188. { Check LFN API on drive c:\ }
  1189. RootName:='C:\';
  1190. syscopytodos(longint(RootName),strlen(RootName)+1);
  1191. { Call 'Get Volume Information' ($71A0) }
  1192. regs.realeax:=$71a0;
  1193. regs.reales:=tb_segment;
  1194. regs.realedi:=tb_offset;
  1195. regs.realecx:=32;
  1196. regs.realds:=tb_segment;
  1197. regs.realedx:=tb_offset;
  1198. regs.realflags:=carryflag;
  1199. sysrealintr($21,regs);
  1200. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  1201. CheckLFN:=(regs.realflags and carryflag=0) and (regs.realebx and $4000=$4000);
  1202. end;
  1203. {$endif RTLLITE}
  1204. {$ifdef MT}
  1205. {$I thread.inc}
  1206. {$endif MT}
  1207. {$ifndef RTLLITE}
  1208. {$ifdef EXCEPTIONS_IN_SYSTEM}
  1209. {$define IN_SYSTEM}
  1210. {$i dpmiexcp.pp}
  1211. {$endif EXCEPTIONS_IN_SYSTEM}
  1212. {$endif RTLLITE}
  1213. var
  1214. temp_int : tseginfo;
  1215. Begin
  1216. { save old int 0 and 75 }
  1217. get_pm_interrupt($00,old_int00);
  1218. get_pm_interrupt($75,old_int75);
  1219. temp_int.segment:=get_cs;
  1220. temp_int.offset:=@new_int00;
  1221. set_pm_interrupt($00,temp_int);
  1222. {$ifndef EXCEPTIONS_IN_SYSTEM}
  1223. temp_int.offset:=@new_int75;
  1224. set_pm_interrupt($75,temp_int);
  1225. {$endif EXCEPTIONS_IN_SYSTEM}
  1226. { to test stack depth }
  1227. loweststack:=maxlongint;
  1228. { Setup heap }
  1229. InitHeap;
  1230. {$ifdef MT}
  1231. { before this, you can't use thread vars !!!! }
  1232. { threadvarblocksize is calculate before the initialization }
  1233. { of the system unit }
  1234. mainprogramthreadblock := sysgetmem(threadvarblocksize);
  1235. {$endif MT}
  1236. InitExceptions;
  1237. { Setup stdin, stdout and stderr }
  1238. OpenStdIO(Input,fmInput,StdInputHandle);
  1239. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1240. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1241. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1242. { Setup environment and arguments }
  1243. Setup_Environment;
  1244. Setup_Arguments;
  1245. { Use LFNSupport LFN }
  1246. LFNSupport:=CheckLFN;
  1247. if LFNSupport then
  1248. FileNameCaseSensitive:=true;
  1249. { Reset IO Error }
  1250. InOutRes:=0;
  1251. {$ifndef RTLLITE}
  1252. {$ifdef EXCEPTIONS_IN_SYSTEM}
  1253. InitDPMIExcp;
  1254. InstallDefaultHandlers;
  1255. {$endif EXCEPTIONS_IN_SYSTEM}
  1256. {$endif RTLLITE}
  1257. End.
  1258. {
  1259. $Log$
  1260. Revision 1.3 2000-08-13 19:23:26 peter
  1261. * fixed double declared ___exit() (merged)
  1262. Revision 1.2 2000/07/13 11:33:40 michael
  1263. + removed logs
  1264. }