2
0

sysutils.pp 26 KB

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