dos.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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. {$i dosh.inc}
  43. {OS/2 specific functions}
  44. function GetEnvPChar (EnvVar: string): PChar;
  45. function DosErrorModuleName: string;
  46. (* In case of an error in Dos.Exec returns the name of the module *)
  47. (* causing the problem - e.g. name of a missing or corrupted DLL. *)
  48. implementation
  49. {$DEFINE HAS_GETMSCOUNT}
  50. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  51. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  52. {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
  53. {$I dos.inc}
  54. threadvar
  55. LastDosErrorModuleName: string;
  56. const FindResvdMask = $00003737; {Allowed bits in attribute
  57. specification for DosFindFirst call.}
  58. function GetMsCount: int64;
  59. var
  60. L: cardinal;
  61. begin
  62. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  63. GetMsCount := L;
  64. end;
  65. function fsearch(path:pathstr;dirlist:string):pathstr;
  66. Var
  67. A: array [0..255] of char;
  68. D, P: AnsiString;
  69. begin
  70. P:=Path;
  71. D:=DirList;
  72. DosError := DosSearchPath (dsIgnoreNetErrs, PChar(D), PChar(P), @A, 255);
  73. fsearch := StrPas (@A);
  74. end;
  75. procedure getftime(var f;var time:longint);
  76. var
  77. FStat: TFileStatus3;
  78. begin
  79. DosError := DosQueryFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  80. SizeOf (FStat));
  81. if DosError=0 then
  82. begin
  83. Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
  84. if Time = 0 then
  85. Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
  86. end else
  87. Time:=0;
  88. end;
  89. procedure SetFTime (var F; Time: longint);
  90. var FStat: TFileStatus3;
  91. RC: cardinal;
  92. begin
  93. RC := DosQueryFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  94. SizeOf (FStat));
  95. if RC = 0 then
  96. begin
  97. FStat.DateLastAccess := Hi (Time);
  98. FStat.DateLastWrite := Hi (Time);
  99. FStat.TimeLastAccess := Lo (Time);
  100. FStat.TimeLastWrite := Lo (Time);
  101. RC := DosSetFileInfo (FileRec (F).Handle, ilStandard, @FStat,
  102. SizeOf (FStat));
  103. end;
  104. DosError := integer (RC);
  105. end;
  106. procedure Exec (const Path: PathStr; const ComLine: ComStr);
  107. {Execute a program.}
  108. var Args0, Args: PByteArray;
  109. ArgSize: word;
  110. Res: TResultCodes;
  111. ObjName: string;
  112. RC: longint;
  113. HQ: THandle;
  114. SPID, STID, QName: string;
  115. SD: TStartData;
  116. SID, PID: cardinal;
  117. RD: TRequestData;
  118. PCI: PChildInfo;
  119. CISize: cardinal;
  120. Prio: byte;
  121. const
  122. MaxArgsSize = 3072; (* Amount of memory reserved for arguments in bytes. *)
  123. begin
  124. { LastDosExitCode := Exec (Path, ExecRunFlags (ExecFlags), efDefault, ComLine);}
  125. QName := FExpand (Path);
  126. if ComLine = '' then
  127. begin
  128. Args0 := nil;
  129. Args := nil;
  130. end
  131. else
  132. begin
  133. GetMem (Args0, MaxArgsSize);
  134. Args := Args0;
  135. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  136. (* should not cross 64K boundary. *)
  137. if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
  138. Inc (pointer (Args), 1024);
  139. ArgSize := 0;
  140. Move (QName [1], Args^ [ArgSize], Length (QName));
  141. Inc (ArgSize, Length (QName));
  142. Args^ [ArgSize] := 0;
  143. Inc (ArgSize);
  144. {Now do the real arguments.}
  145. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  146. Inc (ArgSize, Length (ComLine));
  147. Args^ [ArgSize] := 0;
  148. Inc (ArgSize);
  149. Args^ [ArgSize] := 0;
  150. end;
  151. RC := DosExecPgm (ObjName, cardinal (ExecFlags), Args, nil, Res, Path);
  152. if RC = 0 then
  153. begin
  154. LastDosExitCode := Res.ExitCode;
  155. LastDosErrorModuleName := '';
  156. end
  157. else
  158. if (RC = 190) or (RC = 191) then
  159. begin
  160. FillChar (SD, SizeOf (SD), 0);
  161. SD.Length := 24;
  162. SD.Related := ssf_Related_Child;
  163. if Args = nil then
  164. (* No parameters passed, Args not allocated for DosExecPgm, so allocate now. *)
  165. begin
  166. GetMem (Args, MaxArgsSize);
  167. Move (QName [1], Args^ [0], Length (QName));
  168. Args^ [Length (QName)] := 0;
  169. end
  170. else
  171. SD.PgmInputs := PChar (@Args^ [Length (QName) + 1]);
  172. SD.PgmName := PChar (Args);
  173. SD.InheritOpt := ssf_InhertOpt_Parent;
  174. Str (GetProcessID, SPID);
  175. Str (ThreadID, STID);
  176. QName := '\QUEUES\FPC_Dos_Exec_p' + SPID + 't' + STID + '.QUE'#0;
  177. SD.TermQ := @QName [1];
  178. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  179. if RC = 0 then
  180. begin
  181. RC := DosStartSession (SD, SID, PID);
  182. if (RC = 0) or (RC = 457) then
  183. begin
  184. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  185. if RC = 0 then
  186. begin
  187. LastDosExitCode := PCI^.Return;
  188. DosCloseQueue (HQ);
  189. DosFreeMem (PCI);
  190. end
  191. else
  192. DosCloseQueue (HQ);
  193. end
  194. else
  195. DosCloseQueue (HQ);
  196. end;
  197. end
  198. else
  199. LastDosErrorModuleName := ObjName;
  200. if RC <> 0 then
  201. LastDosExitCode := 0; (* Needed for TP/BP compatibility *)
  202. DosError := RC;
  203. if Args0 <> nil then
  204. FreeMem (Args0, MaxArgsSize);
  205. end;
  206. function DosErrorModuleName: string;
  207. begin
  208. DosErrorModuleName := LastDosErrorModuleName;
  209. end;
  210. function dosversion:word;
  211. {Returns OS/2 version}
  212. var
  213. Minor, Major: Cardinal;
  214. begin
  215. DosQuerySysInfo(svMajorVersion, svMajorVersion, Major, 4);
  216. DosQuerySysInfo(svMinorVersion, svMinorVersion, Minor, 4);
  217. DosVersion:=Major or Minor shl 8;
  218. end;
  219. procedure GetDate (var Year, Month, MDay, WDay: word);
  220. Var
  221. dt: TDateTime;
  222. begin
  223. DosGetDateTime(dt);
  224. Year:=dt.year;
  225. Month:=dt.month;
  226. MDay:=dt.Day;
  227. WDay:=dt.Weekday;
  228. end;
  229. procedure SetDate (Year, Month, Day: word);
  230. var
  231. DT: TDateTime;
  232. begin
  233. DosGetDateTime (DT);
  234. DT.Year := Year;
  235. DT.Month := byte (Month);
  236. DT.Day := byte (Day);
  237. DosSetDateTime (DT);
  238. end;
  239. procedure GetTime (var Hour, Minute, Second, Sec100: word);
  240. var
  241. dt: TDateTime;
  242. begin
  243. DosGetDateTime(dt);
  244. Hour:=dt.Hour;
  245. Minute:=dt.Minute;
  246. Second:=dt.Second;
  247. Sec100:=dt.Hundredths;
  248. end;
  249. procedure SetTime (Hour, Minute, Second, Sec100: word);
  250. var
  251. DT: TDateTime;
  252. begin
  253. DosGetDateTime (DT);
  254. DT.Hour := byte (Hour);
  255. DT.Minute := byte (Minute);
  256. DT.Second := byte (Second);
  257. DT.Sec100 := byte (Sec100);
  258. DosSetDateTime (DT);
  259. end;
  260. function DiskFree (Drive: byte): int64;
  261. var FI: TFSinfo;
  262. RC: cardinal;
  263. begin
  264. {In OS/2, we use the filesystem information.}
  265. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  266. if RC = 0 then
  267. DiskFree := int64 (FI.Free_Clusters) *
  268. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  269. else
  270. DiskFree := -1;
  271. end;
  272. function DiskSize (Drive: byte): int64;
  273. var FI: TFSinfo;
  274. RC: cardinal;
  275. begin
  276. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  277. if RC = 0 then
  278. DiskSize := int64 (FI.Total_Clusters) *
  279. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  280. else
  281. DiskSize := -1;
  282. end;
  283. procedure DosSearchRec2SearchRec (var F: SearchRec);
  284. type
  285. TRec = record
  286. T, D: word;
  287. end;
  288. begin
  289. with F do
  290. begin
  291. Name := FStat^.Name;
  292. Size := FStat^.FileSize;
  293. Attr := byte(FStat^.AttrFile and $FF);
  294. TRec (Time).T := FStat^.TimeLastWrite;
  295. TRec (Time).D := FStat^.DateLastWrite;
  296. end;
  297. end;
  298. procedure FindFirst (const Path: PathStr; Attr: word; var F: SearchRec);
  299. var Count: cardinal;
  300. begin
  301. {No error.}
  302. DosError := 0;
  303. New (F.FStat);
  304. F.Handle := THandle ($FFFFFFFF);
  305. Count := 1;
  306. DosError := integer (DosFindFirst (Path, F.Handle,
  307. Attr and FindResvdMask, F.FStat, SizeOf (F.FStat^),
  308. Count, ilStandard));
  309. if (DosError = 0) and (Count = 0) then DosError := 18;
  310. DosSearchRec2SearchRec (F);
  311. end;
  312. procedure FindNext (var F: SearchRec);
  313. var
  314. Count: cardinal;
  315. begin
  316. {No error}
  317. DosError := 0;
  318. Count := 1;
  319. DosError := integer (DosFindNext (F.Handle, F.FStat, SizeOf (F.FStat^),
  320. Count));
  321. if (DosError = 0) and (Count = 0) then DosError := 18;
  322. DosSearchRec2SearchRec (F);
  323. end;
  324. procedure FindClose (var F: SearchRec);
  325. begin
  326. if F.Handle <> THandle ($FFFFFFFF) then DosError := DosFindClose (F.Handle);
  327. Dispose (F.FStat);
  328. end;
  329. function envcount:longint;
  330. begin
  331. envcount:=envc;
  332. end;
  333. function envstr (index : longint) : string;
  334. var hp:Pchar;
  335. begin
  336. if (index<=0) or (index>envcount) then
  337. begin
  338. envstr:='';
  339. exit;
  340. end;
  341. hp:=EnvP[index-1];
  342. envstr:=strpas(hp);
  343. end;
  344. function GetEnvPChar (EnvVar: string): PChar;
  345. (* The assembler version is more than three times as fast as Pascal. *)
  346. var
  347. P: PChar;
  348. begin
  349. EnvVar := UpCase (EnvVar);
  350. {$ASMMODE INTEL}
  351. asm
  352. cld
  353. mov edi, Environment
  354. lea esi, EnvVar
  355. xor eax, eax
  356. lodsb
  357. @NewVar:
  358. cmp byte ptr [edi], 0
  359. jz @Stop
  360. push eax { eax contains length of searched variable name }
  361. push esi { esi points to the beginning of the variable name }
  362. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  363. mov edx, edi { pointer to beginning of variable name saved in edx }
  364. mov al, '=' { searching until '=' (end of variable name) }
  365. repne
  366. scasb { scan until '=' not found }
  367. neg ecx { what was the name length? }
  368. dec ecx { corrected }
  369. dec ecx { exclude the '=' character }
  370. pop esi { restore pointer to beginning of variable name }
  371. pop eax { restore length of searched variable name }
  372. push eax { and save both of them again for later use }
  373. push esi
  374. cmp ecx, eax { compare length of searched variable name with name }
  375. jnz @NotEqual { ... of currently found variable, jump if different }
  376. xchg edx, edi { pointer to current variable name restored in edi }
  377. repe
  378. cmpsb { compare till the end of variable name }
  379. xchg edx, edi { pointer to beginning of variable contents in edi }
  380. jz @Equal { finish if they're equal }
  381. @NotEqual:
  382. xor eax, eax { look for 00h }
  383. mov ecx, -1 { it _must_ be found }
  384. repne
  385. scasb { scan until found }
  386. pop esi { restore pointer to beginning of variable name }
  387. pop eax { restore length of searched variable name }
  388. jmp @NewVar { ... or continue with new variable otherwise }
  389. @Stop:
  390. xor eax, eax
  391. mov P, eax { Not found - return nil }
  392. jmp @End
  393. @Equal:
  394. pop esi { restore the stack position }
  395. pop eax
  396. mov P, edi { place pointer to variable contents in P }
  397. @End:
  398. end ['eax','ecx','edx','esi','edi'];
  399. GetEnvPChar := P;
  400. end;
  401. {$ASMMODE ATT}
  402. Function GetEnv(envvar: string): string;
  403. (* The assembler version is more than three times as fast as Pascal. *)
  404. begin
  405. GetEnv := StrPas (GetEnvPChar (EnvVar));
  406. end;
  407. procedure GetFAttr (var F; var Attr: word);
  408. var
  409. PathInfo: TFileStatus3;
  410. RC: cardinal;
  411. begin
  412. Attr := 0;
  413. RC := DosQueryPathInfo (@FileRec (F).Name, ilStandard,
  414. @PathInfo, SizeOf (PathInfo));
  415. DosError := integer (RC);
  416. if RC = 0 then
  417. Attr := PathInfo.AttrFile;
  418. end;
  419. procedure SetFAttr (var F; Attr: word);
  420. var
  421. PathInfo: TFileStatus3;
  422. RC: cardinal;
  423. begin
  424. RC := DosQueryPathInfo (@FileRec (F).Name, ilStandard,
  425. @PathInfo, SizeOf (PathInfo));
  426. if RC = 0 then
  427. begin
  428. PathInfo.AttrFile := Attr;
  429. RC := DosSetPathInfo (@FileRec (F).Name, ilStandard, @PathInfo,
  430. SizeOf (PathInfo), doWriteThru);
  431. end;
  432. DosError := integer (RC);
  433. end;
  434. {function GetShortName(var p : String) : boolean;
  435. begin
  436. GetShortName:=true;}
  437. {$WARNING EA .shortname support (see FAT32 driver) should be probably added here!}
  438. {end;
  439. function GetLongName(var p : String) : boolean;
  440. begin
  441. GetLongName:=true;}
  442. {$WARNING EA .longname support should be probably added here!}
  443. {end;}
  444. begin
  445. LastDosExitCode := 0;
  446. LastDosErrorModuleName := '';
  447. ExecFlags := 0;
  448. end.