system.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. {
  2. $Id$
  3. ****************************************************************************
  4. This file is part of the Free Pascal run time library.
  5. Copyright (c) 1999-2002 by Free Pascal development team
  6. Free Pascal - EMX runtime library
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. ****************************************************************************}
  13. unit {$ifdef VER1_0}sysemx{$else}System{$endif};
  14. interface
  15. {Link the startup code.}
  16. {$ifdef VER1_0}
  17. {$l prt1.oo2}
  18. {$else}
  19. {$l prt1.o}
  20. {$endif}
  21. {$I systemh.inc}
  22. {$I heaph.inc}
  23. {Platform specific information}
  24. const
  25. LineEnding = #13#10;
  26. { LFNSupport is defined separately below!!! }
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. PathSeparator = ';';
  30. { FileNameCaseSensitive is defined separately below!!! }
  31. type Tos=(osDOS,osOS2,osDPMI);
  32. var os_mode:Tos;
  33. first_meg:pointer;
  34. type TByteArray = array [0..$ffff] of byte;
  35. PByteArray = ^TByteArray;
  36. TSysThreadIB = record
  37. TID,
  38. Priority,
  39. Version: cardinal;
  40. MCCount,
  41. MCForceFlag: word;
  42. end;
  43. PSysThreadIB = ^TSysThreadIB;
  44. TThreadInfoBlock = record
  45. PExChain,
  46. Stack,
  47. StackLimit: pointer;
  48. TIB2: PSysThreadIB;
  49. Version,
  50. Ordinal: cardinal;
  51. end;
  52. PThreadInfoBlock = ^TThreadInfoBlock;
  53. PPThreadInfoBlock = ^PThreadInfoBlock;
  54. TProcessInfoBlock = record
  55. PID,
  56. ParentPid,
  57. Handle: cardinal;
  58. Cmd,
  59. Env: PByteArray;
  60. Status,
  61. ProcType: cardinal;
  62. end;
  63. PProcessInfoBlock = ^TProcessInfoBlock;
  64. PPProcessInfoBlock = ^PProcessInfoBlock;
  65. const UnusedHandle=$ffff;
  66. StdInputHandle=0;
  67. StdOutputHandle=1;
  68. StdErrorHandle=2;
  69. LFNSupport: boolean = true;
  70. FileNameCaseSensitive: boolean = false;
  71. sLineBreak = LineEnding;
  72. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  73. var
  74. { C-compatible arguments and environment }
  75. argc : longint;external name '_argc';
  76. argv : ppchar;external name '_argv';
  77. envp : ppchar;external name '_environ';
  78. EnvC: cardinal; external name '_envc';
  79. (* Pointer to the block of environment variables - used e.g. in unit Dos. *)
  80. Environment: PChar;
  81. var
  82. (* Type / run mode of the current process: *)
  83. (* 0 .. full screen OS/2 session *)
  84. (* 1 .. DOS session *)
  85. (* 2 .. VIO windowable OS/2 session *)
  86. (* 3 .. Presentation Manager OS/2 session *)
  87. (* 4 .. detached (background) OS/2 process *)
  88. ApplicationType: cardinal;
  89. implementation
  90. {$I system.inc}
  91. var
  92. heap_base: pointer; external name '__heap_base';
  93. heap_brk: pointer; external name '__heap_brk';
  94. heap_end: pointer; external name '__heap_end';
  95. (* Maximum heap size - only used if heap is allocated as continuous block. *)
  96. {$IFDEF CONTHEAP}
  97. BrkLimit: cardinal;
  98. {$ENDIF CONTHEAP}
  99. procedure DosGetInfoBlocks (PATIB: PPThreadInfoBlock;
  100. PAPIB: PPProcessInfoBlock); cdecl;
  101. external 'DOSCALLS' index 312;
  102. function DosLoadModule (ObjName: PChar; ObjLen: cardinal; DLLName: PChar;
  103. var Handle: cardinal): longint; cdecl;
  104. external 'DOSCALLS' index 318;
  105. function DosQueryProcAddr (Handle, Ordinal: cardinal; ProcName: PChar;
  106. var Address: pointer): longint; cdecl;
  107. external 'DOSCALLS' index 321;
  108. function DosSetRelMaxFH (var ReqCount, CurMaxFH: longint): longint; cdecl;
  109. external 'DOSCALLS' index 382;
  110. function DosSetCurrentDir (Name:PChar): longint; cdecl;
  111. external 'DOSCALLS' index 255;
  112. function DosSetDefaultDisk (DiskNum:longint): longint; cdecl;
  113. external 'DOSCALLS' index 220;
  114. { This is not real prototype, but is close enough }
  115. { for us (the 2nd parameter is actually a pointer }
  116. { to a structure). }
  117. function DosCreateDir( Name : pchar; p : pointer): longint; cdecl;
  118. external 'DOSCALLS' index 270;
  119. function DosDeleteDir( Name : pchar) : longint; cdecl;
  120. external 'DOSCALLS' index 226;
  121. {This is the correct way to call external assembler procedures.}
  122. procedure syscall; external name '___SYSCALL';
  123. {
  124. procedure syscall; external 'EMX' index 2;
  125. procedure emx_init; external 'EMX' index 1;
  126. }
  127. { converts an OS/2 error code to a TP compatible error }
  128. { code. Same thing exists under most other supported }
  129. { systems. }
  130. { Only call for OS/2 DLL imported routines }
  131. Procedure Errno2InOutRes;
  132. Begin
  133. { errors 1..18 are the same as in DOS }
  134. case InOutRes of
  135. { simple offset to convert these error codes }
  136. { exactly like the error codes in Win32 }
  137. 19..31 : InOutRes := InOutRes + 131;
  138. { gets a bit more complicated ... }
  139. 32..33 : InOutRes := 5;
  140. 38 : InOutRes := 100;
  141. 39 : InOutRes := 101;
  142. 112 : InOutRes := 101;
  143. 110 : InOutRes := 5;
  144. 114 : InOutRes := 6;
  145. 290 : InOutRes := 290;
  146. end;
  147. { all other cases ... we keep the same error code }
  148. end;
  149. {****************************************************************************
  150. Miscellaneous related routines.
  151. ****************************************************************************}
  152. {$asmmode intel}
  153. procedure system_exit; assembler;
  154. asm
  155. mov ah, 04ch
  156. mov al, byte ptr exitcode
  157. call syscall
  158. end ['EAX'];
  159. {$ASMMODE ATT}
  160. function paramcount:longint;assembler;
  161. asm
  162. movl argc,%eax
  163. decl %eax
  164. end ['EAX'];
  165. function args:pointer;assembler;
  166. asm
  167. movl argv,%eax
  168. end ['EAX'];
  169. function paramstr(l:longint):string;
  170. var p:^Pchar;
  171. begin
  172. { There seems to be a problem with EMX for DOS when trying to }
  173. { access paramstr(0), and to avoid problems between DOS and }
  174. { OS/2 they have been separated. }
  175. if os_Mode = OsOs2 then
  176. begin
  177. if L = 0 then
  178. begin
  179. GetMem (P, 260);
  180. p[0] := #0; { in case of error, initialize to empty string }
  181. {$ASMMODE INTEL}
  182. asm
  183. mov edx, P
  184. mov ecx, 260
  185. mov eax, 7F33h
  186. call syscall { error handle already with empty string }
  187. end ['eax', 'ecx', 'edx'];
  188. ParamStr := StrPas (PChar (P));
  189. FreeMem (P, 260);
  190. end
  191. else
  192. if (l>0) and (l<=paramcount) then
  193. begin
  194. p:=args;
  195. paramstr:=strpas(p[l]);
  196. end
  197. else paramstr:='';
  198. end
  199. else
  200. begin
  201. p:=args;
  202. paramstr:=strpas(p[l]);
  203. end;
  204. end;
  205. procedure randomize; assembler;
  206. asm
  207. mov ah, 2Ch
  208. call syscall
  209. mov word ptr [randseed], cx
  210. mov word ptr [randseed + 2], dx
  211. end ['eax', 'ecx', 'edx'];
  212. {$ASMMODE ATT}
  213. {****************************************************************************
  214. Heap management releated routines.
  215. ****************************************************************************}
  216. { this function allows to extend the heap by calling
  217. syscall $7f00 resizes the brk area}
  218. function sbrk(size:longint):pointer;
  219. {$IFDEF DUMPGROW}
  220. var
  221. L: longword;
  222. begin
  223. WriteLn ('Trying to grow heap by ', Size, ' to ', HeapSize + Size);
  224. {$IFDEF CONTHEAP}
  225. WriteLn ('BrkLimit is ', BrkLimit);
  226. {$ENDIF CONTHEAP}
  227. asm
  228. movl size,%edx
  229. movw $0x7f00,%eax
  230. call syscall { result directly in EAX }
  231. inc %eax { Result in EAX, -1 = error (has to be transformed to 0) }
  232. jz .LSbrk_End
  233. dec %eax { No error - back to previous value }
  234. .LSbrk_End:
  235. mov %eax,L
  236. end ['eax', 'edx'];
  237. WriteLn ('New heap at ', L);
  238. Sbrk := pointer (L);
  239. end;
  240. {$ELSE DUMPGROW}
  241. assembler;
  242. asm
  243. movl size,%edx
  244. movw $0x7f00,%eax
  245. call syscall
  246. inc %eax { Result in EAX, -1 = error (has to be transformed to 0) }
  247. jz .LSbrk_End
  248. dec %eax { No error - back to previous value }
  249. .LSbrk_End:
  250. end ['eax', 'edx'];
  251. {$ENDIF DUMPGROW}
  252. function getheapstart:pointer;assembler;
  253. asm
  254. movl heap_base,%eax
  255. end ['EAX'];
  256. function getheapsize:longint;assembler;
  257. asm
  258. movl heap_brk,%eax
  259. end ['EAX'];
  260. {$i heap.inc}
  261. {****************************************************************************
  262. Low Level File Routines
  263. ****************************************************************************}
  264. procedure allowslash(p:Pchar);
  265. {Allow slash as backslash.}
  266. var i:longint;
  267. begin
  268. for i:=0 to strlen(p) do
  269. if p[i]='/' then p[i]:='\';
  270. end;
  271. procedure do_close(h:longint);
  272. begin
  273. { Only three standard handles under real OS/2 }
  274. if (h > 4) or
  275. ((os_MODE = osOS2) and (h > 2)) then
  276. begin
  277. asm
  278. pushl %ebx
  279. movb $0x3e,%ah
  280. movl h,%ebx
  281. call syscall
  282. jnc .Lnoerror { error code? }
  283. movw %ax, InOutRes { yes, then set InOutRes }
  284. .Lnoerror:
  285. popl %ebx
  286. end ['eax'];
  287. end;
  288. end;
  289. procedure do_erase(p:Pchar);
  290. begin
  291. allowslash(p);
  292. asm
  293. movl P,%edx
  294. movb $0x41,%ah
  295. call syscall
  296. jnc .LERASE1
  297. movw %ax,inoutres;
  298. .LERASE1:
  299. end ['eax', 'edx'];
  300. end;
  301. procedure do_rename(p1,p2:Pchar);
  302. begin
  303. allowslash(p1);
  304. allowslash(p2);
  305. asm
  306. movl P1, %edx
  307. movl P2, %edi
  308. movb $0x56,%ah
  309. call syscall
  310. jnc .LRENAME1
  311. movw %ax,inoutres;
  312. .LRENAME1:
  313. end ['eax', 'edx', 'edi'];
  314. end;
  315. function do_read(h,addr,len:longint):longint; assembler;
  316. asm
  317. movl len,%ecx
  318. movl addr,%edx
  319. movl h,%ebx
  320. movb $0x3f,%ah
  321. call syscall
  322. jnc .LDOSREAD1
  323. movw %ax,inoutres;
  324. xorl %eax,%eax
  325. .LDOSREAD1:
  326. end ['eax', 'ebx', 'ecx', 'edx'];
  327. function do_write(h,addr,len:longint) : longint; assembler;
  328. asm
  329. xorl %eax,%eax
  330. cmpl $0,len { 0 bytes to write is undefined behavior }
  331. jz .LDOSWRITE1
  332. movl len,%ecx
  333. movl addr,%edx
  334. movl h,%ebx
  335. movb $0x40,%ah
  336. call syscall
  337. jnc .LDOSWRITE1
  338. movw %ax,inoutres;
  339. .LDOSWRITE1:
  340. end ['eax', 'ebx', 'ecx', 'edx'];
  341. function do_filepos(handle:longint): longint; assembler;
  342. asm
  343. movw $0x4201,%ax
  344. movl handle,%ebx
  345. xorl %edx,%edx
  346. call syscall
  347. jnc .LDOSFILEPOS
  348. movw %ax,inoutres;
  349. xorl %eax,%eax
  350. .LDOSFILEPOS:
  351. end ['eax', 'ebx', 'ecx', 'edx'];
  352. procedure do_seek(handle,pos:longint); assembler;
  353. asm
  354. movw $0x4200,%ax
  355. movl handle,%ebx
  356. movl pos,%edx
  357. call syscall
  358. jnc .LDOSSEEK1
  359. movw %ax,inoutres;
  360. .LDOSSEEK1:
  361. end ['eax', 'ebx', 'ecx', 'edx'];
  362. function do_seekend(handle:longint):longint; assembler;
  363. asm
  364. movw $0x4202,%ax
  365. movl handle,%ebx
  366. xorl %edx,%edx
  367. call syscall
  368. jnc .Lset_at_end1
  369. movw %ax,inoutres;
  370. xorl %eax,%eax
  371. .Lset_at_end1:
  372. end ['eax', 'ebx', 'ecx', 'edx'];
  373. function do_filesize(handle:longint):longint;
  374. var aktfilepos:longint;
  375. begin
  376. aktfilepos:=do_filepos(handle);
  377. do_filesize:=do_seekend(handle);
  378. do_seek(handle,aktfilepos);
  379. end;
  380. procedure do_truncate(handle,pos:longint); assembler;
  381. asm
  382. (* DOS function 40h isn't safe for this according to EMX documentation *)
  383. movl $0x7F25,%eax
  384. movl Handle,%ebx
  385. movl Pos,%edx
  386. call syscall
  387. incl %eax
  388. movl %ecx, %eax
  389. jnz .LTruncate1 { compare the value of EAX to verify error }
  390. (* File position is undefined after truncation, move to the end. *)
  391. movl $0x4202,%eax
  392. movl Handle,%ebx
  393. movl $0,%edx
  394. call syscall
  395. jnc .LTruncate2
  396. .LTruncate1:
  397. movw %ax,inoutres;
  398. .LTruncate2:
  399. end ['eax', 'ebx', 'ecx', 'edx'];
  400. const
  401. FileHandleCount: longint = 20;
  402. function Increase_File_Handle_Count: boolean;
  403. var Err: word;
  404. L1, L2: longint;
  405. begin
  406. if os_mode = osOS2 then
  407. begin
  408. L1 := 10;
  409. if DosSetRelMaxFH (L1, L2) <> 0 then
  410. Increase_File_Handle_Count := false
  411. else
  412. if L2 > FileHandleCount then
  413. begin
  414. FileHandleCount := L2;
  415. Increase_File_Handle_Count := true;
  416. end
  417. else
  418. Increase_File_Handle_Count := false;
  419. end
  420. else
  421. begin
  422. Inc (FileHandleCount, 10);
  423. Err := 0;
  424. asm
  425. pushl %ebx
  426. movl $0x6700, %eax
  427. movl FileHandleCount, %ebx
  428. call syscall
  429. jnc .LIncFHandles
  430. movw %ax, Err
  431. .LIncFHandles:
  432. popl %ebx
  433. end ['eax'];
  434. if Err <> 0 then
  435. begin
  436. Increase_File_Handle_Count := false;
  437. Dec (FileHandleCount, 10);
  438. end
  439. else
  440. Increase_File_Handle_Count := true;
  441. end;
  442. end;
  443. procedure do_open(var f;p:pchar;flags:longint);
  444. {
  445. filerec and textrec have both handle and mode as the first items so
  446. they could use the same routine for opening/creating.
  447. when (flags and $100) the file will be append
  448. when (flags and $1000) the file will be truncate/rewritten
  449. when (flags and $10000) there is no check for close (needed for textfiles)
  450. }
  451. var Action: longint;
  452. begin
  453. allowslash(p);
  454. { close first if opened }
  455. if ((flags and $10000)=0) then
  456. begin
  457. case filerec(f).mode of
  458. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  459. fmclosed:;
  460. else
  461. begin
  462. inoutres:=102; {not assigned}
  463. exit;
  464. end;
  465. end;
  466. end;
  467. { reset file handle }
  468. filerec(f).handle := UnusedHandle;
  469. Action := 0;
  470. { convert filemode to filerec modes }
  471. case (flags and 3) of
  472. 0 : filerec(f).mode:=fminput;
  473. 1 : filerec(f).mode:=fmoutput;
  474. 2 : filerec(f).mode:=fminout;
  475. end;
  476. if (flags and $1000)<>0 then
  477. Action := $50000; (* Create / replace *)
  478. { empty name is special }
  479. if p[0]=#0 then
  480. begin
  481. case FileRec(f).mode of
  482. fminput :
  483. FileRec(f).Handle:=StdInputHandle;
  484. fminout, { this is set by rewrite }
  485. fmoutput :
  486. FileRec(f).Handle:=StdOutputHandle;
  487. fmappend :
  488. begin
  489. FileRec(f).Handle:=StdOutputHandle;
  490. FileRec(f).mode:=fmoutput; {fool fmappend}
  491. end;
  492. end;
  493. exit;
  494. end;
  495. Action := Action or (Flags and $FF);
  496. (* DenyNone if sharing not specified. *)
  497. if Flags and 112 = 0 then
  498. Action := Action or 64;
  499. asm
  500. pushl %ebx
  501. movl $0x7f2b, %eax
  502. movl Action, %ecx
  503. movl p, %edx
  504. call syscall
  505. cmpl $0xffffffff, %eax
  506. jnz .LOPEN1
  507. movw %cx, InOutRes
  508. movw UnusedHandle, %ax
  509. .LOPEN1:
  510. movl f,%edx { Warning : This assumes Handle is first }
  511. movw %ax,(%edx) { field of FileRec }
  512. popl %ebx
  513. end ['eax', 'ecx', 'edx'];
  514. if (InOutRes = 4) and Increase_File_Handle_Count then
  515. (* Trying again after increasing amount of file handles *)
  516. asm
  517. movl $0x7f2b, %eax
  518. movl Action, %ecx
  519. movl p, %edx
  520. call syscall
  521. cmpl $0xffffffff, %eax
  522. jnz .LOPEN2
  523. movw %cx, InOutRes
  524. movw UnusedHandle, %ax
  525. .LOPEN2:
  526. movl f,%edx
  527. movw %ax,(%edx)
  528. end ['eax', 'ecx', 'edx'];
  529. { for systems that have more handles }
  530. if FileRec (F).Handle > FileHandleCount then
  531. FileHandleCount := FileRec (F).Handle;
  532. if ((Flags and $100) <> 0) and
  533. (FileRec (F).Handle <> UnusedHandle) then
  534. begin
  535. do_seekend (FileRec (F).Handle);
  536. FileRec (F).Mode := fmOutput; {fool fmappend}
  537. end;
  538. end;
  539. {$ASMMODE INTEL}
  540. function do_isdevice (Handle: longint): boolean; assembler;
  541. (*
  542. var HT, Attr: longint;
  543. begin
  544. if os_mode = osOS2 then
  545. begin
  546. if DosQueryHType (Handle, HT, Attr) <> 0 then HT := 1;
  547. end
  548. else
  549. *)
  550. asm
  551. push ebx
  552. mov ebx, Handle
  553. mov eax, 4400h
  554. call syscall
  555. mov eax, 1
  556. jc @IsDevEnd
  557. test edx, 80h { verify if it is a file }
  558. jnz @IsDevEnd
  559. dec eax { nope, so result is zero }
  560. @IsDevEnd:
  561. pop ebx
  562. end ['eax', 'edx'];
  563. {$ASMMODE ATT}
  564. {*****************************************************************************
  565. UnTyped File Handling
  566. *****************************************************************************}
  567. {$i file.inc}
  568. {*****************************************************************************
  569. Typed File Handling
  570. *****************************************************************************}
  571. {$i typefile.inc}
  572. {*****************************************************************************
  573. Text File Handling
  574. *****************************************************************************}
  575. {$DEFINE EOF_CTRLZ}
  576. {$i text.inc}
  577. {****************************************************************************
  578. Directory related routines.
  579. ****************************************************************************}
  580. {*****************************************************************************
  581. Directory Handling
  582. *****************************************************************************}
  583. procedure dosdir(func:byte;const s:string);
  584. var buffer:array[0..255] of char;
  585. begin
  586. move(s[1],buffer,length(s));
  587. buffer[length(s)]:=#0;
  588. allowslash(Pchar(@buffer));
  589. asm
  590. leal buffer,%edx
  591. movb func,%ah
  592. call syscall
  593. jnc .LDOS_DIRS1
  594. movw %ax,inoutres
  595. .LDOS_DIRS1:
  596. end ['eax', 'edx'];
  597. end;
  598. procedure MkDir (const S: string);[IOCHECK];
  599. var buffer:array[0..255] of char;
  600. Rc : word;
  601. begin
  602. If (s='') or (InOutRes <> 0) then
  603. exit;
  604. if os_mode = osOs2 then
  605. begin
  606. move(s[1],buffer,length(s));
  607. buffer[length(s)]:=#0;
  608. allowslash(Pchar(@buffer));
  609. Rc := DosCreateDir(buffer,nil);
  610. if Rc <> 0 then
  611. begin
  612. InOutRes := Rc;
  613. Errno2Inoutres;
  614. end;
  615. end
  616. else
  617. begin
  618. { Under EMX 0.9d DOS this routine call may sometimes fail }
  619. { The syscall documentation indicates clearly that this }
  620. { routine was NOT tested. }
  621. DosDir ($39, S);
  622. end;
  623. end;
  624. procedure rmdir(const s : string);[IOCHECK];
  625. var buffer:array[0..255] of char;
  626. Rc : word;
  627. begin
  628. if (s = '.' ) then
  629. InOutRes := 16;
  630. If (s='') or (InOutRes <> 0) then
  631. exit;
  632. if os_mode = osOs2 then
  633. begin
  634. move(s[1],buffer,length(s));
  635. buffer[length(s)]:=#0;
  636. allowslash(Pchar(@buffer));
  637. Rc := DosDeleteDir(buffer);
  638. if Rc <> 0 then
  639. begin
  640. InOutRes := Rc;
  641. Errno2Inoutres;
  642. end;
  643. end
  644. else
  645. begin
  646. { Under EMX 0.9d DOS this routine call may sometimes fail }
  647. { The syscall documentation indicates clearly that this }
  648. { routine was NOT tested. }
  649. DosDir ($3A, S);
  650. end;
  651. end;
  652. {$ASMMODE INTEL}
  653. procedure ChDir (const S: string);[IOCheck];
  654. var RC: longint;
  655. Buffer: array [0..255] of char;
  656. begin
  657. If (s='') or (InOutRes <> 0) then
  658. exit;
  659. (* According to EMX documentation, EMX has only one current directory
  660. for all processes, so we'll use native calls under OS/2. *)
  661. if os_Mode = osOS2 then
  662. begin
  663. if (Length (S) >= 2) and (S [2] = ':') then
  664. begin
  665. RC := DosSetDefaultDisk ((Ord (S [1]) and
  666. not ($20)) - $40);
  667. if RC <> 0 then
  668. InOutRes := RC
  669. else
  670. if Length (S) > 2 then
  671. begin
  672. Move (S [1], Buffer, Length (S));
  673. Buffer [Length (S)] := #0;
  674. AllowSlash (PChar (@Buffer));
  675. RC := DosSetCurrentDir (@Buffer);
  676. if RC <> 0 then
  677. begin
  678. InOutRes := RC;
  679. Errno2InOutRes;
  680. end;
  681. end;
  682. end
  683. else
  684. begin
  685. Move (S [1], Buffer, Length (S));
  686. Buffer [Length (S)] := #0;
  687. AllowSlash (PChar (@Buffer));
  688. RC := DosSetCurrentDir (@Buffer);
  689. if RC <> 0 then
  690. begin
  691. InOutRes:= RC;
  692. Errno2InOutRes;
  693. end;
  694. end;
  695. end
  696. else
  697. if (Length (S) >= 2) and (S [2] = ':') then
  698. begin
  699. asm
  700. mov esi, S
  701. mov al, [esi + 1]
  702. and al, not (20h)
  703. sub al, 41h
  704. mov edx, eax
  705. mov ah, 0Eh
  706. call syscall
  707. mov ah, 19h
  708. call syscall
  709. cmp al, dl
  710. jz @LCHDIR
  711. mov InOutRes, 15
  712. @LCHDIR:
  713. end ['eax','edx','esi'];
  714. if (Length (S) > 2) and (InOutRes <> 0) then
  715. { Under EMX 0.9d DOS this routine may sometime }
  716. { fail or crash the system. }
  717. DosDir ($3B, S);
  718. end
  719. else
  720. { Under EMX 0.9d DOS this routine may sometime }
  721. { fail or crash the system. }
  722. DosDir ($3B, S);
  723. end;
  724. {$ASMMODE ATT}
  725. procedure GetDir (DriveNr: byte; var Dir: ShortString);
  726. {Written by Michael Van Canneyt.}
  727. var sof:Pchar;
  728. i:byte;
  729. begin
  730. Dir [4] := #0;
  731. { Used in case the specified drive isn't available }
  732. sof:=pchar(@dir[4]);
  733. { dir[1..3] will contain '[drivenr]:\', but is not }
  734. { supplied by DOS, so we let dos string start at }
  735. { dir[4] }
  736. { Get dir from drivenr : 0=default, 1=A etc... }
  737. asm
  738. movb drivenr,%dl
  739. movl sof,%esi
  740. mov $0x47,%ah
  741. call syscall
  742. jnc .LGetDir
  743. movw %ax, InOutRes
  744. .LGetDir:
  745. end [ 'eax','edx','esi'];
  746. { Now Dir should be filled with directory in ASCIIZ, }
  747. { starting from dir[4] }
  748. dir[0]:=#3;
  749. dir[2]:=':';
  750. dir[3]:='\';
  751. i:=4;
  752. {Conversion to Pascal string }
  753. while (dir[i]<>#0) do
  754. begin
  755. { convert path name to DOS }
  756. if dir[i]='/' then
  757. dir[i]:='\';
  758. dir[0]:=char(i);
  759. inc(i);
  760. end;
  761. { upcase the string (FPC function) }
  762. if drivenr<>0 then { Drive was supplied. We know it }
  763. dir[1]:=chr(64+drivenr)
  764. else
  765. begin
  766. { We need to get the current drive from DOS function 19H }
  767. { because the drive was the default, which can be unknown }
  768. asm
  769. movb $0x19,%ah
  770. call syscall
  771. addb $65,%al
  772. movb %al,i
  773. end ['eax'];
  774. dir[1]:=char(i);
  775. end;
  776. if not (FileNameCaseSensitive) then dir:=upcase(dir);
  777. end;
  778. {*****************************************************************************
  779. System unit initialization.
  780. ****************************************************************************}
  781. {****************************************************************************
  782. Error Message writing using messageboxes
  783. ****************************************************************************}
  784. type
  785. TWinMessageBox = function (Parent, Owner: cardinal;
  786. BoxText, BoxTitle: PChar; Identity, Style: cardinal): cardinal; cdecl;
  787. TWinInitialize = function (Options: cardinal): cardinal; cdecl;
  788. TWinCreateMsgQueue = function (Handle: cardinal; cmsg: longint): cardinal;
  789. cdecl;
  790. const
  791. ErrorBufferLength = 1024;
  792. mb_OK = $0000;
  793. mb_Error = $0040;
  794. mb_Moveable = $4000;
  795. MBStyle = mb_OK or mb_Error or mb_Moveable;
  796. WinInitialize: TWinInitialize = nil;
  797. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  798. WinMessageBox: TWinMessageBox = nil;
  799. EnvSize: cardinal = 0;
  800. var
  801. ErrorBuf: array [0..ErrorBufferLength] of char;
  802. ErrorLen: longint;
  803. PMWinHandle: cardinal;
  804. function ErrorWrite (var F: TextRec): integer;
  805. {
  806. An error message should always end with #13#10#13#10
  807. }
  808. var
  809. P: PChar;
  810. I: longint;
  811. begin
  812. if F.BufPos > 0 then
  813. begin
  814. if F.BufPos + ErrorLen > ErrorBufferLength then
  815. I := ErrorBufferLength - ErrorLen
  816. else
  817. I := F.BufPos;
  818. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  819. Inc (ErrorLen, I);
  820. ErrorBuf [ErrorLen] := #0;
  821. end;
  822. if ErrorLen > 3 then
  823. begin
  824. P := @ErrorBuf [ErrorLen];
  825. for I := 1 to 4 do
  826. begin
  827. Dec (P);
  828. if not (P^ in [#10, #13]) then
  829. break;
  830. end;
  831. end;
  832. if ErrorLen = ErrorBufferLength then
  833. I := 4;
  834. if (I = 4) then
  835. begin
  836. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  837. ErrorLen := 0;
  838. end;
  839. F.BufPos := 0;
  840. ErrorWrite := 0;
  841. end;
  842. function ErrorClose (var F: TextRec): integer;
  843. begin
  844. if ErrorLen > 0 then
  845. begin
  846. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  847. ErrorLen := 0;
  848. end;
  849. ErrorLen := 0;
  850. ErrorClose := 0;
  851. end;
  852. function ErrorOpen (var F: TextRec): integer;
  853. begin
  854. TextRec(F).InOutFunc := @ErrorWrite;
  855. TextRec(F).FlushFunc := @ErrorWrite;
  856. TextRec(F).CloseFunc := @ErrorClose;
  857. ErrorOpen := 0;
  858. end;
  859. procedure AssignError (var T: Text);
  860. begin
  861. Assign (T, '');
  862. TextRec (T).OpenFunc := @ErrorOpen;
  863. Rewrite (T);
  864. end;
  865. procedure DosEnvInit;
  866. var
  867. Q: PPChar;
  868. I: cardinal;
  869. begin
  870. (* It's a hack, in fact - DOS stores the environment the same way as OS/2 does,
  871. but I don't know how to find Program Segment Prefix and thus the environment
  872. address under EMX, so I'm recreating this structure using EnvP pointer. *)
  873. {$ASMMODE INTEL}
  874. asm
  875. cld
  876. mov ecx, EnvC
  877. mov esi, EnvP
  878. xor eax, eax
  879. xor edx, edx
  880. @L1:
  881. xchg eax, edx
  882. push ecx
  883. mov ecx, -1
  884. mov edi, [esi]
  885. repne
  886. scasb
  887. neg ecx
  888. dec ecx
  889. xchg eax, edx
  890. add eax, ecx
  891. pop ecx
  892. dec ecx
  893. jecxz @Stop
  894. inc esi
  895. inc esi
  896. inc esi
  897. inc esi
  898. jmp @L1
  899. @Stop:
  900. inc eax
  901. mov EnvSize, eax
  902. end ['eax','ecx','edx','esi','edi'];
  903. Environment := GetMem (EnvSize);
  904. asm
  905. cld
  906. mov ecx, EnvC
  907. mov edx, EnvP
  908. mov edi, Environment
  909. @L2:
  910. mov esi, [edx]
  911. @Copying:
  912. lodsb
  913. stosb
  914. or al, al
  915. jnz @Copying
  916. dec ecx
  917. jecxz @Stop2
  918. inc edx
  919. inc edx
  920. inc edx
  921. inc edx
  922. jmp @L2
  923. @Stop2:
  924. stosb
  925. end ['eax','ecx','edx','esi','edi'];
  926. end;
  927. procedure SysInitStdIO;
  928. begin
  929. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  930. displayed in a messagebox }
  931. (*
  932. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  933. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  934. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  935. if not IsConsole then
  936. begin
  937. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  938. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  939. and
  940. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  941. and
  942. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  943. = 0)
  944. then
  945. begin
  946. WinInitialize (0);
  947. WinCreateMsgQueue (0, 0);
  948. end
  949. else
  950. HandleError (2);
  951. AssignError (StdErr);
  952. AssignError (StdOut);
  953. Assign (Output, '');
  954. Assign (Input, '');
  955. end
  956. else
  957. begin
  958. *)
  959. OpenStdIO (Input, fmInput, StdInputHandle);
  960. OpenStdIO (Output, fmOutput, StdOutputHandle);
  961. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  962. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  963. (*
  964. end;
  965. *)
  966. end;
  967. function GetFileHandleCount: longint;
  968. var L1, L2: longint;
  969. begin
  970. L1 := 0; (* Don't change the amount, just check. *)
  971. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  972. else GetFileHandleCount := L2;
  973. end;
  974. var TIB: PThreadInfoBlock;
  975. PIB: PProcessInfoBlock;
  976. begin
  977. IsLibrary := FALSE;
  978. {Determine the operating system we are running on.}
  979. {$ASMMODE INTEL}
  980. asm
  981. push ebx
  982. mov os_mode, 0
  983. mov eax, 7F0Ah
  984. call syscall
  985. test bx, 512 {Bit 9 is OS/2 flag.}
  986. setne byte ptr os_mode
  987. test bx, 4096
  988. jz @noRSX
  989. mov os_mode, 2
  990. @noRSX:
  991. {Enable the brk area by initializing it with the initial heap size.}
  992. mov eax, 7F01h
  993. mov edx, heap_brk
  994. add edx, heap_base
  995. call syscall
  996. cmp eax, -1
  997. jnz @heapok
  998. pop ebx
  999. push dword 204
  1000. call HandleError
  1001. @heapok:
  1002. {$IFDEF CONTHEAP}
  1003. { Find out brk limit }
  1004. mov eax, 7F02h
  1005. mov ecx, 3
  1006. call syscall
  1007. jcxz @heaplimitknown
  1008. mov eax, 0
  1009. @heaplimitknown:
  1010. mov BrkLimit, eax
  1011. {$ELSE CONTHEAP}
  1012. { Change sbrk behaviour to allocate arbitrary (non-contiguous) memory blocks }
  1013. mov eax, 7F0Fh
  1014. mov ecx, 0Ch
  1015. mov edx, 8
  1016. call syscall
  1017. {$ENDIF CONTHEAP}
  1018. pop ebx
  1019. end ['eax', 'ecx', 'edx'];
  1020. { in OS/2 this will always be nil, but in DOS mode }
  1021. { this can be changed. }
  1022. first_meg := nil;
  1023. {Now request, if we are running under DOS,
  1024. read-access to the first meg. of memory.}
  1025. if os_mode in [osDOS,osDPMI] then
  1026. asm
  1027. push ebx
  1028. mov eax, 7F13h
  1029. xor ebx, ebx
  1030. mov ecx, 0FFFh
  1031. xor edx, edx
  1032. call syscall
  1033. jc @endmem
  1034. mov first_meg, eax
  1035. @endmem:
  1036. pop ebx
  1037. end ['eax', 'ecx', 'edx']
  1038. else
  1039. begin
  1040. (* Initialize the amount of file handles *)
  1041. FileHandleCount := GetFileHandleCount;
  1042. end;
  1043. {At 0.9.2, case for enumeration does not work.}
  1044. case os_mode of
  1045. osDOS:
  1046. begin
  1047. stackbottom:=cardinal(heap_brk); {In DOS mode, heap_brk is
  1048. also the stack bottom.}
  1049. ApplicationType := 1; (* Running under DOS. *)
  1050. IsConsole := true;
  1051. DosEnvInit;
  1052. end;
  1053. osOS2:
  1054. begin
  1055. DosGetInfoBlocks (@TIB, @PIB);
  1056. StackBottom := cardinal (TIB^.Stack);
  1057. Environment := pointer (PIB^.Env);
  1058. ApplicationType := PIB^.ProcType;
  1059. IsConsole := ApplicationType <> 3;
  1060. end;
  1061. osDPMI:
  1062. begin
  1063. stackbottom:=0; {Not sure how to get it, but seems to be
  1064. always zero.}
  1065. ApplicationType := 1; (* Running under DOS. *)
  1066. IsConsole := true;
  1067. DosEnvInit;
  1068. end;
  1069. end;
  1070. exitproc:=nil;
  1071. {Initialize the heap.}
  1072. initheap;
  1073. { ... and exceptions }
  1074. SysInitExceptions;
  1075. { ... and I/O }
  1076. SysInitStdIO;
  1077. { no I/O-Error }
  1078. inoutres:=0;
  1079. {$ifdef HASVARIANT}
  1080. initvariantmanager;
  1081. {$endif HASVARIANT}
  1082. {$IFDEF DUMPGROW}
  1083. {$IFDEF CONTHEAP}
  1084. WriteLn ('Initial brk size is ', GetHeapSize);
  1085. WriteLn ('Brk limit is ', BrkLimit);
  1086. {$ENDIF CONTHEAP}
  1087. {$ENDIF DUMPGROW}
  1088. end.
  1089. {
  1090. $Log$
  1091. Revision 1.14 2003-10-12 18:07:30 hajny
  1092. * wrong use of Intel syntax
  1093. Revision 1.13 2003/10/12 17:59:40 hajny
  1094. * wrong use of Intel syntax
  1095. Revision 1.12 2003/10/12 17:52:28 hajny
  1096. * wrong use of Intel syntax
  1097. Revision 1.11 2003/10/12 10:45:36 hajny
  1098. * sbrk error handling corrected
  1099. Revision 1.10 2003/10/07 21:33:24 hajny
  1100. * stdcall fixes and asm routines cleanup
  1101. Revision 1.9 2003/10/04 17:53:08 hajny
  1102. * stdcall changes merged to EMX
  1103. Revision 1.8 2003/09/29 18:39:59 hajny
  1104. * append fix applied to GO32v2, OS/2 and EMX
  1105. Revision 1.7 2003/09/27 11:52:35 peter
  1106. * sbrk returns pointer
  1107. Revision 1.6 2003/09/24 11:13:09 yuri
  1108. * Cosmetic changes
  1109. * Slightly improved emx.pas
  1110. Revision 1.5 2003/06/26 17:12:29 yuri
  1111. * pmbidi added
  1112. * some cosmetic changes
  1113. Revision 1.4 2003/03/23 23:11:17 hajny
  1114. + emx target added
  1115. Revision 1.3 2002/12/15 22:46:29 hajny
  1116. * First_Meg fixed + Environment initialization under Dos
  1117. Revision 1.2 2002/11/17 22:32:05 hajny
  1118. * type corrections (longing x cardinal)
  1119. Revision 1.1 2002/11/17 16:22:54 hajny
  1120. + RTL for emx target
  1121. }