dos.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2004 by the Free Pascal development team.
  4. Dos unit for BP7 compatible RTL
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit dos;
  12. {$mode fpc}
  13. interface
  14. uses windows;
  15. Const
  16. Max_Path = MaxPathLen;
  17. Type
  18. Searchrec = Packed Record
  19. FindHandle : THandle;
  20. W32FindData : TWin32FindData;
  21. ExcludeAttr : longint;
  22. time : longint;
  23. size : longint;
  24. attr : longint;
  25. name : string;
  26. end;
  27. {$i dosh.inc}
  28. Function WinToDosTime (Const Wtime : TFileTime; var DTime:longint):longbool;
  29. Function DosToWinTime (DTime:longint; var Wtime : TFileTime):longbool;
  30. implementation
  31. {$DEFINE HAS_GETMSCOUNT}
  32. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  33. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  34. {$I dos.inc}
  35. {******************************************************************************
  36. --- Conversion ---
  37. ******************************************************************************}
  38. function GetMsCount: int64;
  39. begin
  40. GetMsCount := cardinal (GetTickCount);
  41. end;
  42. function Last2DosError(d:dword):integer;
  43. begin
  44. case d of
  45. 87 : { Parameter invalid -> Data invalid }
  46. Last2DosError:=13;
  47. else
  48. Last2DosError:=integer(d);
  49. end;
  50. end;
  51. Function DosToWinAttr (Const Attr : Longint) : longint;
  52. begin
  53. DosToWinAttr:=Attr;
  54. end;
  55. Function WinToDosAttr (Const Attr : Longint) : longint;
  56. begin
  57. WinToDosAttr:=Attr;
  58. end;
  59. type
  60. Longrec=packed record
  61. lo,hi : word;
  62. end;
  63. Function DosToWinTime (DTime:longint; var Wtime : TFileTime):longbool;
  64. var
  65. FatDate, FatTime: WORD;
  66. lft: TFileTime;
  67. st: SYSTEMTIME;
  68. begin
  69. FatDate:=Longrec(Dtime).Hi;
  70. FatTime:=Longrec(Dtime).Lo;
  71. with st do
  72. begin
  73. wDay:=FatDate and $1F;
  74. wMonth:=(FatDate shr 5) and $F;
  75. wYear:=(FatDate shr 9) + 1980;
  76. wSecond:=(FatTime and $1F)*2;
  77. wMinute:=(FatTime shr 5) and $1F;
  78. wHour:=FatTime shr 11;
  79. wMilliseconds:=0;
  80. wDayOfWeek:=0;
  81. end;
  82. DosToWinTime:=SystemTimeToFileTime(@st, @lft) and LocalFileTimeToFileTime(@lft, @Wtime);
  83. end;
  84. Function WinToDosTime (Const Wtime : TFileTime; var DTime:longint):longbool;
  85. var
  86. FatDate, FatTime: WORD;
  87. lft: TFileTime;
  88. st: SYSTEMTIME;
  89. res: longbool;
  90. begin
  91. res:=FileTimeToLocalFileTime(@WTime, @lft) and FileTimeToSystemTime(@lft, @st);
  92. if res then
  93. begin
  94. FatDate:=st.wDay or (st.wMonth shl 5) or (word(st.wYear - 1980) shl 9);
  95. FatTime:=word(st.wSecond div 2) or (st.wMinute shl 5) or (st.wHour shl 11);
  96. Longrec(Dtime).Hi:=FatDate;
  97. Longrec(Dtime).Lo:=FatTime;
  98. end;
  99. WinToDosTime:=res;
  100. end;
  101. {******************************************************************************
  102. --- Info / Date / Time ---
  103. ******************************************************************************}
  104. function dosversion : word;
  105. var
  106. versioninfo : OSVERSIONINFO;
  107. begin
  108. versioninfo.dwOSVersionInfoSize:=sizeof(versioninfo);
  109. GetVersionEx(versioninfo);
  110. dosversion:=versioninfo.dwMajorVersion and $FF or versioninfo.dwMinorVersion and $FF shl 8;
  111. end;
  112. procedure getdate(var year,month,mday,wday : word);
  113. var
  114. t : TSystemTime;
  115. begin
  116. GetLocalTime(t);
  117. year:=t.wYear;
  118. month:=t.wMonth;
  119. mday:=t.wDay;
  120. wday:=t.wDayOfWeek;
  121. end;
  122. procedure setdate(year,month,day : word);
  123. var
  124. t : TSystemTime;
  125. begin
  126. GetLocalTime(t);
  127. t.wYear:=year;
  128. t.wMonth:=month;
  129. t.wDay:=day;
  130. { only a quite good solution, we can loose some ms }
  131. SetLocalTime(t);
  132. end;
  133. procedure gettime(var hour,minute,second,sec100 : word);
  134. var
  135. t : TSystemTime;
  136. begin
  137. GetLocalTime(t);
  138. hour:=t.wHour;
  139. minute:=t.wMinute;
  140. second:=t.wSecond;
  141. sec100:=t.wMilliSeconds div 10;
  142. end;
  143. procedure settime(hour,minute,second,sec100 : word);
  144. var
  145. t : TSystemTime;
  146. begin
  147. GetLocalTime(t);
  148. t.wHour:=hour;
  149. t.wMinute:=minute;
  150. t.wSecond:=second;
  151. t.wMilliSeconds:=sec100*10;
  152. SetLocalTime(t);
  153. end;
  154. {******************************************************************************
  155. --- Exec ---
  156. ******************************************************************************}
  157. procedure exec(const path : pathstr;const comline : comstr);
  158. var
  159. PI: TProcessInformation;
  160. Proc : THandle;
  161. l : LongInt;
  162. PathW : array[0..FileNameLen] of WideChar;
  163. CmdLineW : array[0..FileNameLen] of WideChar;
  164. begin
  165. DosError := 0;
  166. AnsiToWideBuf(@path[1], Length(path), PathW, SizeOf(PathW));
  167. AnsiToWideBuf(@comline[1], Length(comline), CmdLineW, SizeOf(CmdLineW));
  168. if not CreateProcess(PathW, CmdLineW,
  169. nil, nil, FALSE, 0, nil, nil, nil, PI) then
  170. begin
  171. DosError:=Last2DosError(GetLastError);
  172. exit;
  173. end;
  174. Proc:=PI.hProcess;
  175. CloseHandle(PI.hThread);
  176. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  177. GetExitCodeProcess(Proc, @l)
  178. else
  179. l:=-1;
  180. CloseHandle(Proc);
  181. LastDosExitCode:=l;
  182. end;
  183. {******************************************************************************
  184. --- Disk ---
  185. ******************************************************************************}
  186. var
  187. DriveNames: array[1..24] of PWideChar;
  188. function GetDriveName(drive: byte): PWideChar;
  189. const
  190. dev_attr = FILE_ATTRIBUTE_TEMPORARY or FILE_ATTRIBUTE_DIRECTORY;
  191. var
  192. h: THandle;
  193. fd: TWin32FindData;
  194. i, len: LongInt;
  195. begin
  196. GetDriveName:=nil;
  197. // Current drive is C: drive always
  198. if drive = 0 then
  199. drive:=2;
  200. if (drive < 3) or (drive > 26) then
  201. exit;
  202. if DriveNames[1] = nil then
  203. begin
  204. // Drive C: is filesystem root always
  205. GetMem(DriveNames[1], 2*SizeOf(WideChar));
  206. DriveNames[1][0]:='\';
  207. DriveNames[1][1]:=#0;
  208. // Other drives are found dinamically
  209. h:=FindFirstFile('\*', @fd);
  210. if h <> 0 then
  211. begin
  212. i:=2;
  213. repeat
  214. if fd.dwFileAttributes and dev_attr = dev_attr then begin
  215. len:=0;
  216. while fd.cFileName[len] <> #0 do
  217. Inc(len);
  218. len:=(len + 2)*SizeOf(WideChar);
  219. GetMem(DriveNames[i], len);
  220. DriveNames[i]^:='\';
  221. Move(fd.cFileName, DriveNames[i][1], len - SizeOf(WideChar));
  222. Inc(i);
  223. end;
  224. until (i > 24) or not FindNextFile(h, fd);
  225. Windows.FindClose(h);
  226. end;
  227. end;
  228. GetDriveName:=DriveNames[drive - 2];
  229. end;
  230. function diskfree(drive : byte) : int64;
  231. var
  232. disk: PWideChar;
  233. qwtotal,qwfree,qwcaller : int64;
  234. begin
  235. disk:=GetDriveName(drive);
  236. if (disk <> nil) and GetDiskFreeSpaceEx(disk, @qwcaller, @qwtotal, @qwfree) then
  237. diskfree:=qwfree
  238. else
  239. diskfree:=-1;
  240. end;
  241. function disksize(drive : byte) : int64;
  242. var
  243. disk : PWideChar;
  244. qwtotal,qwfree,qwcaller : int64;
  245. begin
  246. disk:=GetDriveName(drive);
  247. if (disk <> nil) and GetDiskFreeSpaceEx(disk, @qwcaller, @qwtotal, @qwfree) then
  248. disksize:=qwtotal
  249. else
  250. disksize:=-1;
  251. end;
  252. {******************************************************************************
  253. --- Findfirst FindNext ---
  254. ******************************************************************************}
  255. Procedure StringToPchar (Var S : ShortString);
  256. Var L : Longint;
  257. begin
  258. L:=ord(S[0]);
  259. Move (S[1],S[0],L);
  260. S[L]:=#0;
  261. end;
  262. Procedure PCharToString (Var S : ShortString);
  263. Var L : Longint;
  264. begin
  265. L:=strlen(PAnsiChar(@S[0]));
  266. Move (S[0],S[1],L);
  267. S[0]:=AnsiChar(l);
  268. end;
  269. procedure FindMatch(var f:searchrec);
  270. var
  271. buf: array[0..MaxPathLen] of AnsiChar;
  272. begin
  273. { Find file with correct attribute }
  274. While (F.W32FindData.dwFileAttributes and cardinal(F.ExcludeAttr))<>0 do
  275. begin
  276. if not FindNextFile (F.FindHandle, F.W32FindData) then
  277. begin
  278. DosError:=Last2DosError(GetLastError);
  279. if DosError=2 then
  280. DosError:=18;
  281. exit;
  282. end;
  283. end;
  284. { Convert some attributes back }
  285. f.size:=F.W32FindData.NFileSizeLow;
  286. f.attr:=WinToDosAttr(F.W32FindData.dwFileAttributes);
  287. WinToDosTime(F.W32FindData.ftLastWriteTime,f.Time);
  288. WideToAnsiBuf(@F.W32FindData.cFileName, -1, buf, SizeOf(buf));
  289. f.Name:=StrPas(@buf);
  290. end;
  291. procedure findfirst(const path : pathstr;attr : word;var f : searchRec);
  292. var
  293. buf: array[0..MaxPathLen] of WideChar;
  294. begin
  295. if path = ''then
  296. begin
  297. DosError:=3;
  298. exit;
  299. end;
  300. fillchar(f,sizeof(f),0);
  301. { no error }
  302. doserror:=0;
  303. F.Name:=Path;
  304. F.Attr:=attr;
  305. F.ExcludeAttr:=(not Attr) and ($1e); {hidden,sys,dir,volume}
  306. StringToPchar(f.name);
  307. { FindFirstFile is a WinCE Call }
  308. F.W32FindData.dwFileAttributes:=DosToWinAttr(f.attr);
  309. AnsiToWideBuf(@f.Name, -1, buf, SizeOf(buf));
  310. F.FindHandle:=FindFirstFile (buf, F.W32FindData);
  311. If F.FindHandle = Invalid_Handle_value then
  312. begin
  313. DosError:=Last2DosError(GetLastError);
  314. if DosError=2 then
  315. DosError:=18;
  316. exit;
  317. end;
  318. { Find file with correct attribute }
  319. FindMatch(f);
  320. end;
  321. procedure findnext(var f : searchRec);
  322. begin
  323. { no error }
  324. doserror:=0;
  325. if not FindNextFile (F.FindHandle, F.W32FindData) then
  326. begin
  327. DosError:=Last2DosError(GetLastError);
  328. if DosError=2 then
  329. DosError:=18;
  330. exit;
  331. end;
  332. { Find file with correct attribute }
  333. FindMatch(f);
  334. end;
  335. Procedure FindClose(Var f: SearchRec);
  336. begin
  337. If F.FindHandle <> Invalid_Handle_value then
  338. Windows.FindClose(F.FindHandle);
  339. end;
  340. {******************************************************************************
  341. --- File ---
  342. ******************************************************************************}
  343. Function FSearch(path: pathstr; dirlist: shortstring): pathstr;
  344. var
  345. p1 : longint;
  346. s : searchrec;
  347. newdir : pathstr;
  348. begin
  349. { No wildcards allowed in these things }
  350. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  351. begin
  352. fsearch:='';
  353. exit;
  354. end;
  355. { check if the file specified exists }
  356. findfirst(path,anyfile and not(directory),s);
  357. if doserror=0 then
  358. begin
  359. findclose(s);
  360. fsearch:=path;
  361. exit;
  362. end;
  363. findclose(s);
  364. { allow slash as backslash }
  365. DoDirSeparators(dirlist);
  366. repeat
  367. p1:=pos(';',dirlist);
  368. if p1<>0 then
  369. begin
  370. newdir:=copy(dirlist,1,p1-1);
  371. delete(dirlist,1,p1);
  372. end
  373. else
  374. begin
  375. newdir:=dirlist;
  376. dirlist:='';
  377. end;
  378. if (newdir<>'') and (not (newdir[length(newdir)] in [DirectorySeparator,DriveSeparator])) then
  379. newdir:=newdir+DirectorySeparator;
  380. findfirst(newdir+path,anyfile and not(directory),s);
  381. if doserror=0 then
  382. newdir:=newdir+path
  383. else
  384. newdir:='';
  385. findclose(s);
  386. until (dirlist='') or (newdir<>'');
  387. fsearch:=newdir;
  388. end;
  389. { </immobilizer> }
  390. procedure getftime(var f;var time : longint);
  391. var
  392. ft : TFileTime;
  393. begin
  394. doserror:=0;
  395. if GetFileTime(filerec(f).Handle,nil,nil,@ft) and
  396. WinToDosTime(ft,time) then
  397. exit
  398. else
  399. begin
  400. DosError:=Last2DosError(GetLastError);
  401. time:=0;
  402. end;
  403. end;
  404. procedure setftime(var f;time : longint);
  405. var
  406. ft : TFileTime;
  407. begin
  408. doserror:=0;
  409. if DosToWinTime(time,ft) and
  410. SetFileTime(filerec(f).Handle,nil,nil,@ft) then
  411. exit
  412. else
  413. DosError:=Last2DosError(GetLastError);
  414. end;
  415. procedure getfattr(var f;var attr : word);
  416. var
  417. l : cardinal;
  418. {$ifdef FPC_ANSI_TEXTFILEREC}
  419. u: unicodestring;
  420. {$endif FPC_ANSI_TEXTFILEREC}
  421. begin
  422. if filerec(f).name[0] = #0 then
  423. begin
  424. doserror:=3;
  425. attr:=0;
  426. end
  427. else
  428. begin
  429. doserror:=0;
  430. {$ifdef FPC_ANSI_TEXTFILEREC}
  431. widestringmanager.Ansi2UnicodeMoveProc(filerec(f).name,DefaultFileSystemCodePage,u,length(filerec(f).name));
  432. l:=GetFileAttributes(pwidechar(u));
  433. {$else}
  434. l:=GetFileAttributes(filerec(f).name);
  435. {$endif}
  436. if l = $ffffffff then
  437. begin
  438. doserror:=Last2DosError(GetLastError);
  439. attr:=0;
  440. end
  441. else
  442. attr:=l and $ffff;
  443. end;
  444. end;
  445. procedure setfattr(var f;attr : word);
  446. var
  447. buf: array[0..MaxPathLen] of WideChar;
  448. begin
  449. { Fail for setting VolumeId }
  450. if (attr and VolumeID)<>0 then
  451. doserror:=5
  452. else
  453. begin
  454. AnsiToWideBuf(@filerec(f).name, -1, buf, SizeOf(buf));
  455. if SetFileAttributes(buf,attr) then
  456. doserror:=0
  457. else
  458. doserror:=Last2DosError(GetLastError);
  459. end;
  460. end;
  461. {******************************************************************************
  462. --- Environment ---
  463. ******************************************************************************}
  464. // WinCE does not have environment. It can be emulated via registry or file. (YS)
  465. function envcount : longint;
  466. begin
  467. envcount:=0;
  468. end;
  469. Function EnvStr (Index: longint): string;
  470. begin
  471. EnvStr:='';
  472. end;
  473. Function GetEnv(envvar: string): string;
  474. begin
  475. GetEnv:='';
  476. end;
  477. var
  478. oldexitproc : pointer;
  479. procedure dosexitproc;
  480. var
  481. i: LongInt;
  482. begin
  483. exitproc:=oldexitproc;
  484. if DriveNames[1] <> nil then
  485. for i:=1 to 24 do
  486. if DriveNames[i] <> nil then
  487. FreeMem(DriveNames[i])
  488. else
  489. break;
  490. end;
  491. begin
  492. oldexitproc:=exitproc;
  493. exitproc:=@dosexitproc;
  494. end.