sysutils.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for OS/2
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. {$MODESWITCH OUT}
  16. { force ansistrings }
  17. {$H+}
  18. {$DEFINE HAS_SLEEP}
  19. { Include platform independent interface part }
  20. {$i sysutilh.inc}
  21. implementation
  22. uses
  23. sysconst, DosCalls;
  24. type
  25. (* Necessary here due to a different definition of TDateTime in DosCalls. *)
  26. TDateTime = System.TDateTime;
  27. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  28. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  29. {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
  30. {$DEFINE HAS_GETTICKCOUNT}
  31. {$DEFINE HAS_GETTICKCOUNT64}
  32. { used OS file system APIs use ansistring }
  33. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  34. { Include platform independent implementation part }
  35. {$i sysutils.inc}
  36. {****************************************************************************
  37. File Functions
  38. ****************************************************************************}
  39. const
  40. ofRead = $0000; {Open for reading}
  41. ofWrite = $0001; {Open for writing}
  42. ofReadWrite = $0002; {Open for reading/writing}
  43. doDenyRW = $0010; {DenyAll (no sharing)}
  44. faCreateNew = $00010000; {Create if file does not exist}
  45. faOpenReplace = $00040000; {Truncate if file exists}
  46. faCreate = $00050000; {Create if file does not exist, truncate otherwise}
  47. FindResvdMask = $00003737; {Allowed bits in attribute
  48. specification for DosFindFirst call.}
  49. function FileOpen (const FileName: rawbytestring; Mode: integer): THandle;
  50. Var
  51. SystemFileName: RawByteString;
  52. Handle: THandle;
  53. Rc, Action: cardinal;
  54. begin
  55. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  56. (* DenyNone if sharing not specified. *)
  57. if (Mode and 112 = 0) or (Mode and 112 > 64) then
  58. Mode := Mode or 64;
  59. Rc:=Sys_DosOpenL(PChar (SystemFileName), Handle, Action, 0, 0, 1, Mode, nil);
  60. If Rc=0 then
  61. FileOpen:=Handle
  62. else
  63. FileOpen:=feInvalidHandle; //FileOpen:=-RC;
  64. //should return feInvalidHandle(=-1) if fail, other negative returned value are no more errors
  65. end;
  66. function FileCreate (const FileName: RawByteString): THandle;
  67. begin
  68. FileCreate := FileCreate (FileName, doDenyRW, 777); (* Sharing to DenyAll *)
  69. end;
  70. function FileCreate (const FileName: RawByteString; Rights: integer): THandle;
  71. begin
  72. FileCreate := FileCreate (FileName, doDenyRW, Rights);
  73. (* Sharing to DenyAll *)
  74. end;
  75. function FileCreate (const FileName: RawByteString; ShareMode: integer;
  76. Rights: integer): THandle;
  77. var
  78. SystemFileName: RawByteString;
  79. Handle: THandle;
  80. RC, Action: cardinal;
  81. begin
  82. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  83. ShareMode := ShareMode and 112;
  84. (* Sharing to DenyAll as default in case of values not allowed by OS/2. *)
  85. if (ShareMode = 0) or (ShareMode > 64) then
  86. ShareMode := doDenyRW;
  87. RC := Sys_DosOpenL (PChar (SystemFileName), Handle, Action, 0, 0, $12,
  88. faCreate or ofReadWrite or ShareMode, nil);
  89. if RC = 0 then
  90. FileCreate := Handle
  91. else
  92. FileCreate := feInvalidHandle;
  93. End;
  94. function FileRead (Handle: THandle; Out Buffer; Count: longint): longint;
  95. Var
  96. T: cardinal;
  97. begin
  98. DosRead(Handle, Buffer, Count, T);
  99. FileRead := longint (T);
  100. end;
  101. function FileWrite (Handle: THandle; const Buffer; Count: longint): longint;
  102. Var
  103. T: cardinal;
  104. begin
  105. DosWrite (Handle, Buffer, Count, T);
  106. FileWrite := longint (T);
  107. end;
  108. function FileSeek (Handle: THandle; FOffset, Origin: longint): longint;
  109. var
  110. NPos: int64;
  111. begin
  112. if (Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos) = 0)
  113. and (NPos < high (longint)) then
  114. FileSeek:= longint (NPos)
  115. else
  116. FileSeek:=-1;
  117. end;
  118. function FileSeek (Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  119. var
  120. NPos: int64;
  121. begin
  122. if Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos) = 0 then
  123. FileSeek:= NPos
  124. else
  125. FileSeek:=-1;
  126. end;
  127. procedure FileClose (Handle: THandle);
  128. begin
  129. DosClose(Handle);
  130. end;
  131. function FileTruncate (Handle: THandle; Size: Int64): boolean;
  132. begin
  133. FileTruncate:=Sys_DosSetFileSizeL(Handle, Size)=0;
  134. FileSeek(Handle, 0, 2);
  135. end;
  136. function FileAge (const FileName: string): longint;
  137. var Handle: longint;
  138. begin
  139. Handle := FileOpen (FileName, 0);
  140. if Handle <> -1 then
  141. begin
  142. Result := FileGetDate (Handle);
  143. FileClose (Handle);
  144. end
  145. else
  146. Result := -1;
  147. end;
  148. function FileExists (const FileName: RawByteString): boolean;
  149. var
  150. L: longint;
  151. begin
  152. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  153. if FileName = '' then
  154. Result := false
  155. else
  156. begin
  157. L := FileGetAttr (FileName);
  158. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  159. (* Neither VolumeIDs nor directories are files. *)
  160. end;
  161. end;
  162. type TRec = record
  163. T, D: word;
  164. end;
  165. PSearchRec = ^TSearchRec;
  166. function FindFirst (const Path: string; Attr: longint; out Rslt: TSearchRec): longint;
  167. var SR: PSearchRec;
  168. FStat: PFileFindBuf3L;
  169. Count: cardinal;
  170. Err: cardinal;
  171. I: cardinal;
  172. begin
  173. New (FStat);
  174. Rslt.FindHandle := THandle ($FFFFFFFF);
  175. Count := 1;
  176. if FSApi64 then
  177. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  178. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandardL)
  179. else
  180. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  181. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandard);
  182. if (Err = 0) and (Count = 0) then
  183. Err := 18;
  184. FindFirst := -Err;
  185. if Err = 0 then
  186. begin
  187. Rslt.ExcludeAttr := 0;
  188. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  189. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  190. if FSApi64 then
  191. begin
  192. Rslt.Size := FStat^.FileSize;
  193. Rslt.Name := FStat^.Name;
  194. Rslt.Attr := FStat^.AttrFile;
  195. end
  196. else
  197. begin
  198. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  199. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  200. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  201. end;
  202. end
  203. else
  204. FindClose(Rslt);
  205. Dispose (FStat);
  206. end;
  207. function FindNext (var Rslt: TSearchRec): longint;
  208. var
  209. SR: PSearchRec;
  210. FStat: PFileFindBuf3L;
  211. Count: cardinal;
  212. Err: cardinal;
  213. begin
  214. New (FStat);
  215. Count := 1;
  216. Err := DosFindNext (Rslt.FindHandle, FStat, SizeOf (FStat^), Count);
  217. if (Err = 0) and (Count = 0) then
  218. Err := 18;
  219. FindNext := -Err;
  220. if Err = 0 then
  221. begin
  222. Rslt.ExcludeAttr := 0;
  223. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  224. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  225. if FSApi64 then
  226. begin
  227. Rslt.Size := FStat^.FileSize;
  228. Rslt.Name := FStat^.Name;
  229. Rslt.Attr := FStat^.AttrFile;
  230. end
  231. else
  232. begin
  233. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  234. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  235. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  236. end;
  237. end;
  238. Dispose (FStat);
  239. end;
  240. procedure FindClose (var F: TSearchrec);
  241. var
  242. SR: PSearchRec;
  243. begin
  244. DosFindClose (F.FindHandle);
  245. F.FindHandle := 0;
  246. end;
  247. function FileGetDate (Handle: THandle): longint;
  248. var
  249. FStat: TFileStatus3;
  250. Time: Longint;
  251. RC: cardinal;
  252. begin
  253. RC := DosQueryFileInfo(Handle, ilStandard, @FStat, SizeOf(FStat));
  254. if RC = 0 then
  255. begin
  256. Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
  257. if Time = 0 then
  258. Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
  259. end else
  260. Time:=0;
  261. FileGetDate:=Time;
  262. end;
  263. function FileSetDate (Handle: THandle; Age: longint): longint;
  264. var
  265. FStat: PFileStatus3;
  266. RC: cardinal;
  267. begin
  268. New (FStat);
  269. RC := DosQueryFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  270. if RC <> 0 then
  271. FileSetDate := -1
  272. else
  273. begin
  274. FStat^.DateLastAccess := Hi (Age);
  275. FStat^.DateLastWrite := Hi (Age);
  276. FStat^.TimeLastAccess := Lo (Age);
  277. FStat^.TimeLastWrite := Lo (Age);
  278. RC := DosSetFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  279. if RC <> 0 then
  280. FileSetDate := -1
  281. else
  282. FileSetDate := 0;
  283. end;
  284. Dispose (FStat);
  285. end;
  286. function FileGetAttr (const FileName: RawByteString): longint;
  287. var
  288. FS: PFileStatus3;
  289. SystemFileName: RawByteString;
  290. begin
  291. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  292. New(FS);
  293. Result:=-DosQueryPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^));
  294. If Result=0 Then Result:=FS^.attrFile;
  295. Dispose(FS);
  296. end;
  297. function FileSetAttr (const Filename: RawByteString; Attr: longint): longint;
  298. Var
  299. FS: PFileStatus3;
  300. SystemFileName: RawByteString;
  301. Begin
  302. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  303. New(FS);
  304. FillChar(FS, SizeOf(FS^), 0);
  305. FS^.AttrFile:=Attr;
  306. Result:=-DosSetPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^), 0);
  307. Dispose(FS);
  308. end;
  309. function DeleteFile (const FileName: RawByteString): boolean;
  310. var
  311. SystemFileName: RawByteString;
  312. Begin
  313. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  314. Result:=(DosDelete(PChar (FileName))=0);
  315. End;
  316. function RenameFile (const OldName, NewName: RawByteString): boolean;
  317. var
  318. OldSystemFileName, NewSystemFileName: RawByteString;
  319. Begin
  320. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  321. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  322. Result:=(DosMove(PChar (OldSystemFileName), PChar (NewSystemFileName))=0);
  323. End;
  324. {****************************************************************************
  325. Disk Functions
  326. ****************************************************************************}
  327. function DiskFree (Drive: byte): int64;
  328. var FI: TFSinfo;
  329. RC: cardinal;
  330. begin
  331. {In OS/2, we use the filesystem information.}
  332. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  333. if RC = 0 then
  334. DiskFree := int64 (FI.Free_Clusters) *
  335. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  336. else
  337. DiskFree := -1;
  338. end;
  339. function DiskSize (Drive: byte): int64;
  340. var FI: TFSinfo;
  341. RC: cardinal;
  342. begin
  343. {In OS/2, we use the filesystem information.}
  344. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  345. if RC = 0 then
  346. DiskSize := int64 (FI.Total_Clusters) *
  347. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  348. else
  349. DiskSize := -1;
  350. end;
  351. function GetCurrentDir: string;
  352. begin
  353. GetDir (0, Result);
  354. end;
  355. function SetCurrentDir (const NewDir: string): boolean;
  356. var
  357. OrigInOutRes: word;
  358. begin
  359. OrigInOutRes := InOutRes;
  360. InOutRes := 0;
  361. {$I-}
  362. ChDir (NewDir);
  363. Result := InOutRes = 0;
  364. {$I+}
  365. InOutRes := OrigInOutRes;
  366. end;
  367. function CreateDir (const NewDir: string): boolean;
  368. var
  369. OrigInOutRes: word;
  370. begin
  371. OrigInOutRes := InOutRes;
  372. InOutRes := 0;
  373. {$I-}
  374. MkDir (NewDir);
  375. Result := InOutRes = 0;
  376. {$I+}
  377. InOutRes := OrigInOutRes;
  378. end;
  379. function RemoveDir (const Dir: string): boolean;
  380. var
  381. OrigInOutRes: word;
  382. begin
  383. OrigInOutRes := InOutRes;
  384. InOutRes := 0;
  385. {$I-}
  386. RmDir (Dir);
  387. Result := InOutRes = 0;
  388. {$I+}
  389. InOutRes := OrigInOutRes;
  390. end;
  391. function DirectoryExists (const Directory: RawByteString): boolean;
  392. var
  393. L: longint;
  394. begin
  395. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  396. if Directory = '' then
  397. Result := false
  398. else
  399. begin
  400. if ((Length (Directory) = 2) or
  401. (Length (Directory) = 3) and
  402. (Directory [3] in AllowDirectorySeparators)) and
  403. (Directory [2] in AllowDriveSeparators) and
  404. (UpCase (Directory [1]) in ['A'..'Z']) then
  405. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  406. L := FileGetAttr (Directory + '.')
  407. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  408. (Length (Directory) > 1) and
  409. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  410. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  411. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  412. else
  413. L := FileGetAttr (Directory);
  414. Result := (L > 0) and (L and faDirectory = faDirectory);
  415. end;
  416. end;
  417. {****************************************************************************
  418. Time Functions
  419. ****************************************************************************}
  420. procedure GetLocalTime (var SystemTime: TSystemTime);
  421. var
  422. DT: DosCalls.TDateTime;
  423. begin
  424. DosGetDateTime(DT);
  425. with SystemTime do
  426. begin
  427. Year:=DT.Year;
  428. Month:=DT.Month;
  429. Day:=DT.Day;
  430. Hour:=DT.Hour;
  431. Minute:=DT.Minute;
  432. Second:=DT.Second;
  433. MilliSecond:=DT.Sec100;
  434. end;
  435. end;
  436. {****************************************************************************
  437. Misc Functions
  438. ****************************************************************************}
  439. procedure sysbeep;
  440. begin
  441. // Maybe implement later on ?
  442. end;
  443. {****************************************************************************
  444. Locale Functions
  445. ****************************************************************************}
  446. procedure InitAnsi;
  447. var I: byte;
  448. Country: TCountryCode;
  449. begin
  450. for I := 0 to 255 do
  451. UpperCaseTable [I] := Chr (I);
  452. Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
  453. FillChar (Country, SizeOf (Country), 0);
  454. DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
  455. for I := 0 to 255 do
  456. if UpperCaseTable [I] <> Chr (I) then
  457. LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
  458. end;
  459. procedure InitInternational;
  460. var Country: TCountryCode;
  461. CtryInfo: TCountryInfo;
  462. Size: cardinal;
  463. RC: cardinal;
  464. begin
  465. Size := 0;
  466. FillChar (Country, SizeOf (Country), 0);
  467. FillChar (CtryInfo, SizeOf (CtryInfo), 0);
  468. RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
  469. if RC = 0 then
  470. begin
  471. DateSeparator := CtryInfo.DateSeparator;
  472. case CtryInfo.DateFormat of
  473. 1: begin
  474. ShortDateFormat := 'd/m/y';
  475. LongDateFormat := 'dd" "mmmm" "yyyy';
  476. end;
  477. 2: begin
  478. ShortDateFormat := 'y/m/d';
  479. LongDateFormat := 'yyyy" "mmmm" "dd';
  480. end;
  481. 3: begin
  482. ShortDateFormat := 'm/d/y';
  483. LongDateFormat := 'mmmm" "dd" "yyyy';
  484. end;
  485. end;
  486. TimeSeparator := CtryInfo.TimeSeparator;
  487. DecimalSeparator := CtryInfo.DecimalSeparator;
  488. ThousandSeparator := CtryInfo.ThousandSeparator;
  489. CurrencyFormat := CtryInfo.CurrencyFormat;
  490. CurrencyString := PChar (CtryInfo.CurrencyUnit);
  491. end;
  492. InitAnsi;
  493. InitInternationalGeneric;
  494. end;
  495. function SysErrorMessage(ErrorCode: Integer): String;
  496. begin
  497. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  498. end;
  499. {****************************************************************************
  500. OS Utils
  501. ****************************************************************************}
  502. function GetEnvPChar (EnvVar: shortstring): PChar;
  503. (* The assembler version is more than three times as fast as Pascal. *)
  504. var
  505. P: PChar;
  506. begin
  507. EnvVar := UpCase (EnvVar);
  508. {$ASMMODE INTEL}
  509. asm
  510. cld
  511. mov edi, Environment
  512. lea esi, EnvVar
  513. xor eax, eax
  514. lodsb
  515. @NewVar:
  516. cmp byte ptr [edi], 0
  517. jz @Stop
  518. push eax { eax contains length of searched variable name }
  519. push esi { esi points to the beginning of the variable name }
  520. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  521. mov edx, edi { pointer to beginning of variable name saved in edx }
  522. mov al, '=' { searching until '=' (end of variable name) }
  523. repne
  524. scasb { scan until '=' not found }
  525. neg ecx { what was the name length? }
  526. dec ecx { corrected }
  527. dec ecx { exclude the '=' character }
  528. pop esi { restore pointer to beginning of variable name }
  529. pop eax { restore length of searched variable name }
  530. push eax { and save both of them again for later use }
  531. push esi
  532. cmp ecx, eax { compare length of searched variable name with name }
  533. jnz @NotEqual { ... of currently found variable, jump if different }
  534. xchg edx, edi { pointer to current variable name restored in edi }
  535. repe
  536. cmpsb { compare till the end of variable name }
  537. xchg edx, edi { pointer to beginning of variable contents in edi }
  538. jz @Equal { finish if they're equal }
  539. @NotEqual:
  540. xor eax, eax { look for 00h }
  541. mov ecx, -1 { it _must_ be found }
  542. repne
  543. scasb { scan until found }
  544. pop esi { restore pointer to beginning of variable name }
  545. pop eax { restore length of searched variable name }
  546. jmp @NewVar { ... or continue with new variable otherwise }
  547. @Stop:
  548. xor eax, eax
  549. mov P, eax { Not found - return nil }
  550. jmp @End
  551. @Equal:
  552. pop esi { restore the stack position }
  553. pop eax
  554. mov P, edi { place pointer to variable contents in P }
  555. @End:
  556. end ['eax','ecx','edx','esi','edi'];
  557. GetEnvPChar := P;
  558. end;
  559. {$ASMMODE ATT}
  560. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  561. begin
  562. GetEnvironmentVariable := StrPas (GetEnvPChar (EnvVar));
  563. end;
  564. Function GetEnvironmentVariableCount : Integer;
  565. begin
  566. (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
  567. GetEnvironmentVariableCount := EnvC;
  568. end;
  569. Function GetEnvironmentString(Index : Integer) : String;
  570. begin
  571. Result:=FPCGetEnvStrFromP (EnvP, Index);
  572. end;
  573. procedure Sleep (Milliseconds: cardinal);
  574. begin
  575. DosSleep (Milliseconds);
  576. end;
  577. function SysTimerTick: QWord;
  578. var
  579. L: cardinal;
  580. begin
  581. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  582. SysTimerTick := L;
  583. end;
  584. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  585. integer;
  586. var
  587. E: EOSError;
  588. CommandLine: ansistring;
  589. Args0, Args: DosCalls.PByteArray;
  590. ObjNameBuf: PChar;
  591. ArgSize: word;
  592. Res: TResultCodes;
  593. ObjName: shortstring;
  594. RC: cardinal;
  595. ExecAppType: cardinal;
  596. const
  597. MaxArgsSize = 3072; (* Amount of memory reserved for arguments in bytes. *)
  598. ObjBufSize = 512;
  599. function StartSession: cardinal;
  600. var
  601. HQ: THandle;
  602. SPID, STID, QName: shortstring;
  603. SID, PID: cardinal;
  604. SD: TStartData;
  605. RD: TRequestData;
  606. PCI: PChildInfo;
  607. CISize: cardinal;
  608. Prio: byte;
  609. begin
  610. Result := $FFFFFFFF;
  611. FillChar (SD, SizeOf (SD), 0);
  612. SD.Length := SizeOf (SD);
  613. SD.Related := ssf_Related_Child;
  614. if FileExists (Path) then
  615. (* Full path necessary for starting different executable files from current *)
  616. (* directory. *)
  617. CommandLine := ExpandFileName (Path)
  618. else
  619. CommandLine := Path;
  620. SD.PgmName := PChar (CommandLine);
  621. if ComLine <> '' then
  622. SD.PgmInputs := PChar (ComLine);
  623. if ExecInheritsHandles in Flags then
  624. SD.InheritOpt := ssf_InhertOpt_Parent;
  625. Str (GetProcessID, SPID);
  626. Str (ThreadID, STID);
  627. QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
  628. SD.TermQ := @QName [1];
  629. SD.ObjectBuffer := ObjNameBuf;
  630. SD.ObjectBuffLen := ObjBufSize;
  631. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  632. if RC <> 0 then
  633. Move (QName [1], ObjNameBuf^, Length (QName))
  634. else
  635. begin
  636. RC := DosStartSession (SD, SID, PID);
  637. if (RC = 0) or (RC = 457) then
  638. begin
  639. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  640. if RC = 0 then
  641. begin
  642. Result := PCI^.Return;
  643. DosCloseQueue (HQ);
  644. DosFreeMem (PCI);
  645. FreeMem (ObjNameBuf, ObjBufSize);
  646. end
  647. else
  648. DosCloseQueue (HQ);
  649. end
  650. else
  651. DosCloseQueue (HQ);
  652. end;
  653. end;
  654. begin
  655. Result := integer ($FFFFFFFF);
  656. ObjName := '';
  657. GetMem (ObjNameBuf, ObjBufSize);
  658. FillChar (ObjNameBuf^, ObjBufSize, 0);
  659. if (DosQueryAppType (PChar (Path), ExecAppType) = 0) and
  660. (ApplicationType and 3 = ExecAppType and 3) then
  661. (* DosExecPgm should work... *)
  662. begin
  663. if ComLine = '' then
  664. begin
  665. Args0 := nil;
  666. Args := nil;
  667. end
  668. else
  669. begin
  670. GetMem (Args0, MaxArgsSize);
  671. Args := Args0;
  672. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  673. (* should not cross 64K boundary. *)
  674. if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
  675. Inc (pointer (Args), 1024);
  676. ArgSize := 0;
  677. Move (Path [1], Args^ [ArgSize], Length (Path));
  678. Inc (ArgSize, Length (Path));
  679. Args^ [ArgSize] := 0;
  680. Inc (ArgSize);
  681. {Now do the real arguments.}
  682. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  683. Inc (ArgSize, Length (ComLine));
  684. Args^ [ArgSize] := 0;
  685. Inc (ArgSize);
  686. Args^ [ArgSize] := 0;
  687. end;
  688. Res.ExitCode := $FFFFFFFF;
  689. RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res, PChar (Path));
  690. if Args0 <> nil then
  691. FreeMem (Args0, MaxArgsSize);
  692. if RC = 0 then
  693. begin
  694. Result := Res.ExitCode;
  695. FreeMem (ObjNameBuf, ObjBufSize);
  696. end
  697. else
  698. begin
  699. if (RC = 190) or (RC = 191) then
  700. Result := StartSession;
  701. end;
  702. end
  703. else
  704. Result := StartSession;
  705. if RC <> 0 then
  706. begin
  707. ObjName := StrPas (ObjNameBuf);
  708. FreeMem (ObjNameBuf, ObjBufSize);
  709. if ComLine = '' then
  710. CommandLine := Path
  711. else
  712. CommandLine := Path + ' ' + ComLine;
  713. if ObjName = '' then
  714. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
  715. else
  716. E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
  717. E.ErrorCode := Result;
  718. raise E;
  719. end;
  720. end;
  721. function ExecuteProcess (const Path: AnsiString;
  722. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  723. var
  724. CommandLine: AnsiString;
  725. I: integer;
  726. begin
  727. Commandline := '';
  728. for I := 0 to High (ComLine) do
  729. if Pos (' ', ComLine [I]) <> 0 then
  730. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  731. else
  732. CommandLine := CommandLine + ' ' + Comline [I];
  733. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  734. end;
  735. function GetTickCount: LongWord;
  736. var
  737. L: cardinal;
  738. begin
  739. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  740. GetTickCount := L;
  741. end;
  742. function GetTickCount64: QWord;
  743. var
  744. L: cardinal;
  745. begin
  746. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  747. GetTickCount64 := L;
  748. end;
  749. {****************************************************************************
  750. Initialization code
  751. ****************************************************************************}
  752. Initialization
  753. InitExceptions; { Initialize exceptions. OS independent }
  754. InitInternational; { Initialize internationalization settings }
  755. OnBeep:=@SysBeep;
  756. Finalization
  757. DoneExceptions;
  758. end.