system.pp 34 KB

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