fpc/rtl/morphos/dos.pp

1380 lines
35 KiB
ObjectPascal

{
$Id$
This file is part of the Free Pascal run time library.
Copyright (c) 2004 by Karoly Balogh for Genesi Sarl
Heavily based on the Amiga/m68k RTL by Nils Sjoholm and
Carl Eric Codere
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.
**********************************************************************}
unit Dos;
{--------------------------------------------------------------------}
{ LEFT TO DO: }
{--------------------------------------------------------------------}
{ o DiskFree / Disksize don't work as expected }
{ o Implement EnvCount,EnvStr }
{ o FindFirst should only work with correct attributes }
{--------------------------------------------------------------------}
Interface
Const
{Bitmasks for CPU Flags}
fcarry = $0001;
fparity = $0004;
fauxiliary = $0010;
fzero = $0040;
fsign = $0080;
foverflow = $0800;
{Bitmasks for file attribute}
readonly = $01;
hidden = $02;
sysfile = $04;
volumeid = $08;
directory = $10;
archive = $20;
anyfile = $3F;
{File Status}
fmclosed = $D7B0;
fminput = $D7B1;
fmoutput = $D7B2;
fminout = $D7B3;
Type
ComStr = String[255]; { size increased to be more compatible with Unix}
PathStr = String[255]; { size increased to be more compatible with Unix}
DirStr = String[255]; { size increased to be more compatible with Unix}
NameStr = String[255]; { size increased to be more compatible with Unix}
ExtStr = String[255]; { size increased to be more compatible with Unix}
{
filerec.inc contains the definition of the filerec.
textrec.inc contains the definition of the textrec.
It is in a separate file to make it available in other units without
having to use the DOS unit for it.
}
{$i filerec.inc}
{$i textrec.inc}
Type
SearchRec = Packed Record
{ watch out this is correctly aligned for all processors }
{ don't modify. }
{ Replacement for Fill }
{0} AnchorPtr : Pointer; { Pointer to the Anchorpath structure }
{4} Fill: Array[1..15] of Byte; {future use}
{End of replacement for fill}
Attr : BYTE; {attribute of found file}
Time : LongInt; {last modify date of found file}
Size : LongInt; {file size of found file}
Name : String[255]; {name of found file}
End;
DateTime = packed record
Year: Word;
Month: Word;
Day: Word;
Hour: Word;
Min: Word;
Sec: word;
End;
{ Some ugly x86 registers... }
registers = packed record
case i : integer of
0 : (ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,f8,flags,fs,gs : word);
1 : (al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh : byte);
2 : (eax, ebx, ecx, edx, ebp, esi, edi : longint);
end;
Var
DosError : integer;
{Interrupt}
Procedure Intr(intno: byte; var regs: registers);
Procedure MSDos(var regs: registers);
{Info/Date/Time}
Function DosVersion: Word;
Procedure GetDate(var year, month, mday, wday: word);
Procedure GetTime(var hour, minute, second, sec100: word);
procedure SetDate(year,month,day: word);
Procedure SetTime(hour,minute,second,sec100: word);
Procedure UnpackTime(p: longint; var t: datetime);
Procedure PackTime(var t: datetime; var p: longint);
{Exec}
Procedure Exec(const path: pathstr; const comline: comstr);
Function DosExitCode: word;
{Disk}
Function DiskFree(drive: byte) : longint;
Function DiskSize(drive: byte) : longint;
Procedure FindFirst(path: pathstr; attr: word; var f: searchRec);
Procedure FindNext(var f: searchRec);
Procedure FindClose(Var f: SearchRec);
{File}
Procedure GetFAttr(var f; var attr: word);
Procedure GetFTime(var f; var time: longint);
Function FSearch(path: pathstr; dirlist: string): pathstr;
Function FExpand(const path: pathstr): pathstr;
Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
{Environment}
Function EnvCount: longint;
Function EnvStr(index: integer): string;
Function GetEnv(envvar: string): string;
{Misc}
Procedure SetFAttr(var f; attr: word);
Procedure SetFTime(var f; time: longint);
Procedure GetCBreak(var breakvalue: boolean);
Procedure SetCBreak(breakvalue: boolean);
Procedure GetVerify(var verify: boolean);
Procedure SetVerify(verify: boolean);
{Do Nothing Functions}
Procedure SwapVectors;
Procedure GetIntVec(intno: byte; var vector: pointer);
Procedure SetIntVec(intno: byte; vector: pointer);
Procedure Keep(exitcode: word);
implementation
const
DaysPerMonth : Array[1..12] of ShortInt =
(031,028,031,030,031,030,031,031,030,031,030,031);
DaysPerYear : Array[1..12] of Integer =
(031,059,090,120,151,181,212,243,273,304,334,365);
DaysPerLeapYear : Array[1..12] of Integer =
(031,060,091,121,152,182,213,244,274,305,335,366);
SecsPerYear : LongInt = 31536000;
SecsPerLeapYear : LongInt = 31622400;
SecsPerDay : LongInt = 86400;
SecsPerHour : Integer = 3600;
SecsPerMinute : ShortInt = 60;
TICKSPERSECOND = 50;
type
BPTR = Longint;
BSTR = Longint;
const
LDF_READ = 1;
LDF_DEVICES = 4;
ERROR_NO_MORE_ENTRIES = 232;
FIBF_SCRIPT = 64; { program is a script }
FIBF_PURE = 32; { program is reentrant }
FIBF_ARCHIVE = 16; { cleared whenever file is changed }
FIBF_READ = 8; { ignoed by old filesystem }
FIBF_WRITE = 4; { ignored by old filesystem }
FIBF_EXECUTE = 2; { ignored by system, used by shell }
FIBF_DELETE = 1; { prevent file from being deleted }
SHARED_LOCK = -2;
{******************************************************************************
--- Internal routines ---
******************************************************************************}
function Lock(const name : string;
accessmode : Longint) : BPTR;
var
buffer: Array[0..255] of char;
Begin
move(name[1],buffer,length(name));
buffer[length(name)]:=#0;
lock:=dos_Lock(buffer,accessmode);
end;
FUNCTION BADDR(bval : BPTR): POINTER;
BEGIN
BADDR := POINTER( bval shl 2);
END;
Procedure AmigaToDt(SecsPast: LongInt; Var Dt: DateTime);
var
cd : pClockData;
Begin
New(cd);
util_Amiga2Date(SecsPast,cd);
Dt.sec := cd^.sec;
Dt.min := cd^.min;
Dt.hour := cd^.hour;
Dt.day := cd^.mday;
Dt.month := cd^.month;
Dt.year := cd^.year;
Dispose(cd);
End;
Function DtToAmiga(DT: DateTime): LongInt;
var
cd : pClockData;
temp : Longint;
Begin
New(cd);
cd^.sec := Dt.sec;
cd^.min := Dt.min;
cd^.hour := Dt.hour;
cd^.mday := Dt.day;
cd^.month := Dt.month;
cd^.year := Dt.year;
temp := util_Date2Amiga(cd);
Dispose(cd);
DtToAmiga := temp;
end;
function IsLeapYear(Source : Word) : Boolean;
Begin
{$WARNING FIX ME!!! Leap year calculation is "somewhat" buggy.}
If (Source Mod 4 = 0) Then
IsLeapYear := True
Else
IsLeapYear := False;
End;
Procedure Amiga2DateStamp(Date : LongInt; Var TotalDays,Minutes,Ticks: longint);
{ Converts a value in seconds past 1978 to a value in AMIGA DateStamp format }
{ Taken from SWAG and modified to work with the Amiga format - CEC }
Var
LocalDate : LongInt; Done : Boolean; TotDays : Integer;
Y: Word;
H: Word;
Min: Word;
S : Word;
Begin
Y := 1978; H := 0; Min := 0; S := 0;
TotalDays := 0;
Minutes := 0;
Ticks := 0;
LocalDate := Date;
Done := False;
While Not Done Do
Begin
If LocalDate >= SecsPerYear Then
Begin
Inc(Y,1);
Dec(LocalDate,SecsPerYear);
Inc(TotalDays,DaysPerYear[12]);
End
Else
Done := True;
If (IsLeapYear(Y+1)) And (LocalDate >= SecsPerLeapYear) And
(Not Done) Then
Begin
Inc(Y,1);
Dec(LocalDate,SecsPerLeapYear);
Inc(TotalDays,DaysPerLeapYear[12]);
End;
End; { END WHILE }
Done := False;
TotDays := LocalDate Div SecsPerDay;
{ Total number of days }
TotalDays := TotalDays + TotDays;
Dec(LocalDate,TotDays*SecsPerDay);
{ Absolute hours since start of day }
H := LocalDate Div SecsPerHour;
{ Convert to minutes }
Minutes := H*60;
Dec(LocalDate,(H * SecsPerHour));
{ Find the remaining minutes to add }
Min := LocalDate Div SecsPerMinute;
Dec(LocalDate,(Min * SecsPerMinute));
Minutes:=Minutes+Min;
{ Find the number of seconds and convert to ticks }
S := LocalDate;
Ticks:=TICKSPERSECOND*S;
End;
function SetProtection(const name: string; mask:longint): Boolean;
var
buffer : array[0..255] of Char;
begin
move(name[1],buffer,length(name));
buffer[length(name)]:=#0;
SetProtection:=dos_SetProtection(buffer,mask);
end;
function SetFileDate(name: string; p : PDateStamp): Boolean;
var buffer : array[0..255] of Char;
begin
move(name[1],buffer,length(name));
buffer[length(name)]:=#0;
SetFileDate:=dos_SetFileDate(buffer,p);
end;
{******************************************************************************
--- Dos Interrupt ---
******************************************************************************}
Procedure Intr (intno: byte; var regs: registers);
Begin
{ Does not apply to MorphOS - not implemented }
End;
Procedure SwapVectors;
Begin
{ Does not apply to MorphOS - Do Nothing }
End;
Procedure msdos(var regs : registers);
Begin
{ ! Not implemented in MorphOS ! }
End;
Procedure getintvec(intno : byte;var vector : pointer);
Begin
{ ! Not implemented in MorphOS ! }
End;
Procedure setintvec(intno : byte;vector : pointer);
Begin
{ ! Not implemented in MorphOS ! }
End;
{******************************************************************************
--- Info / Date / Time ---
******************************************************************************}
function DosVersion: Word;
var p: PLibrary;
begin
p:=PLibrary(MOS_DOSBase);
DosVersion:= p^.lib_Version or (p^.lib_Revision shl 8);
end;
{ Here are a lot of stuff just for setdate and settime }
Const
{ unit defintions }
UNIT_MICROHZ = 0;
UNIT_VBLANK = 1;
TIMERNAME : PChar = 'timer.device';
Type
ptimeval = ^ttimeval;
ttimeval = record
tv_secs : longint;
tv_micro : longint;
end;
ptimerequest = ^ttimerequest;
ttimerequest = record
tr_node : tIORequest;
tr_time : ttimeval;
end;
Const
{ IO_COMMAND to use for adding a timer }
CMD_NONSTD = 9;
TR_ADDREQUEST = CMD_NONSTD;
TR_GETSYSTIME = CMD_NONSTD + 1;
TR_SETSYSTIME = CMD_NONSTD + 2;
MEMF_PUBLIC = %000000000000000000000001;
MEMF_CLEAR = %000000010000000000000000;
{ To use any of the routines below, TimerBase must be set to point
to the timer.device, either by calling CreateTimer or by pulling
the device pointer from a valid TimeRequest, i.e.
TimerBase := TimeRequest.io_Device;
_after_ you have called OpenDevice on the timer.
}
var
TimerBase : Pointer;
procedure NewList (list: pList);
begin
with list^ do
begin
lh_Head := pNode(@lh_Tail);
lh_Tail := NIL;
lh_TailPred := pNode(@lh_Head)
end
end;
function CreateExtIO (port: pMsgPort; size: Longint): pIORequest;
var
IOReq: pIORequest;
begin
IOReq := NIL;
if port <> NIL then
begin
IOReq := exec_AllocMem(size, MEMF_CLEAR or MEMF_PUBLIC);
if IOReq <> NIL then
begin
IOReq^.io_Message.mn_Node.ln_Type := 7;
IOReq^.io_Message.mn_Length := size;
IOReq^.io_Message.mn_ReplyPort := port;
end;
end;
CreateExtIO := IOReq;
end;
procedure DeleteExtIO (ioReq: pIORequest);
begin
if ioReq <> NIL then
begin
ioReq^.io_Message.mn_Node.ln_Type := $FF;
ioReq^.io_Message.mn_ReplyPort := pMsgPort(-1);
ioReq^.io_Device := pDevice(-1);
exec_FreeMem(ioReq, ioReq^.io_Message.mn_Length);
end
end;
function Createport(name : PChar; pri : longint): pMsgPort;
var
sigbit : ShortInt;
port : pMsgPort;
begin
sigbit := exec_AllocSignal(-1);
if sigbit = -1 then CreatePort := nil;
port := exec_Allocmem(sizeof(tMsgPort),MEMF_CLEAR or MEMF_PUBLIC);
if port = nil then begin
exec_FreeSignal(sigbit);
CreatePort := nil;
end;
with port^ do begin
if assigned(name) then
mp_Node.ln_Name := name
else mp_Node.ln_Name := nil;
mp_Node.ln_Pri := pri;
mp_Node.ln_Type := 4;
mp_Flags := 0;
mp_SigBit := sigbit;
mp_SigTask := exec_FindTask(nil);
end;
if assigned(name) then exec_AddPort(port)
else NewList(addr(port^.mp_MsgList));
CreatePort := port;
end;
procedure DeletePort (port: pMsgPort);
begin
if port <> NIL then
begin
if port^.mp_Node.ln_Name <> NIL then
exec_RemPort(port);
port^.mp_Node.ln_Type := $FF;
port^.mp_MsgList.lh_Head := pNode(-1);
exec_FreeSignal(port^.mp_SigBit);
exec_FreeMem(port, sizeof(tMsgPort));
end;
end;
Function Create_Timer(theUnit : longint) : pTimeRequest;
var
Error : longint;
TimerPort : pMsgPort;
TimeReq : pTimeRequest;
begin
TimerPort := CreatePort(Nil, 0);
if TimerPort = Nil then
Create_Timer := Nil;
TimeReq := pTimeRequest(CreateExtIO(TimerPort,sizeof(tTimeRequest)));
if TimeReq = Nil then begin
DeletePort(TimerPort);
Create_Timer := Nil;
end;
Error := exec_OpenDevice(TIMERNAME, theUnit, pIORequest(TimeReq), 0);
if Error <> 0 then begin
DeleteExtIO(pIORequest(TimeReq));
DeletePort(TimerPort);
Create_Timer := Nil;
end;
TimerBase := pointer(TimeReq^.tr_Node.io_Device);
Create_Timer := pTimeRequest(TimeReq);
end;
Procedure Delete_Timer(WhichTimer : pTimeRequest);
var
WhichPort : pMsgPort;
begin
WhichPort := WhichTimer^.tr_Node.io_Message.mn_ReplyPort;
if assigned(WhichTimer) then begin
exec_CloseDevice(pIORequest(WhichTimer));
DeleteExtIO(pIORequest(WhichTimer));
end;
if assigned(WhichPort) then
DeletePort(WhichPort);
end;
function set_new_time(secs, micro : longint): longint;
var
tr : ptimerequest;
begin
tr := create_timer(UNIT_MICROHZ);
{ non zero return says error }
if tr = nil then set_new_time := -1;
tr^.tr_time.tv_secs := secs;
tr^.tr_time.tv_micro := micro;
tr^.tr_node.io_Command := TR_SETSYSTIME;
exec_DoIO(pIORequest(tr));
delete_timer(tr);
set_new_time := 0;
end;
function get_sys_time(tv : ptimeval): longint;
var
tr : ptimerequest;
begin
tr := create_timer( UNIT_MICROHZ );
{ non zero return says error }
if tr = nil then get_sys_time := -1;
tr^.tr_node.io_Command := TR_GETSYSTIME;
exec_DoIO(pIORequest(tr));
{ structure assignment }
tv^ := tr^.tr_time;
delete_timer(tr);
get_sys_time := 0;
end;
Procedure GetDate(Var Year, Month, MDay, WDay: Word);
Var
cd : pClockData;
oldtime : ttimeval;
begin
New(cd);
get_sys_time(@oldtime);
util_Amiga2Date(oldtime.tv_secs,cd);
Year := cd^.year;
Month := cd^.month;
MDay := cd^.mday;
WDay := cd^.wday;
Dispose(cd);
end;
Procedure SetDate(Year, Month, Day: Word);
var
cd : pClockData;
oldtime : ttimeval;
Begin
new(cd);
get_sys_time(@oldtime);
util_Amiga2Date(oldtime.tv_secs,cd);
cd^.year := Year;
cd^.month := Month;
cd^.mday := Day;
set_new_time(util_Date2Amiga(cd),0);
dispose(cd);
End;
Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
Var
cd : pClockData;
oldtime : ttimeval;
begin
New(cd);
get_sys_time(@oldtime);
util_Amiga2Date(oldtime.tv_secs,cd);
Hour := cd^.hour;
Minute := cd^.min;
Second := cd^.sec;
Sec100 := oldtime.tv_micro div 10000;
Dispose(cd);
END;
Procedure SetTime(Hour, Minute, Second, Sec100: Word);
var
cd : pClockData;
oldtime : ttimeval;
Begin
new(cd);
get_sys_time(@oldtime);
util_Amiga2Date(oldtime.tv_secs,cd);
cd^.hour := Hour;
cd^.min := Minute;
cd^.sec := Second;
set_new_time(util_Date2Amiga(cd), Sec100 * 10000);
dispose(cd);
End;
Procedure unpacktime(p : longint;var t : datetime);
Begin
AmigaToDt(p,t);
End;
Procedure packtime(var t : datetime;var p : longint);
Begin
p := DtToAmiga(t);
end;
{******************************************************************************
--- Exec ---
******************************************************************************}
Var
LastDosExitCode: word;
Ver : Boolean;
Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
var
p : string;
buf: array[0..255] of char;
result : longint;
MyLock : longint;
i : Integer;
Begin
DosError := 0;
LastdosExitCode := 0;
p:=Path+' '+ComLine;
{ allow backslash as slash }
for i:=1 to length(p) do
if p[i]='\' then p[i]:='/';
Move(p[1],buf,length(p));
buf[Length(p)]:=#0;
{ Here we must first check if the command we wish to execute }
{ actually exists, because this is NOT handled by the }
{ _SystemTagList call (program will abort!!) }
{ Try to open with shared lock }
MyLock:=Lock(Path,SHARED_LOCK);
if MyLock <> 0 then
Begin
{ File exists - therefore unlock it }
dos_Unlock(MyLock);
result:=dos_SystemTagList(buf,nil);
{ on return of -1 the shell could not be executed }
{ probably because there was not enough memory }
if result = -1 then
DosError:=8
else
LastDosExitCode:=word(result);
end
else
DosError:=3;
End;
Function DosExitCode: Word;
Begin
DosExitCode:=LastdosExitCode;
End;
Procedure GetCBreak(Var BreakValue: Boolean);
Begin
breakvalue := system.BreakOn;
End;
Procedure SetCBreak(BreakValue: Boolean);
Begin
system.Breakon := BreakValue;
End;
Procedure GetVerify(Var Verify: Boolean);
Begin
verify:=ver;
End;
Procedure SetVerify(Verify: Boolean);
Begin
ver:=Verify;
End;
{******************************************************************************
--- Disk ---
******************************************************************************}
{ How to solve the problem with this: }
{ We could walk through the device list }
{ at startup to determine possible devices }
const
not_to_use_devs : array[0..12] of string =(
'DF0:',
'DF1:',
'DF2:',
'DF3:',
'PED:',
'PRJ:',
'PIPE:',
'RAM:',
'CON:',
'RAW:',
'SER:',
'PAR:',
'PRT:');
var
deviceids : array[1..20] of byte;
devicenames : array[1..20] of string[20];
numberofdevices : Byte;
Function DiskFree(Drive: Byte): Longint;
Var
MyLock : BPTR;
Inf : pInfoData;
Free : Longint;
myproc : pProcess;
OldWinPtr : Pointer;
Begin
Free := -1;
{ Here we stop systemrequesters to appear }
myproc := pProcess(exec_FindTask(nil));
OldWinPtr := myproc^.pr_WindowPtr;
myproc^.pr_WindowPtr := Pointer(-1);
{ End of systemrequesterstop }
New(Inf);
MyLock := Lock(devicenames[deviceids[Drive]],SHARED_LOCK);
If MyLock <> 0 then begin
if dos_Info(MyLock,Inf) then begin
Free := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock) -
(Inf^.id_NumBlocksUsed * Inf^.id_BytesPerBlock);
end;
dos_Unlock(MyLock);
end;
Dispose(Inf);
{ Restore systemrequesters }
myproc^.pr_WindowPtr := OldWinPtr;
diskfree := Free;
end;
Function DiskSize(Drive: Byte): Longint;
Var
MyLock : BPTR;
Inf : pInfoData;
Size : Longint;
myproc : pProcess;
OldWinPtr : Pointer;
Begin
Size := -1;
{ Here we stop systemrequesters to appear }
myproc := pProcess(exec_FindTask(nil));
OldWinPtr := myproc^.pr_WindowPtr;
myproc^.pr_WindowPtr := Pointer(-1);
{ End of systemrequesterstop }
New(Inf);
MyLock := Lock(devicenames[deviceids[Drive]],SHARED_LOCK);
If MyLock <> 0 then begin
if dos_Info(MyLock,Inf) then begin
Size := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock);
end;
dos_Unlock(MyLock);
end;
Dispose(Inf);
{ Restore systemrequesters }
myproc^.pr_WindowPtr := OldWinPtr;
disksize := Size;
end;
Procedure FindFirst(Path: PathStr; Attr: Word; Var f: SearchRec);
var
buf: Array[0..255] of char;
Anchor : pAnchorPath;
Result : Longint;
index : Integer;
s : string;
j : integer;
Begin
DosError:=0;
New(Anchor);
{----- allow backslash as slash -----}
for index:=1 to length(path) do
if path[index]='\' then path[index]:='/';
{ remove any dot characters and replace by their current }
{ directory equivalent. }
if pos('../',path) = 1 then
begin
getdir(0,s);
while pos('../',path) = 1 do
{ look for parent directory }
Begin
delete(path,1,3);
j:=length(s);
while (s[j] <> '/') AND (s[j] <> ':') AND (j > 0 ) do
dec(j);
if j > 0 then
s:=copy(s,1,j-1);
end;
if (length(s) <> 0) and (s[length(s)] <> ':') then
s:=s + '/';
path:=s+path;
end
else
if pos('./',path) = 1 then
{ look for current directory }
Begin
delete(path,1,2);
getdir(0,s);
if (s[length(s)] <> '/') and (s[length(s)] <> ':') then
s:=s+'/';
path:=s+path;
end;
{----- replace * by #? AmigaOs strings -----}
repeat
index:= pos('*',Path);
if index <> 0 then
Begin
delete(Path,index,1);
insert('#?',Path,index);
end;
until index =0;
{--------------------------------------------}
FillChar(Anchor^,sizeof(TAnchorPath),#0);
move(path[1],buf,length(path));
buf[length(path)]:=#0;
Result:=dos_MatchFirst(@buf,Anchor);
f.AnchorPtr:=Anchor;
if Result = ERROR_NO_MORE_ENTRIES then
DosError:=18
else
if Result <> 0 then
DosError:=3;
{ If there is an error, deallocate }
{ the anchorpath structure }
if DosError <> 0 then
Begin
dos_MatchEnd(Anchor);
if assigned(Anchor) then
Dispose(Anchor);
end
else
{-------------------------------------------------------------------}
{ Here we fill up the SearchRec attribute, but we also do check }
{ something else, if the it does not match the mask we are looking }
{ for we should go to the next file or directory. }
{-------------------------------------------------------------------}
Begin
with Anchor^.ap_Info do
Begin
f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
fib_Date.ds_Minute * 60 +
fib_Date.ds_Tick div 50;
{*------------------------------------*}
{* Determine if is a file or a folder *}
{*------------------------------------*}
if fib_DirEntryType > 0 then
f.attr:=f.attr OR DIRECTORY;
{*------------------------------------*}
{* Determine if Read only *}
{* Readonly if R flag on and W flag *}
{* off. *}
{* Should we check also that EXEC *}
{* is zero? for read only? *}
{*------------------------------------*}
if ((fib_Protection and FIBF_READ) <> 0)
AND ((fib_Protection and FIBF_WRITE) = 0)
then
f.attr:=f.attr or READONLY;
f.Name := strpas(fib_FileName);
f.Size := fib_Size;
end; { end with }
end;
End;
Procedure FindNext(Var f: SearchRec);
var
Result: longint;
Anchor : pAnchorPath;
Begin
DosError:=0;
Result:=dos_MatchNext(f.AnchorPtr);
if Result = ERROR_NO_MORE_ENTRIES then
DosError:=18
else
if Result <> 0 then
DosError:=3;
{ If there is an error, deallocate }
{ the anchorpath structure }
if DosError <> 0 then
Begin
dos_MatchEnd(f.AnchorPtr);
if assigned(f.AnchorPtr) then
{Dispose}FreeMem(f.AnchorPtr);
end
else
{ Fill up the Searchrec information }
{ and also check if the files are with }
{ the correct attributes }
Begin
Anchor:=pAnchorPath(f.AnchorPtr);
with Anchor^.ap_Info do
Begin
f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
fib_Date.ds_Minute * 60 +
fib_Date.ds_Tick div 50;
{*------------------------------------*}
{* Determine if is a file or a folder *}
{*------------------------------------*}
if fib_DirEntryType > 0 then
f.attr:=f.attr OR DIRECTORY;
{*------------------------------------*}
{* Determine if Read only *}
{* Readonly if R flag on and W flag *}
{* off. *}
{* Should we check also that EXEC *}
{* is zero? for read only? *}
{*------------------------------------*}
if ((fib_Protection and FIBF_READ) <> 0)
AND ((fib_Protection and FIBF_WRITE) = 0)
then
f.attr:=f.attr or READONLY;
f.Name := strpas(fib_FileName);
f.Size := fib_Size;
end; { end with }
end;
End;
Procedure FindClose(Var f: SearchRec);
begin
end;
{******************************************************************************
--- File ---
******************************************************************************}
Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
var
I: Word;
begin
{ allow backslash as slash }
for i:=1 to length(path) do
if path[i]='\' then path[i]:='/';
I := Length(Path);
while (I > 0) and not ((Path[I] = '/') or (Path[I] = ':'))
do Dec(I);
if Path[I] = '/' then
dir := Copy(Path, 0, I)
else dir := Copy(Path,0,I);
if Length(Path) > Length(dir) then
name := Copy(Path, I + 1, Length(Path)-I)
else
name := '';
{ Remove extension }
if pos('.',name) <> 0 then
begin
ext:=copy(name,pos('.',name),length(name));
delete(name,pos('.',name),length(name));
end
else
ext := '';
end;
{$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
{$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
{$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
{$I fexpand.inc}
{$UNDEF FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
{$UNDEF FPC_FEXPAND_DRIVESEP_IS_ROOT}
{$UNDEF FPC_FEXPAND_NO_DEFAULT_PATHS}
Function fsearch(path : pathstr;dirlist : string) : pathstr;
var
i,p1 : longint;
s : searchrec;
newdir : pathstr;
begin
{ No wildcards allowed in these things }
if (pos('?',path)<>0) or (pos('*',path)<>0) then
fsearch:=''
else
begin
{ allow slash as backslash }
for i:=1 to length(dirlist) do
if dirlist[i]='\' then dirlist[i]:='/';
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 ['/',':'])) then
newdir:=newdir+'/';
findfirst(newdir+path,anyfile,s);
if doserror=0 then
newdir:=newdir+path
else
newdir:='';
until (dirlist='') or (newdir<>'');
fsearch:=newdir;
end;
end;
Procedure getftime (var f; var time : longint);
{
This function returns a file's date and time as the number of
seconds after January 1, 1978 that the file was created.
}
var
FInfo : pFileInfoBlock;
FTime : Longint;
FLock : Longint;
Str : String;
i : integer;
begin
DosError:=0;
FTime := 0;
Str := StrPas(filerec(f).name);
for i:=1 to length(Str) do
if str[i]='\' then str[i]:='/';
FLock := Lock(Str, SHARED_LOCK);
IF FLock <> 0 then begin
New(FInfo);
if dos_Examine(FLock, FInfo) then begin
with FInfo^.fib_Date do
FTime := ds_Days * (24 * 60 * 60) +
ds_Minute * 60 +
ds_Tick div 50;
end else begin
FTime := 0;
end;
dos_Unlock(FLock);
Dispose(FInfo);
end
else
DosError:=6;
time := FTime;
end;
Procedure setftime(var f; time : longint);
var
DateStamp: pDateStamp;
Str: String;
i: Integer;
Days, Minutes,Ticks: longint;
FLock: longint;
Begin
new(DateStamp);
Str := StrPas(filerec(f).name);
for i:=1 to length(Str) do
if str[i]='\' then str[i]:='/';
{ Check first of all, if file exists }
FLock := Lock(Str, SHARED_LOCK);
IF FLock <> 0 then
begin
dos_Unlock(FLock);
Amiga2DateStamp(time,Days,Minutes,ticks);
DateStamp^.ds_Days:=Days;
DateStamp^.ds_Minute:=Minutes;
DateStamp^.ds_Tick:=Ticks;
if SetFileDate(Str,DateStamp) then
DosError:=0
else
DosError:=6;
end
else
DosError:=2;
if assigned(DateStamp) then Dispose(DateStamp);
End;
Procedure getfattr(var f; var attr : word);
var
info : pFileInfoBlock;
MyLock : Longint;
flags: word;
Str: String;
i: integer;
Begin
DosError:=0;
flags:=0;
New(info);
Str := StrPas(filerec(f).name);
for i:=1 to length(Str) do
if str[i]='\' then str[i]:='/';
{ open with shared lock to check if file exists }
MyLock:=Lock(Str,SHARED_LOCK);
if MyLock <> 0 then
Begin
dos_Examine(MyLock,info);
{*------------------------------------*}
{* Determine if is a file or a folder *}
{*------------------------------------*}
if info^.fib_DirEntryType > 0 then
flags:=flags OR DIRECTORY;
{*------------------------------------*}
{* Determine if Read only *}
{* Readonly if R flag on and W flag *}
{* off. *}
{* Should we check also that EXEC *}
{* is zero? for read only? *}
{*------------------------------------*}
if ((info^.fib_Protection and FIBF_READ) <> 0)
AND ((info^.fib_Protection and FIBF_WRITE) = 0)
then
flags:=flags OR ReadOnly;
dos_Unlock(mylock);
end
else
DosError:=3;
attr:=flags;
Dispose(info);
End;
Procedure setfattr (var f;attr : word);
var
flags: longint;
MyLock : longint;
str: string;
i: integer;
Begin
DosError:=0;
flags:=FIBF_WRITE;
{ open with shared lock }
Str := StrPas(filerec(f).name);
for i:=1 to length(Str) do
if str[i]='\' then str[i]:='/';
MyLock:=Lock(Str,SHARED_LOCK);
{ By default files are read-write }
if attr AND ReadOnly <> 0 then
{ Clear the Fibf_write flags }
flags:=FIBF_READ;
if MyLock <> 0 then
Begin
dos_Unlock(MyLock);
if Not SetProtection(Str,flags) then
DosError:=5;
end
else
DosError:=3;
End;
{******************************************************************************
--- Environment ---
******************************************************************************}
var
StrofPaths : string[255];
function getpathstring: string;
var
f : text;
s : string;
found : boolean;
temp : string[255];
begin
found := true;
temp := '';
assign(f,'ram:makepathstr');
rewrite(f);
writeln(f,'path >ram:temp.lst');
close(f);
exec('c:protect','ram:makepathstr sarwed');
exec('C:execute','ram:makepathstr');
exec('c:delete','ram:makepathstr quiet');
assign(f,'ram:temp.lst');
reset(f);
{ skip the first line, garbage }
if not eof(f) then readln(f,s);
while not eof(f) do begin
readln(f,s);
if found then begin
temp := s;
found := false;
end else begin;
if (length(s) + length(temp)) < 255 then
temp := temp + ';' + s;
end;
end;
close(f);
exec('C:delete','ram:temp.lst quiet');
getpathstring := temp;
end;
Function EnvCount: Longint;
{ HOW TO GET THIS VALUE: }
{ Each time this function is called, we look at the }
{ local variables in the Process structure (2.0+) }
{ And we also read all files in the ENV: directory }
Begin
EnvCount := 0;
End;
Function EnvStr(Index: Integer): String;
Begin
EnvStr:='';
End;
function GetEnv(envvar : String): String;
var
bufarr : array[0..255] of char;
strbuffer : array[0..255] of char;
temp : Longint;
begin
if UpCase(envvar) = 'PATH' then begin
if StrOfpaths = '' then StrOfPaths := GetPathString;
GetEnv := StrofPaths;
end else begin
move(envvar,strbuffer,length(envvar));
strbuffer[length(envvar)] := #0;
temp := dos_GetVar(strbuffer,bufarr,255,$100);
if temp = -1 then
GetEnv := ''
else GetEnv := StrPas(bufarr);
end;
end;
{******************************************************************************
--- Not Supported ---
******************************************************************************}
Procedure keep(exitcode : word);
Begin
{ ! Not implemented in Linux ! }
End;
procedure AddDevice(str : String);
begin
inc(numberofdevices);
deviceids[numberofdevices] := numberofdevices;
devicenames[numberofdevices] := str;
end;
function MakeDeviceName(str : pchar): string;
var
temp : string[20];
begin
temp := strpas(str);
temp := temp + ':';
MakeDeviceName := temp;
end;
function IsInDeviceList(str : string): boolean;
var
i : byte;
theresult : boolean;
begin
theresult := false;
for i := low(not_to_use_devs) to high(not_to_use_devs) do
begin
if str = not_to_use_devs[i] then begin
theresult := true;
break;
end;
end;
IsInDeviceList := theresult;
end;
function BSTR2STRING(s : BSTR): pchar;
begin
BSTR2STRING := Pointer(Longint(BADDR(s))+1);
end;
procedure ReadInDevices;
var
dl : pDosList;
temp : pchar;
str : string[20];
begin
dl := dos_LockDosList(LDF_DEVICES or LDF_READ );
repeat
dl := dos_NextDosEntry(dl,LDF_DEVICES );
if dl <> nil then begin
temp := BSTR2STRING(dl^.dol_Name);
str := MakeDeviceName(temp);
if not IsInDeviceList(str) then
AddDevice(str);
end;
until dl = nil;
dos_UnLockDosList(LDF_DEVICES or LDF_READ );
end;
Begin
DosError:=0;
ver := TRUE;
numberofdevices := 0;
StrOfPaths := '';
AddDevice('DF0:');
AddDevice('DF1:');
AddDevice('DF2:');
AddDevice('DF3:');
ReadInDevices;
End.
{
$Log$
Revision 1.1 2004-05-12 20:27:29 karoly
* first implementation of MorphOS DOS unit, based on Amiga version
}