{ This file is part of the Free Pascal run time library. Copyright (c) 1999-2000 by Michael Van Canneyt and Peter Vreman, members of the Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} {$IFNDEF FPC_DOTTEDUNITS} Unit Dos; {$ENDIF FPC_DOTTEDUNITS} Interface Const FileNameLen = 255; Type SearchRec = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT} packed {$endif FPC_REQUIRES_PROPER_ALIGNMENT} Record {Fill : array[1..21] of byte; Fill replaced with below} SearchPos : UInt64; {directory position} SearchNum : LongInt; {to track which search this is} DirFD : LongInt; {directory fd handle for reading directory} SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file} SearchAttr : Byte; {attribute we are searching for} Mode : Word; Fill : Array[1..1] of Byte; {future use} {End of fill} Attr : Byte; {attribute of found file} Time : LongInt; {last modify date of found file} Size : LongInt; {file size of found file} Reserved : Word; {future use} Name : String[FileNameLen]; {name of found file} SearchSpec : String[FileNameLen]; {search pattern} NamePos : Word; {end of path, start of name position} End; {$DEFINE HAS_FILENAMELEN} {$i dosh.inc} {Extra Utils} function weekday(y,m,d : longint) : longint; platform; Procedure WasiDateToDt(NanoSecsPast: UInt64; Var Dt: DateTime); platform; Function DTToWasiDate(DT: DateTime): UInt64; platform; {Disk} //Function AddDisk(const path:string) : byte; platform; Implementation {$IFDEF FPC_DOTTEDUNITS} Uses WASIApi.WASIApi, WASIApi.WASIUtil; {$ELSE FPC_DOTTEDUNITS} Uses WasiAPI, WasiUtil; {$ENDIF FPC_DOTTEDUNITS} {$DEFINE HAS_GETMSCOUNT} {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home } {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PAnsiChar } {$I dos.inc} {****************************************************************************** --- Link C Lib if set --- ******************************************************************************} {****************************************************************************** --- Info / Date / Time --- ******************************************************************************} Function DosVersion:Word; Begin End; function WeekDay (y,m,d:longint):longint; { Calculates th day of the week. returns -1 on error } var u,v : longint; begin if (m<1) or (m>12) or (y<1600) or (y>4000) or (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then WeekDay:=-1 else begin u:=m; v:=y; if m<3 then begin inc(u,12); dec(v); end; WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7; end; end; Procedure GetDate(Var Year, Month, MDay, WDay: Word); var NanoSecsPast: __wasi_timestamp_t; DT: DateTime; begin if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,10000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then begin WasiDateToDT(NanoSecsPast,DT); Year:=DT.Year; Month:=DT.Month; MDay:=DT.Day; WDay:=weekday(DT.Year,DT.Month,DT.Day); end else begin Year:=0; Month:=0; MDay:=0; WDay:=0; end; end; procedure SetTime(Hour,Minute,Second,sec100:word); begin end; procedure SetDate(Year,Month,Day:Word); begin end; Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean; begin end; Procedure GetTime(Var Hour, Minute, Second, Sec100: Word); var NanoSecsPast: __wasi_timestamp_t; begin if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,10000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then begin { todo: convert UTC to local time, as soon as we can get the local timezone from WASI: https://github.com/WebAssembly/WASI/issues/239 } NanoSecsPast:=NanoSecsPast div 10000000; Sec100:=NanoSecsPast mod 100; NanoSecsPast:=NanoSecsPast div 100; Second:=NanoSecsPast mod 60; NanoSecsPast:=NanoSecsPast div 60; Minute:=NanoSecsPast mod 60; NanoSecsPast:=NanoSecsPast div 60; Hour:=NanoSecsPast mod 24; end else begin Hour:=0; Minute:=0; Second:=0; Sec100:=0; end; end; Function DTToWasiDate(DT: DateTime): UInt64; var res: Int64; begin res:={$IFDEF FPC_DOTTEDUNITS}WASIApi.{$ENDIF}WasiUtil.LocalToEpoch(DT.year,DT.month,DT.day,DT.hour,DT.min,DT.sec); if res<0 then DTToWasiDate:=0 else DTToWasiDate:=res*1000000000; end; Procedure WasiDateToDt(NanoSecsPast: UInt64; Var Dt: DateTime); Begin {$IFDEF FPC_DOTTEDUNITS}WASIApi.{$ENDIF}WasiUtil.EpochToLocal(NanoSecsPast div 1000000000,Dt.Year,Dt.Month,Dt.Day,Dt.Hour,Dt.Min,Dt.Sec); End; function GetMsCount: int64; var NanoSecsPast: __wasi_timestamp_t; begin if __wasi_clock_time_get(__WASI_CLOCKID_REALTIME,1000000,@NanoSecsPast)=__WASI_ERRNO_SUCCESS then GetMsCount:=NanoSecsPast div 1000000 else GetMsCount:=0; end; {****************************************************************************** --- Exec --- ******************************************************************************} Procedure Exec (Const Path: PathStr; Const ComLine: ComStr); Begin End; {****************************************************************************** --- Disk --- ******************************************************************************} { The Diskfree and Disksize functions need a file on the specified drive, since this is required for the fpstatfs system call. These filenames are set in drivestr[0..26], and have been preset to : 0 - '.' (default drive - hence current dir is ok.) 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system ) 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system ) 3 - '/' (C: equivalent of dos is the root partition) 4..26 (can be set by you're own applications) ! Use AddDisk() to Add new drives ! They both return -1 when a failure occurs. } Const FixDriveStr : array[0..3] of PAnsiChar=( '.', '/fd0/.', '/fd1/.', '/.' ); const Drives : byte = 4; var DriveStr : array[4..26] of PAnsiChar; Function AddDisk(const path:string) : byte; begin { if not (DriveStr[Drives]=nil) then FreeMem(DriveStr[Drives]); GetMem(DriveStr[Drives],length(Path)+1); StrPCopy(DriveStr[Drives],path); AddDisk:=Drives; inc(Drives); if Drives>26 then Drives:=4;} end; Function DiskFree(Drive: Byte): int64; {var fs : tstatfs;} Begin { if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then Diskfree:=int64(fs.bavail)*int64(fs.bsize) else Diskfree:=-1;} End; Function DiskSize(Drive: Byte): int64; {var fs : tstatfs;} Begin { if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then DiskSize:=int64(fs.blocks)*int64(fs.bsize) else DiskSize:=-1;} End; Procedure FreeDriveStr; {var i: longint;} begin { for i:=low(drivestr) to high(drivestr) do if assigned(drivestr[i]) then begin freemem(drivestr[i]); drivestr[i]:=nil; end;} end; {****************************************************************************** --- Findfirst FindNext --- ******************************************************************************} procedure SearchRec2WasiSearchRec(const i: SearchRec; var o: TWasiSearchRec); var DT: DateTime; begin FillChar(o,SizeOf(o),0); o.SearchPos:=i.SearchPos; o.SearchNum:=i.SearchNum; o.DirFD:=i.DirFD; o.SearchType:=i.SearchType; o.SearchAttr:=i.SearchAttr; o.Attr:=i.Attr; UnpackTime(i.Time,DT); o.Time:=DTToWasiDate(DT); o.Size:=i.Size; o.Name:=i.Name; o.SearchSpec:=i.SearchSpec; o.NamePos:=i.NamePos; end; procedure WasiSearchRec2SearchRec(const i: TWasiSearchRec; var o: SearchRec); var DT: DateTime; begin FillChar(o,SizeOf(o),0); o.SearchPos:=i.SearchPos; o.SearchNum:=i.SearchNum; o.DirFD:=i.DirFD; o.SearchType:=i.SearchType; o.SearchAttr:=i.SearchAttr; o.Attr:=i.Attr; WasiDateToDt(i.Time,DT); PackTime(DT,o.Time); o.Size:=i.Size; o.Name:=i.Name; o.SearchSpec:=i.SearchSpec; o.NamePos:=i.NamePos; end; Procedure FindClose(Var f: SearchRec); var wf: TWasiSearchRec; Begin SearchRec2WasiSearchRec(f,wf); WasiFindClose(wf); WasiSearchRec2SearchRec(wf,f); End; Procedure FindNext(Var f: SearchRec); var wf: TWasiSearchRec; Begin SearchRec2WasiSearchRec(f,wf); doserror:=WasiFindNext(wf); WasiSearchRec2SearchRec(wf,f); End; Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec); var wf: TWasiSearchRec; Begin SearchRec2WasiSearchRec(f,wf); doserror:=WasiFindFirst(Path,Attr,wf); WasiSearchRec2SearchRec(wf,f); End; {****************************************************************************** --- File --- ******************************************************************************} Function FSearch(path: pathstr; dirlist: shortstring): pathstr; var p1 : longint; s : searchrec; newdir : pathstr; begin { No wildcards allowed in these things } if (pos('?',path)<>0) or (pos('*',path)<>0) then begin fsearch:=''; exit; end; { check if the file specified exists } findfirst(path,anyfile and not(directory),s); if doserror=0 then begin findclose(s); fsearch:=path; exit; end; findclose(s); //{ allow slash as backslash } //DoDirSeparators(dirlist); repeat p1:=pos(';',dirlist); if p1<>0 then begin newdir:=copy(dirlist,1,p1-1); delete(dirlist,1,p1); end else begin newdir:=dirlist; dirlist:=''; end; if (newdir<>'') and (not (newdir[length(newdir)] in (AllowDirectorySeparators+[':']))) then newdir:=newdir+DirectorySeparator; findfirst(newdir+path,anyfile and not(directory),s); if doserror=0 then newdir:=newdir+path else newdir:=''; findclose(s); until (dirlist='') or (newdir<>''); fsearch:=newdir; end; Procedure GetFAttr(var f; var attr : word); Var pr: RawByteString; fd: __wasi_fd_t; Info: __wasi_filestat_t; Begin DosError:=0; Attr:=0; if ConvertToFdRelativePath(textrec(f).name,fd,pr)<>0 then begin DosError:=3; exit; end; if __wasi_path_filestat_get(fd,__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,PAnsiChar(pr),length(pr),@Info)<>__WASI_ERRNO_SUCCESS then begin DosError:=3; exit; end; if Info.filetype=__WASI_FILETYPE_DIRECTORY then Attr:=$10; if filerec(f).name[0]='.' then Attr:=Attr or $2; end; Procedure getftime (var f; var time : longint); Var res: __wasi_errno_t; Info: __wasi_filestat_t; DT: DateTime; Begin doserror:=0; res:=__wasi_fd_filestat_get(filerec(f).handle,@Info); if res<>__WASI_ERRNO_SUCCESS then begin Time:=0; case res of __WASI_ERRNO_ACCES, __WASI_ERRNO_NOTCAPABLE: doserror:=5; else doserror:=6; end; exit end else WasiDateToDt(Info.mtim,DT); PackTime(DT,Time); End; Procedure setftime(var f; time : longint); Var DT: DateTime; modtime: UInt64; pr: RawByteString; fd: __wasi_fd_t; Begin doserror:=0; UnPackTime(Time,DT); modtime:=DTToWasiDate(DT); if ConvertToFdRelativePath(textrec(f).name,fd,pr)<>0 then begin doserror:=3; exit; end; if __wasi_path_filestat_set_times(fd,0,PAnsiChar(pr),length(pr),0,modtime, __WASI_FSTFLAGS_MTIM or __WASI_FSTFLAGS_ATIM_NOW)<>__WASI_ERRNO_SUCCESS then doserror:=3; End; {****************************************************************************** --- Environment --- ******************************************************************************} Function EnvCount: Longint; var envcnt : longint; p : PPAnsiChar; Begin envcnt:=0; p:=envp; {defined in system} if p<>nil then while p^<>nil do begin inc(envcnt); inc(p); end; EnvCount := envcnt End; Function EnvStr (Index: longint): ShortString; Var i : longint; p : PPAnsiChar; Begin if (Index <= 0) or (envp=nil) then envstr:='' else begin p:=envp; {defined in system} i:=1; while (inil) do begin inc(i); inc(p); end; if p^=nil then envstr:='' else envstr:=strpas(p^) end; end; Function GetEnv(EnvVar: ShortString): ShortString; var hp : PPAnsiChar; hs : string; eqpos : longint; Begin getenv:=''; hp:=envp; if hp<>nil then while assigned(hp^) do begin hs:=strpas(hp^); eqpos:=pos('=',hs); if copy(hs,1,eqpos-1)=envvar then begin getenv:=copy(hs,eqpos+1,length(hs)-eqpos); break; end; inc(hp); end; End; Procedure setfattr (var f;attr : word); Begin {! No WASI equivalent !} { Fail for setting VolumeId } if (attr and VolumeID)<>0 then doserror:=5; End; {****************************************************************************** --- Initialization --- ******************************************************************************} //Finalization // FreeDriveStr; End.