dos.pas 20 KB

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