sysutils.pp 26 KB

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