sysutils.pp 26 KB

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