sysutils.pp 25 KB

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