dos.pas 21 KB

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