sysutils.pp 26 KB

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