system.pas 33 KB

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