sysutils.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  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. RC := DosQueryPathInfo (PChar (SystemFileName), ilStandard, FS, SizeOf (FS^));
  377. if RC = 0 then
  378. begin
  379. FS^.AttrFile:=Attr;
  380. RC := DosSetPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^), 0);
  381. if RC <> 0 then
  382. OSErrorWatch (RC);
  383. end
  384. else
  385. OSErrorWatch (RC);
  386. Result := - longint (RC);
  387. Dispose(FS);
  388. end;
  389. function DeleteFile (const FileName: RawByteString): boolean;
  390. var
  391. SystemFileName: RawByteString;
  392. RC: cardinal;
  393. Begin
  394. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  395. RC := DosDelete (PChar (SystemFileName));
  396. if RC <> 0 then
  397. begin
  398. Result := false;
  399. OSErrorWatch (RC);
  400. end
  401. else
  402. Result := true;
  403. End;
  404. function RenameFile (const OldName, NewName: RawByteString): boolean;
  405. var
  406. OldSystemFileName, NewSystemFileName: RawByteString;
  407. RC: cardinal;
  408. Begin
  409. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  410. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  411. RC := DosMove (PChar (OldSystemFileName), PChar (NewSystemFileName));
  412. if RC <> 0 then
  413. begin
  414. Result := false;
  415. OSErrorWatch (RC);
  416. end
  417. else
  418. Result := true;
  419. End;
  420. {****************************************************************************
  421. Disk Functions
  422. ****************************************************************************}
  423. function DiskFree (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. DiskFree := int64 (FI.Free_Clusters) *
  431. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  432. else
  433. begin
  434. DiskFree := -1;
  435. OSErrorWatch (RC);
  436. end;
  437. end;
  438. function DiskSize (Drive: byte): int64;
  439. var FI: TFSinfo;
  440. RC: cardinal;
  441. begin
  442. {In OS/2, we use the filesystem information.}
  443. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  444. if RC = 0 then
  445. DiskSize := int64 (FI.Total_Clusters) *
  446. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  447. else
  448. begin
  449. DiskSize := -1;
  450. OSErrorWatch (RC);
  451. end;
  452. end;
  453. function DirectoryExists (const Directory: RawByteString): boolean;
  454. var
  455. L: longint;
  456. begin
  457. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  458. if Directory = '' then
  459. Result := false
  460. else
  461. begin
  462. if ((Length (Directory) = 2) or
  463. (Length (Directory) = 3) and
  464. (Directory [3] in AllowDirectorySeparators)) and
  465. (Directory [2] in AllowDriveSeparators) and
  466. (UpCase (Directory [1]) in ['A'..'Z']) then
  467. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  468. L := FileGetAttr (Directory + '.')
  469. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  470. (Length (Directory) > 1) and
  471. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  472. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  473. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  474. else
  475. L := FileGetAttr (Directory);
  476. Result := (L > 0) and (L and faDirectory = faDirectory);
  477. end;
  478. end;
  479. {****************************************************************************
  480. Time Functions
  481. ****************************************************************************}
  482. procedure GetLocalTime (var SystemTime: TSystemTime);
  483. var
  484. DT: DosCalls.TDateTime;
  485. begin
  486. DosGetDateTime(DT);
  487. with SystemTime do
  488. begin
  489. Year:=DT.Year;
  490. Month:=DT.Month;
  491. Day:=DT.Day;
  492. Hour:=DT.Hour;
  493. Minute:=DT.Minute;
  494. Second:=DT.Second;
  495. MilliSecond:=DT.Sec100;
  496. end;
  497. end;
  498. {****************************************************************************
  499. Misc Functions
  500. ****************************************************************************}
  501. procedure sysbeep;
  502. begin
  503. DosBeep (800, 250);
  504. end;
  505. {****************************************************************************
  506. Locale Functions
  507. ****************************************************************************}
  508. var
  509. Country: TCountryCode;
  510. CtryInfo: TCountryInfo;
  511. procedure InitAnsi;
  512. var
  513. I: byte;
  514. RC: cardinal;
  515. begin
  516. for I := 0 to 255 do
  517. UpperCaseTable [I] := Chr (I);
  518. Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
  519. FillChar (Country, SizeOf (Country), 0);
  520. DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
  521. for I := 0 to 255 do
  522. if UpperCaseTable [I] <> Chr (I) then
  523. LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
  524. end;
  525. procedure InitInternational;
  526. var
  527. Size: cardinal;
  528. RC: cardinal;
  529. begin
  530. Size := 0;
  531. FillChar (Country, SizeOf (Country), 0);
  532. FillChar (CtryInfo, SizeOf (CtryInfo), 0);
  533. RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
  534. if RC = 0 then
  535. begin
  536. DateSeparator := CtryInfo.DateSeparator;
  537. case CtryInfo.DateFormat of
  538. 1: begin
  539. ShortDateFormat := 'd/m/y';
  540. LongDateFormat := 'dd" "mmmm" "yyyy';
  541. end;
  542. 2: begin
  543. ShortDateFormat := 'y/m/d';
  544. LongDateFormat := 'yyyy" "mmmm" "dd';
  545. end;
  546. 3: begin
  547. ShortDateFormat := 'm/d/y';
  548. LongDateFormat := 'mmmm" "dd" "yyyy';
  549. end;
  550. end;
  551. TimeSeparator := CtryInfo.TimeSeparator;
  552. DecimalSeparator := CtryInfo.DecimalSeparator;
  553. ThousandSeparator := CtryInfo.ThousandSeparator;
  554. CurrencyFormat := CtryInfo.CurrencyFormat;
  555. CurrencyString := PChar (CtryInfo.CurrencyUnit);
  556. end
  557. else
  558. OSErrorWatch (RC);
  559. InitAnsi;
  560. InitInternationalGeneric;
  561. end;
  562. function SysErrorMessage(ErrorCode: Integer): String;
  563. const
  564. SysMsgFile: array [0..10] of char = 'OSO001.MSG'#0;
  565. var
  566. OutBuf: array [0..999] of char;
  567. RetMsgSize: cardinal;
  568. RC: cardinal;
  569. begin
  570. RC := DosGetMessage (nil, 0, @OutBuf [0], SizeOf (OutBuf),
  571. ErrorCode, @SysMsgFile [0], RetMsgSize);
  572. if RC = 0 then
  573. begin
  574. SetLength (Result, RetMsgSize);
  575. Move (OutBuf [0], Result [1], RetMsgSize);
  576. end
  577. else
  578. begin
  579. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  580. OSErrorWatch (RC);
  581. end;
  582. end;
  583. {****************************************************************************
  584. OS Utils
  585. ****************************************************************************}
  586. function GetEnvPChar (EnvVar: shortstring): PChar;
  587. (* The assembler version is more than three times as fast as Pascal. *)
  588. var
  589. P: PChar;
  590. begin
  591. EnvVar := UpCase (EnvVar);
  592. {$ASMMODE INTEL}
  593. asm
  594. cld
  595. mov edi, Environment
  596. lea esi, EnvVar
  597. xor eax, eax
  598. lodsb
  599. @NewVar:
  600. cmp byte ptr [edi], 0
  601. jz @Stop
  602. push eax { eax contains length of searched variable name }
  603. push esi { esi points to the beginning of the variable name }
  604. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  605. mov edx, edi { pointer to beginning of variable name saved in edx }
  606. mov al, '=' { searching until '=' (end of variable name) }
  607. repne
  608. scasb { scan until '=' not found }
  609. neg ecx { what was the name length? }
  610. dec ecx { corrected }
  611. dec ecx { exclude the '=' character }
  612. pop esi { restore pointer to beginning of variable name }
  613. pop eax { restore length of searched variable name }
  614. push eax { and save both of them again for later use }
  615. push esi
  616. cmp ecx, eax { compare length of searched variable name with name }
  617. jnz @NotEqual { ... of currently found variable, jump if different }
  618. xchg edx, edi { pointer to current variable name restored in edi }
  619. repe
  620. cmpsb { compare till the end of variable name }
  621. xchg edx, edi { pointer to beginning of variable contents in edi }
  622. jz @Equal { finish if they're equal }
  623. @NotEqual:
  624. xor eax, eax { look for 00h }
  625. mov ecx, -1 { it _must_ be found }
  626. repne
  627. scasb { scan until found }
  628. pop esi { restore pointer to beginning of variable name }
  629. pop eax { restore length of searched variable name }
  630. jmp @NewVar { ... or continue with new variable otherwise }
  631. @Stop:
  632. xor eax, eax
  633. mov P, eax { Not found - return nil }
  634. jmp @End
  635. @Equal:
  636. pop esi { restore the stack position }
  637. pop eax
  638. mov P, edi { place pointer to variable contents in P }
  639. @End:
  640. end ['eax','ecx','edx','esi','edi'];
  641. GetEnvPChar := P;
  642. end;
  643. {$ASMMODE ATT}
  644. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  645. begin
  646. GetEnvironmentVariable := GetEnvPChar (EnvVar);
  647. end;
  648. Function GetEnvironmentVariableCount : Integer;
  649. begin
  650. (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
  651. GetEnvironmentVariableCount := EnvC;
  652. end;
  653. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  654. begin
  655. Result:=FPCGetEnvStrFromP (EnvP, Index);
  656. end;
  657. procedure Sleep (Milliseconds: cardinal);
  658. begin
  659. DosSleep (Milliseconds);
  660. end;
  661. function SysTimerTick: QWord;
  662. var
  663. L: cardinal;
  664. begin
  665. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  666. SysTimerTick := L;
  667. end;
  668. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  669. integer;
  670. var
  671. E: EOSError;
  672. CommandLine: ansistring;
  673. Args0, Args: DosCalls.PByteArray;
  674. ObjNameBuf: PChar;
  675. ArgSize: word;
  676. Res: TResultCodes;
  677. ObjName: shortstring;
  678. RC: cardinal;
  679. ExecAppType: cardinal;
  680. MaxArgsSize: PtrUInt; (* Amount of memory reserved for arguments in bytes. *)
  681. MaxArgsSizeInc: word;
  682. const
  683. ObjBufSize = 512;
  684. function StartSession: cardinal;
  685. var
  686. HQ: THandle;
  687. SPID, STID, QName: shortstring;
  688. SID, PID: cardinal;
  689. SD: TStartData;
  690. RD: TRequestData;
  691. PCI: PChildInfo;
  692. CISize: cardinal;
  693. Prio: byte;
  694. begin
  695. Result := $FFFFFFFF;
  696. FillChar (SD, SizeOf (SD), 0);
  697. SD.Length := SizeOf (SD);
  698. SD.Related := ssf_Related_Child;
  699. if FileExists (Path) then
  700. (* Full path necessary for starting different executable files from current *)
  701. (* directory. *)
  702. CommandLine := ExpandFileName (Path)
  703. else
  704. CommandLine := Path;
  705. SD.PgmName := PChar (CommandLine);
  706. if ComLine <> '' then
  707. SD.PgmInputs := PChar (ComLine);
  708. if ExecInheritsHandles in Flags then
  709. SD.InheritOpt := ssf_InhertOpt_Parent;
  710. Str (GetProcessID, SPID);
  711. Str (ThreadID, STID);
  712. QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
  713. SD.TermQ := @QName [1];
  714. SD.ObjectBuffer := ObjNameBuf;
  715. SD.ObjectBuffLen := ObjBufSize;
  716. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  717. if RC <> 0 then
  718. begin
  719. Move (QName [1], ObjNameBuf^, Length (QName));
  720. OSErrorWatch (RC);
  721. end
  722. else
  723. begin
  724. RC := DosStartSession (SD, SID, PID);
  725. if (RC = 0) or (RC = 457) then
  726. begin
  727. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  728. if RC = 0 then
  729. begin
  730. Result := PCI^.Return;
  731. RC := DosCloseQueue (HQ);
  732. if RC <> 0 then
  733. OSErrorWatch (RC);
  734. RC := DosFreeMem (PCI);
  735. if RC <> 0 then
  736. OSErrorWatch (RC);
  737. FreeMem (ObjNameBuf, ObjBufSize);
  738. end
  739. else
  740. begin
  741. OSErrorWatch (RC);
  742. RC := DosCloseQueue (HQ);
  743. OSErrorWatch (RC);
  744. end;
  745. end
  746. else
  747. begin
  748. OSErrorWatch (RC);
  749. RC := DosCloseQueue (HQ);
  750. if RC <> 0 then
  751. OSErrorWatch (RC);
  752. end;
  753. end;
  754. end;
  755. begin
  756. Result := integer ($FFFFFFFF);
  757. ObjName := '';
  758. GetMem (ObjNameBuf, ObjBufSize);
  759. FillChar (ObjNameBuf^, ObjBufSize, 0);
  760. RC := DosQueryAppType (PChar (Path), ExecAppType);
  761. if RC <> 0 then
  762. begin
  763. OSErrorWatch (RC);
  764. if (RC = 190) or (RC = 191) then
  765. Result := StartSession;
  766. end
  767. else
  768. begin
  769. if (ApplicationType and 3 = ExecAppType and 3) then
  770. (* DosExecPgm should work... *)
  771. begin
  772. MaxArgsSize := Length (ComLine) + Length (Path) + 256; (* More than enough *)
  773. if MaxArgsSize > high (word) then
  774. Exit;
  775. if ComLine = '' then
  776. begin
  777. Args0 := nil;
  778. Args := nil;
  779. end
  780. else
  781. begin
  782. GetMem (Args0, MaxArgsSize);
  783. Args := Args0;
  784. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  785. (* should not cross 64K boundary. *)
  786. while ((PtrUInt (Args) + MaxArgsSize) and $FFFF) < MaxArgsSize do
  787. begin
  788. MaxArgsSizeInc := MaxArgsSize -
  789. ((PtrUInt (Args) + MaxArgsSize) and $FFFF);
  790. Inc (MaxArgsSize, MaxArgsSizeInc);
  791. if MaxArgsSize > high (word) then
  792. Exit;
  793. ReallocMem (Args0, MaxArgsSize);
  794. Inc (pointer (Args), MaxArgsSizeInc);
  795. end;
  796. ArgSize := 0;
  797. Move (Path [1], Args^ [ArgSize], Length (Path));
  798. Inc (ArgSize, Length (Path));
  799. Args^ [ArgSize] := 0;
  800. Inc (ArgSize);
  801. {Now do the real arguments.}
  802. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  803. Inc (ArgSize, Length (ComLine));
  804. Args^ [ArgSize] := 0;
  805. Inc (ArgSize);
  806. Args^ [ArgSize] := 0;
  807. end;
  808. Res.ExitCode := $FFFFFFFF;
  809. RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res,
  810. PChar (Path));
  811. if RC <> 0 then
  812. OSErrorWatch (RC);
  813. if Args0 <> nil then
  814. FreeMem (Args0, MaxArgsSize);
  815. if RC = 0 then
  816. begin
  817. Result := Res.ExitCode;
  818. FreeMem (ObjNameBuf, ObjBufSize);
  819. end
  820. end
  821. end;
  822. if RC <> 0 then
  823. begin
  824. ObjName := StrPas (ObjNameBuf);
  825. FreeMem (ObjNameBuf, ObjBufSize);
  826. if ComLine = '' then
  827. CommandLine := Path
  828. else
  829. CommandLine := Path + ' ' + ComLine;
  830. if ObjName = '' then
  831. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
  832. else
  833. E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
  834. E.ErrorCode := Result;
  835. raise E;
  836. end;
  837. end;
  838. function ExecuteProcess (const Path: AnsiString;
  839. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  840. var
  841. CommandLine: AnsiString;
  842. I: integer;
  843. begin
  844. Commandline := '';
  845. for I := 0 to High (ComLine) do
  846. if Pos (' ', ComLine [I]) <> 0 then
  847. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  848. else
  849. CommandLine := CommandLine + ' ' + Comline [I];
  850. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  851. end;
  852. function GetTickCount: LongWord;
  853. var
  854. L: cardinal;
  855. begin
  856. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  857. GetTickCount := L;
  858. end;
  859. function GetTickCount64: QWord;
  860. var
  861. Freq2: cardinal;
  862. T: QWord;
  863. begin
  864. DosTmrQueryFreq (Freq2);
  865. DosTmrQueryTime (T);
  866. GetTickCount64 := T div (QWord (Freq2) div 1000);
  867. {$NOTE GetTickCount64 takes 20 microseconds on 1GHz CPU, GetTickCount not measurable}
  868. end;
  869. const
  870. OrigOSErrorWatch: TOSErrorWatch = nil;
  871. procedure TrackLastOSError (Error: cardinal);
  872. begin
  873. LastOSError := Error;
  874. OrigOSErrorWatch (Error);
  875. end;
  876. function GetLastOSError: Integer;
  877. begin
  878. GetLastOSError := Integer (LastOSError);
  879. end;
  880. {****************************************************************************
  881. Initialization code
  882. ****************************************************************************}
  883. Initialization
  884. InitExceptions; { Initialize exceptions. OS independent }
  885. InitInternational; { Initialize internationalization settings }
  886. OnBeep:=@SysBeep;
  887. LastOSError := 0;
  888. OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
  889. Finalization
  890. DoneExceptions;
  891. end.