dos.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. {****************************************************************************
  2. Free Pascal Runtime-Library
  3. DOS unit for OS/2
  4. Copyright (c) 1997,1999-2000 by Daniel Mantione,
  5. member of the Free Pascal development team
  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 dos;
  13. {$ASMMODE ATT}
  14. {***************************************************************************}
  15. interface
  16. {***************************************************************************}
  17. {$PACKRECORDS 1}
  18. uses Strings, DosCalls;
  19. Type
  20. {Search record which is used by findfirst and findnext:}
  21. SearchRec = record
  22. case boolean of
  23. false: (Handle: THandle; {Used in os_OS2 mode}
  24. FStat: PFileFindBuf3;
  25. Fill: array [1..21 - SizeOf (THandle) - SizeOf (pointer)]
  26. of byte;
  27. Attr: byte;
  28. Time: longint;
  29. Size: longint;
  30. Name: string); {Filenames can be long in OS/2!}
  31. true: (Fill2: array [1..21] of byte;
  32. Attr2: byte;
  33. Time2: longint;
  34. Size2: longint;
  35. Name2: string); {Filenames can be long in OS/2!}
  36. end;
  37. {Flags for the exec procedure:
  38. }
  39. threadvar
  40. (* For compatibility with VP/2, used for runflags in Exec procedure. *)
  41. ExecFlags: cardinal;
  42. (* Note that the TP/BP compatible method for retrieval of exit codes *)
  43. (* is limited to only one (the last) execution! Including the following *)
  44. (* two variables in the interface part allows querying the status of *)
  45. (* of asynchronously started programs using DosWaitChild with dtNoWait *)
  46. (* parameter, i.e. without waiting for the final program result (as *)
  47. (* opposed to calling DosExitCode which would wait for the exit code). *)
  48. LastExecRes: TResultCodes;
  49. LastExecFlags: cardinal;
  50. {$i dosh.inc}
  51. {OS/2 specific functions}
  52. function GetEnvPChar (EnvVar: string): PChar;
  53. function DosErrorModuleName: string;
  54. (* In case of an error in Dos.Exec returns the name of the module *)
  55. (* causing the problem - e.g. name of a missing or corrupted DLL. *)
  56. (* It may also contain a queue name in case of a failed attempt *)
  57. (* to create queue for reading results of started sessions. *)
  58. implementation
  59. {$DEFINE HAS_GETMSCOUNT}
  60. {$DEFINE HAS_DOSEXITCODE}
  61. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  62. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  63. {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
  64. {$I dos.inc}
  65. threadvar
  66. LastDosErrorModuleName: string;
  67. const FindResvdMask = $00003737; {Allowed bits in attribute
  68. specification for DosFindFirst call.}
  69. function GetMsCount: int64;
  70. var
  71. L: cardinal;
  72. begin
  73. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  74. GetMsCount := L;
  75. end;
  76. function fsearch(path:pathstr;dirlist:string):pathstr;
  77. Var
  78. A: array [0..255] of char;
  79. D, P: AnsiString;
  80. begin
  81. P:=Path;
  82. D:=DirList;
  83. DosError := DosSearchPath (dsIgnoreNetErrs, PChar(D), PChar(P), @A, 255);
  84. if DosError <> 0 then
  85. OSErrorWatch (DosError);
  86. fsearch := StrPas (@A);
  87. end;
  88. procedure getftime(var f;var time:longint);
  89. var
  90. FStat: TFileStatus3;
  91. begin
  92. DosError := DosQueryFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  93. SizeOf (FStat));
  94. if DosError=0 then
  95. begin
  96. Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
  97. if Time = 0 then
  98. Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
  99. end
  100. else
  101. begin
  102. Time:=0;
  103. OSErrorWatch (DosError);
  104. if DosError = 87 then
  105. DosError := 6; (* Align to TP/BP behaviour *)
  106. end;
  107. end;
  108. procedure SetFTime (var F; Time: longint);
  109. var FStat: TFileStatus3;
  110. RC: cardinal;
  111. begin
  112. RC := DosQueryFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  113. SizeOf (FStat));
  114. if RC = 0 then
  115. begin
  116. FStat.DateLastAccess := Hi (Time);
  117. FStat.DateLastWrite := Hi (Time);
  118. FStat.TimeLastAccess := Lo (Time);
  119. FStat.TimeLastWrite := Lo (Time);
  120. RC := DosSetFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  121. SizeOf (FStat));
  122. if RC <> 0 then
  123. OSErrorWatch (RC);
  124. end
  125. else
  126. begin
  127. OSErrorWatch (RC);
  128. if RC = 87 then
  129. RC := 6;
  130. end;
  131. DosError := integer (RC);
  132. end;
  133. function DosExitCode: word;
  134. var
  135. Res: TResultCodes;
  136. PPID: cardinal;
  137. RC: cardinal;
  138. begin
  139. if (LastExecFlags = deAsyncResult) or (LastExecFlags = deAsyncResultDb) then
  140. begin
  141. RC := DosWaitChild (DCWA_PROCESS, dtWait, Res, PPID, LastExecRes.PID);
  142. if RC = 0 then
  143. (* If we succeeded, the process is finished - possible future querying
  144. of DosExitCode shall return the result immediately as with synchronous
  145. execution. *)
  146. begin
  147. LastExecFlags := deSync;
  148. LastExecRes := Res;
  149. end
  150. else
  151. begin
  152. LastExecRes.ExitCode := RC shl 16;
  153. OSErrorWatch (RC);
  154. end;
  155. end;
  156. if LastExecRes.ExitCode > high (word) then
  157. DosExitCode := high (word)
  158. else
  159. DosExitCode := LastExecRes.ExitCode and $FFFF;
  160. end;
  161. procedure Exec (const Path: PathStr; const ComLine: ComStr);
  162. {Execute a program.}
  163. var
  164. Args0, Args: PByteArray;
  165. ArgSize: word;
  166. ObjName: string;
  167. Res: TResultCodes;
  168. RC, RC2: cardinal;
  169. ExecAppType: cardinal;
  170. HQ: THandle;
  171. SPID, STID, QName: string;
  172. SID, PID: cardinal;
  173. SD: TStartData;
  174. RD: TRequestData;
  175. PCI: PChildInfo;
  176. CISize: cardinal;
  177. Prio: byte;
  178. DSS: boolean;
  179. SR: SearchRec;
  180. MaxArgsSize: PtrUInt; (* Amount of memory reserved for arguments in bytes. *)
  181. MaxArgsSizeInc: word;
  182. PathZ: array [0..255] of char;
  183. begin
  184. { LastDosExitCode := Exec (Path, ExecRunFlags (ExecFlags), efDefault, ComLine);}
  185. ObjName := '';
  186. (* FExpand should be used only for the DosStartSession part
  187. and only if the executable is in the current directory. *)
  188. FindFirst (Path, AnyFile, SR);
  189. if DosError = 0 then
  190. QName := FExpand (Path)
  191. else
  192. QName := Path;
  193. FindClose (SR);
  194. MaxArgsSize := Length (ComLine) + Length (QName) + 256; (* More than enough *)
  195. if MaxArgsSize > high (word) then
  196. begin
  197. DosError := 8; (* Not quite, but "not enough memory" is close enough *)
  198. Exit;
  199. end;
  200. if ComLine = '' then
  201. begin
  202. Args0 := nil;
  203. Args := nil;
  204. StrPCopy (PathZ, Path);
  205. RC := DosQueryAppType (@PathZ [0], ExecAppType);
  206. end
  207. else
  208. begin
  209. GetMem (Args0, MaxArgsSize);
  210. Args := Args0;
  211. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  212. (* should not cross a 64K boundary. *)
  213. while ((PtrUInt (Args) + MaxArgsSize) and $FFFF) < MaxArgsSize do
  214. begin
  215. MaxArgsSizeInc := MaxArgsSize -
  216. ((PtrUInt (Args) + MaxArgsSize) and $FFFF);
  217. Inc (MaxArgsSize, MaxArgsSizeInc);
  218. if MaxArgsSize > high (word) then
  219. begin
  220. DosError := 8; (* Not quite, but "not enough memory" is close enough *)
  221. Exit;
  222. end;
  223. ReallocMem (Args0, MaxArgsSize);
  224. Inc (pointer (Args), MaxArgsSizeInc);
  225. end;
  226. ArgSize := 0;
  227. Move (QName [1], Args^ [ArgSize], Length (QName));
  228. Inc (ArgSize, Length (QName));
  229. Args^ [ArgSize] := 0;
  230. Inc (ArgSize);
  231. {Now do the real arguments.}
  232. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  233. Inc (ArgSize, Length (ComLine));
  234. Args^ [ArgSize] := 0;
  235. Inc (ArgSize);
  236. Args^ [ArgSize] := 0;
  237. RC := DosQueryAppType (PChar (Args), ExecAppType);
  238. end;
  239. if RC <> 0 then
  240. OSErrorWatch (RC)
  241. else
  242. if (ApplicationType and 3 = ExecAppType and 3) then
  243. (* DosExecPgm should work... *)
  244. begin
  245. DSS := false;
  246. Res.ExitCode := $FFFFFFFF;
  247. RC := DosExecPgm (ObjName, cardinal (ExecFlags), Args, nil, Res, Path);
  248. if RC = 0 then
  249. begin
  250. LastExecFlags := ExecFlags;
  251. LastExecRes := Res;
  252. LastDosErrorModuleName := '';
  253. end
  254. else
  255. begin
  256. if (RC = 190) or (RC = 191) then
  257. DSS := true;
  258. OSErrorWatch (RC);
  259. end;
  260. end
  261. else
  262. DSS := true;
  263. if DSS then
  264. begin
  265. Str (GetProcessID, SPID);
  266. Str (ThreadID, STID);
  267. QName := '\QUEUES\FPC_Dos_Exec_p' + SPID + 't' + STID + '.QUE'#0;
  268. FillChar (SD, SizeOf (SD), 0);
  269. SD.Length := SizeOf (SD);
  270. RC := 0;
  271. case ExecFlags of
  272. deSync:
  273. begin
  274. SD.Related := ssf_Related_Child;
  275. LastExecFlags := ExecFlags;
  276. SD.TermQ := @QName [1];
  277. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  278. if RC <> 0 then
  279. OSErrorWatch (RC);
  280. end;
  281. deAsync,
  282. deAsyncResult:
  283. begin
  284. (* Current implementation of DosExitCode does not support retrieval *)
  285. (* of result codes for other session types started asynchronously. *)
  286. LastExecFlags := deAsync;
  287. SD.Related := ssf_Related_Independent;
  288. end;
  289. deBackground:
  290. begin
  291. (* Current implementation of DosExitCode does not support retrieval *)
  292. (* of result codes for other session types started asynchronously. *)
  293. LastExecFlags := ExecFlags;
  294. SD.Related := ssf_Related_Independent;
  295. SD.FgBg := ssf_FgBg_Back;
  296. end;
  297. deAsyncResultDB:
  298. begin
  299. (* Current implementation of DosExitCode does not support retrieval *)
  300. (* of result codes for other session types started asynchronously. *)
  301. LastExecFlags := ExecFlags;
  302. SD.Related := ssf_Related_Child;
  303. SD.TraceOpt := ssf_TraceOpt_Trace;
  304. end;
  305. end;
  306. if RC <> 0 then
  307. ObjName := Copy (QName, 1, Pred (Length (QName)))
  308. else
  309. begin
  310. if Args = nil then
  311. (* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *)
  312. begin
  313. GetMem (Args0, MaxArgsSize);
  314. Args := Args0;
  315. Move (QName [1], Args^ [0], Length (QName));
  316. Args^ [Length (QName)] := 0;
  317. end
  318. else
  319. SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]);
  320. SD.PgmName := PChar (Args);
  321. SD.InheritOpt := ssf_InhertOpt_Parent;
  322. SD.ObjectBuffer := @ObjName [1];
  323. SD.ObjectBuffLen := SizeOf (ObjName) - 1;
  324. RC := DosStartSession (SD, SID, PID);
  325. if RC <> 0 then
  326. OSErrorWatch (RC);
  327. if (RC = 0) or (RC = 457) then
  328. begin
  329. LastExecRes.PID := PID;
  330. if ExecFlags = deSync then
  331. begin
  332. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  333. if RC <> 0 then
  334. OSErrorWatch (RC);
  335. if (RC = 0) and (PCI^.SessionID = SID) then
  336. begin
  337. LastExecRes.ExitCode := PCI^.Return;
  338. RC2 := DosCloseQueue (HQ);
  339. if RC2 <> 0 then
  340. OSErrorWatch (RC2);
  341. RC2 := DosFreeMem (PCI);
  342. if RC2 <> 0 then
  343. OSErrorWatch (RC2);
  344. end
  345. else
  346. begin
  347. RC2 := DosCloseQueue (HQ);
  348. if RC2 <> 0 then
  349. OSErrorWatch (RC2);
  350. end;
  351. end;
  352. end
  353. else if ExecFlags = deSync then
  354. begin
  355. RC2 := DosCloseQueue (HQ);
  356. if RC2 <> 0 then
  357. OSErrorWatch (RC2);
  358. end;
  359. end;
  360. end;
  361. if RC <> 0 then
  362. begin
  363. LastDosErrorModuleName := ObjName;
  364. LastExecFlags := deSync;
  365. LastExecRes.ExitCode := 0; (* Needed for TP/BP compatibility *)
  366. LastExecRes.TerminateReason := $FFFFFFFF;
  367. end;
  368. DosError := RC;
  369. if Args0 <> nil then
  370. FreeMem (Args0, MaxArgsSize);
  371. end;
  372. function DosErrorModuleName: string;
  373. begin
  374. DosErrorModuleName := LastDosErrorModuleName;
  375. end;
  376. function dosversion:word;
  377. {Returns OS/2 version}
  378. var
  379. Minor, Major: Cardinal;
  380. begin
  381. DosQuerySysInfo(svMajorVersion, svMajorVersion, Major, 4);
  382. DosQuerySysInfo(svMinorVersion, svMinorVersion, Minor, 4);
  383. DosVersion:=Major or Minor shl 8;
  384. end;
  385. procedure GetDate (var Year, Month, MDay, WDay: word);
  386. Var
  387. dt: TDateTime;
  388. begin
  389. DosGetDateTime(dt);
  390. Year:=dt.year;
  391. Month:=dt.month;
  392. MDay:=dt.Day;
  393. WDay:=dt.Weekday;
  394. end;
  395. procedure SetDate (Year, Month, Day: word);
  396. var
  397. DT: TDateTime;
  398. RC: cardinal;
  399. begin
  400. DosGetDateTime (DT);
  401. DT.Year := Year;
  402. DT.Month := byte (Month);
  403. DT.Day := byte (Day);
  404. RC := DosSetDateTime (DT);
  405. if RC <> 0 then
  406. OSErrorWatch (RC);
  407. end;
  408. procedure GetTime (var Hour, Minute, Second, Sec100: word);
  409. var
  410. dt: TDateTime;
  411. begin
  412. DosGetDateTime(dt);
  413. Hour:=dt.Hour;
  414. Minute:=dt.Minute;
  415. Second:=dt.Second;
  416. Sec100:=dt.Hundredths;
  417. end;
  418. procedure SetTime (Hour, Minute, Second, Sec100: word);
  419. var
  420. DT: TDateTime;
  421. RC: cardinal;
  422. begin
  423. DosGetDateTime (DT);
  424. DT.Hour := byte (Hour);
  425. DT.Minute := byte (Minute);
  426. DT.Second := byte (Second);
  427. DT.Sec100 := byte (Sec100);
  428. RC := DosSetDateTime (DT);
  429. if RC <> 0 then
  430. OSErrorWatch (RC);
  431. end;
  432. function DiskFree (Drive: byte): int64;
  433. var FI: TFSinfo;
  434. RC: cardinal;
  435. begin
  436. {In OS/2, we use the filesystem information.}
  437. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  438. if RC = 0 then
  439. DiskFree := int64 (FI.Free_Clusters) *
  440. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  441. else
  442. begin
  443. DiskFree := -1;
  444. OSErrorWatch (RC);
  445. end;
  446. end;
  447. function DiskSize (Drive: byte): int64;
  448. var FI: TFSinfo;
  449. RC: cardinal;
  450. begin
  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. procedure DosSearchRec2SearchRec (var F: SearchRec);
  462. type
  463. TRec = record
  464. T, D: word;
  465. end;
  466. begin
  467. with F do
  468. begin
  469. Name := FStat^.Name;
  470. Size := FStat^.FileSize;
  471. Attr := byte(FStat^.AttrFile and $FF);
  472. TRec (Time).T := FStat^.TimeLastWrite;
  473. TRec (Time).D := FStat^.DateLastWrite;
  474. end;
  475. end;
  476. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  477. var Count: cardinal;
  478. begin
  479. {No error.}
  480. DosError := 0;
  481. New (F.FStat);
  482. F.Handle := THandle ($FFFFFFFF);
  483. Count := 1;
  484. DosError := integer (DosFindFirst (Path, F.Handle,
  485. Attr and FindResvdMask, F.FStat, SizeOf (F.FStat^),
  486. Count, ilStandard));
  487. if DosError <> 0 then
  488. OSErrorWatch (DosError)
  489. else if Count = 0 then
  490. DosError := 18;
  491. DosSearchRec2SearchRec (F);
  492. end;
  493. procedure FindNext (var F: SearchRec);
  494. var
  495. Count: cardinal;
  496. begin
  497. {No error}
  498. DosError := 0;
  499. Count := 1;
  500. DosError := integer (DosFindNext (F.Handle, F.FStat, SizeOf (F.FStat^),
  501. Count));
  502. if DosError <> 0 then
  503. OSErrorWatch (DosError)
  504. else if Count = 0 then
  505. DosError := 18;
  506. DosSearchRec2SearchRec (F);
  507. end;
  508. procedure FindClose (var F: SearchRec);
  509. begin
  510. if F.Handle <> THandle ($FFFFFFFF) then
  511. begin
  512. DosError := integer (DosFindClose (F.Handle));
  513. if DosError <> 0 then
  514. OSErrorWatch (DosError);
  515. end;
  516. Dispose (F.FStat);
  517. end;
  518. function envcount:longint;
  519. begin
  520. envcount:=envc;
  521. end;
  522. function envstr (index : longint) : string;
  523. var hp:Pchar;
  524. begin
  525. if (index<=0) or (index>envcount) then
  526. begin
  527. envstr:='';
  528. exit;
  529. end;
  530. hp:=EnvP[index-1];
  531. envstr:=strpas(hp);
  532. end;
  533. function GetEnvPChar (EnvVar: string): PChar;
  534. (* The assembler version is more than three times as fast as Pascal. *)
  535. var
  536. P: PChar;
  537. begin
  538. EnvVar := UpCase (EnvVar);
  539. {$ASMMODE INTEL}
  540. asm
  541. cld
  542. mov edi, Environment
  543. lea esi, EnvVar
  544. xor eax, eax
  545. lodsb
  546. @NewVar:
  547. cmp byte ptr [edi], 0
  548. jz @Stop
  549. push eax { eax contains length of searched variable name }
  550. push esi { esi points to the beginning of the variable name }
  551. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  552. mov edx, edi { pointer to beginning of variable name saved in edx }
  553. mov al, '=' { searching until '=' (end of variable name) }
  554. repne
  555. scasb { scan until '=' not found }
  556. neg ecx { what was the name length? }
  557. dec ecx { corrected }
  558. dec ecx { exclude the '=' character }
  559. pop esi { restore pointer to beginning of variable name }
  560. pop eax { restore length of searched variable name }
  561. push eax { and save both of them again for later use }
  562. push esi
  563. cmp ecx, eax { compare length of searched variable name with name }
  564. jnz @NotEqual { ... of currently found variable, jump if different }
  565. xchg edx, edi { pointer to current variable name restored in edi }
  566. repe
  567. cmpsb { compare till the end of variable name }
  568. xchg edx, edi { pointer to beginning of variable contents in edi }
  569. jz @Equal { finish if they're equal }
  570. @NotEqual:
  571. xor eax, eax { look for 00h }
  572. mov ecx, -1 { it _must_ be found }
  573. repne
  574. scasb { scan until found }
  575. pop esi { restore pointer to beginning of variable name }
  576. pop eax { restore length of searched variable name }
  577. jmp @NewVar { ... or continue with new variable otherwise }
  578. @Stop:
  579. xor eax, eax
  580. mov P, eax { Not found - return nil }
  581. jmp @End
  582. @Equal:
  583. pop esi { restore the stack position }
  584. pop eax
  585. mov P, edi { place pointer to variable contents in P }
  586. @End:
  587. end ['eax','ecx','edx','esi','edi'];
  588. GetEnvPChar := P;
  589. end;
  590. {$ASMMODE ATT}
  591. Function GetEnv(envvar: string): string;
  592. (* The assembler version is more than three times as fast as Pascal. *)
  593. begin
  594. GetEnv := StrPas (GetEnvPChar (EnvVar));
  595. end;
  596. procedure GetFAttr (var F; var Attr: word);
  597. var
  598. PathInfo: TFileStatus3;
  599. RC: cardinal;
  600. {$ifndef FPC_ANSI_TEXTFILEREC}
  601. R: rawbytestring;
  602. {$endif not FPC_ANSI_TEXTFILEREC}
  603. P: pchar;
  604. begin
  605. Attr := 0;
  606. {$ifdef FPC_ANSI_TEXTFILEREC}
  607. P := @FileRec (F).Name;
  608. {$else FPC_ANSI_TEXTFILEREC}
  609. R := ToSingleByteFileSystemEncodedFileName (FileRec (F).Name);
  610. P := PChar (R);
  611. {$endif FPC_ANSI_TEXTFILEREC}
  612. RC := DosQueryPathInfo (P, ilStandard, @PathInfo, SizeOf (PathInfo));
  613. DosError := integer (RC);
  614. if RC = 0 then
  615. Attr := PathInfo.AttrFile
  616. else
  617. OSErrorWatch (RC);
  618. end;
  619. procedure SetFAttr (var F; Attr: word);
  620. var
  621. PathInfo: TFileStatus3;
  622. RC: cardinal;
  623. {$ifndef FPC_ANSI_TEXTFILEREC}
  624. R: rawbytestring;
  625. {$endif not FPC_ANSI_TEXTFILEREC}
  626. P: pchar;
  627. begin
  628. {$ifdef FPC_ANSI_TEXTFILEREC}
  629. P := @FileRec (F).Name;
  630. {$else FPC_ANSI_TEXTFILEREC}
  631. R := ToSingleByteFileSystemEncodedFileName (FileRec (F).Name);
  632. P := PChar (R);
  633. {$endif FPC_ANSI_TEXTFILEREC}
  634. RC := DosQueryPathInfo (P, ilStandard, @PathInfo, SizeOf (PathInfo));
  635. if RC = 0 then
  636. begin
  637. PathInfo.AttrFile := Attr;
  638. RC := DosSetPathInfo (P, ilStandard, @PathInfo, SizeOf (PathInfo),
  639. doWriteThru);
  640. if RC <> 0 then
  641. OSErrorWatch (RC);
  642. end
  643. else
  644. OSErrorWatch (RC);
  645. DosError := integer (RC);
  646. end;
  647. {function GetShortName(var p : String) : boolean;
  648. begin
  649. GetShortName:=true;}
  650. {$WARNING EA .shortname support (see FAT32 driver) should be probably added here!}
  651. {end;
  652. function GetLongName(var p : String) : boolean;
  653. begin
  654. GetLongName:=true;}
  655. {$WARNING EA .longname support should be probably added here!}
  656. {end;}
  657. begin
  658. FillChar (LastExecRes, SizeOf (LastExecRes), 0);
  659. LastDosErrorModuleName := '';
  660. ExecFlags := 0;
  661. LastExecFlags := deSync;
  662. end.