system.pas 31 KB

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