2
0

dos.pas 20 KB

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