sysutils.pp 26 KB

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