FPPS4/tools/vop_generator/vop_generator.lpr

728 lines
15 KiB
Plaintext

uses
Classes,
SysUtils;
type
TChars=Set of AnsiChar;
Function CountOf(var Value:RawByteString;Delimiters:TChars):SizeUInt;
Var
i:SizeUInt;
begin
Result:=0;
if Length(Value)>0 then
begin
For i:=1 to Length(Value) do
begin
if (Value[i] in Delimiters) then Inc(Result);
end;
end;
end;
procedure DelChars(var Value:RawByteString;Delimiters:TChars);
Var
i:SizeUInt;
begin
if Length(Value)>0 then
begin
i:=1;
While (i<=Length(Value)) do
begin
if (Value[i] in Delimiters) then
begin
System.Delete(Value,i,1);
end else
begin
Inc(i);
end;
end;
end;
end;
function SpaceChars(b:byte;ch:char):RawByteString;
begin
SetLength(Result,b);
FillChar(Result[1],b,ch);
end;
procedure TrimComm(var Value:RawByteString;Delimiters:TChars);
Var
i:SizeUInt;
begin
if Length(Value)>0 then
begin
For i:=1 to Length(Value) do
begin
if (Value[i] in Delimiters) then
begin
System.Delete(Value,i,Length(Value)-i+1);
Exit;
end;
end;
end;
end;
function FetchAny(var Value:RawByteString;Delimiters,Quotations:TChars):RawByteString;
Var
i:SizeUInt;
Quote:AnsiChar;
State:Byte;
begin
Result:='';
Quote:=#0;
State:=0;
if Length(Value)>0 then
begin
For i:=1 to Length(Value) do
begin
case State of
0:begin
if (Value[i] in Quotations) then
begin
State:=2;
Quote:=Value[i];
end else
if (Value[i] in Delimiters) then
begin
end else
begin
Result:=Result+Value[i];
State:=1;
end;
end;
1:begin
if (Value[i] in Quotations) then
begin
State:=2;
Quote:=Value[i];
end else
if (Value[i] in Delimiters) then
begin
System.Delete(Value,1,i);
Exit;
end else
begin
Result:=Result+Value[i];
end;
end;
2:begin
if Value[i]=Quote then
begin
State:=3;
end else
begin
Result:=Result+Value[i];
end;
end;
3:begin
if Value[i]=Quote then
begin
State:=2;
Result:=Result+Quote;
end else
if (Value[i] in Delimiters) then
begin
System.Delete(Value,1,i);
Exit;
end else
begin
State:=1;
Quote:=#0;
Result:=Result+Value[i];
end;
end;
end;
end;
Value:='';
end;
end;
type
TEnum=class(TStringList)
public
name:RawByteString;
namelen:SizeUInt;
pre :RawByteString;
post:RawByteString;
end;
var
EnumList:TStringList;
function FixFieldName(const S:RawByteString):RawByteString;
begin
Case S of
'type' ,
'label',
'file' ,
'a' ,
'v' ,
's' :Result:='_'+S;
else
Result:=S;
end;
end;
function FixFuncName(const S:RawByteString):RawByteString;
begin
Case S of
'vop_lock1':Result:='vop_lock';
else
Result:=S;
end;
end;
Procedure load_if(const fname:RawByteString);
var
L:TStringList;
i,x:Integer;
S,Name:RawByteString;
pre,post:RawByteString;
releflags:RawByteString;
vpp_offset:RawByteString;
rele:ptruint;
F:THandle;
Enum:TEnum;
state:Integer;
links,maxlen:SizeUInt;
vpnum:Integer;
begin
EnumList:=TStringList.Create;
state:=0;
pre :='';
post:='';
L:=TStringList.Create;
L.LoadFromFile(fname);
For i:=0 to L.Count -1 do
begin
S:=L.Strings[i];
TrimComm(S,['#']);
Name:=FetchAny(S,[' ',#9],[]);
Case Name of
'' :;
'%%':;
'%!':begin //pre/post
Name:=FetchAny(S,[' ',#9],[]); //enum name
Name:=FetchAny(S,[' ',#9],[]); //cmd
//exclude
Case S of
'vop_strategy_pre',
'vop_lock_pre',
'vop_lock_post',
'vop_unlock_pre',
'vop_unlock_post':S:='';
else;
end;
Case Name of
'pre' :pre :=S;
'post':post:=S;
else;
end;
end;
'};':begin //close
state:=0;
pre :='';
post:='';
Enum:=nil;
end;
else
Case state of
0:begin //open
Case Name of
'vop_cachedlookup' :state:=2; //skip
'vop_advise' :state:=2; //skip
'vop_is_text' :state:=2; //skip
'vop_set_text' :state:=2; //skip
'vop_unset_text' :state:=2; //skip
'vop_get_writecount':state:=2; //skip
'vop_add_writecount':state:=2; //skip
'vop_setlabel' :state:=2; //skip
'vop_getacl' :state:=2; //skip
'vop_setacl' :state:=2; //skip
'vop_aclcheck' :state:=2; //skip
'vop_closeextattr' :state:=2; //skip
'vop_getextattr' :state:=2; //skip
'vop_listextattr' :state:=2; //skip
'vop_openextattr' :state:=2; //skip
'vop_deleteextattr' :state:=2; //skip
'vop_setextattr' :state:=2; //skip
'vop_spare4' :state:=2; //skip
'vop_spare5' :state:=2; //skip
else
begin
Enum:=TEnum.Create;
Enum.name:=name;
Enum.NameValueSeparator:=':';
Enum.pre :=pre;
Enum.post:=post;
EnumList.AddObject(Enum.name,Enum);
state:=1;
end;
end;
end;
1:begin //value
rele:=0;
repeat
case Name of
'IN':;
'OUT':;
'INOUT':;
'WILLRELE':rele:=1;
'struct':;
'const':;
else
Break;
end;
Name:=FetchAny(S,[' ',#9],[]);
until false;
Case Name of
'thread':Continue; //skip
'ucred' :Continue; //skip
end;
links:=CountOf(S,['*']);
DelChars(S,['*',';']);
S:=Trim(S);
Case Name of
'int' :Name:=SpaceChars(links,'P')+'Integer';
'void' :Name:=SpaceChars(links-1,'P')+'Pointer';
'u_long',
'register_t',
'vm_ooffset_t',
'size_t',
'off_t' :Name:=SpaceChars(links,'P')+'PtrUint';
'char' :Name:=SpaceChars(links,'P')+'Char';
else
begin
if (links<>0) then
Name:=SpaceChars(links,'p')+'_'+Name;
end;
end;
Case S of
'end' :S:='__end';
else;
end;
if (Length(S)>Enum.namelen) then Enum.namelen:=Length(S);
Enum.AddPair(S,Name,TObject(rele));
Writeln(S,':',Name);
end;
end;
end;
end;
L.Free;
F:=FileCreate(ChangeFileExt(fname,'.pas'));
S:='{This file is automatically generated by "vop_generator"}'#13#10;
S:=S+#13#10;
S:=S+'unit '+ChangeFileExt(ExtractFileName(fname),'')+';'#13#10;
S:=S+#13#10;
S:=S+'interface'#13#10;
S:=S+#13#10;
S:=S+'{$mode objfpc}{$H+}'#13#10;
S:=S+'{$CALLING SysV_ABI_CDecl}'#13#10;
S:=S+#13#10;
S:=S+'uses'#13#10;
S:=S+' sys_event,'#13#10;
S:=S+' vnode,'#13#10;
S:=S+' vnamei,'#13#10;
S:=S+' vfile,'#13#10;
S:=S+' vuio,'#13#10;
S:=S+' vmount,'#13#10;
S:=S+' vfcntl,'#13#10;
S:=S+' vsocketvar;'#13#10;
S:=S+#13#10;
S:=S+'type'#13#10;
S:=S+' PPPtrUint =^PPtrUint;'#13#10;
S:=S+' pp_bufobj =Pointer;'#13#10;
S:=S+' daddr_t =PtrUint;'#13#10;
S:=S+' p_daddr_t =PPtrUint;'#13#10;
S:=S+' p_buf =Pointer;'#13#10;
S:=S+' p_task =Pointer;'#13#10;
S:=S+' p_cluster_save=Pointer;'#13#10;
S:=S+' p_vm_page_t =Pointer;'#13#10;
//S:=S+' acl_type_t =Integer;'#13#10;
//S:=S+' p_acl =Pointer;'#13#10;
//S:=S+' p_label =Pointer;'#13#10;
S:=S+#13#10;
FileWrite(F,Pchar(S)^,Length(S));
maxlen:=0;
//records
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
S:=' p_'+Enum.name+'_args=^'+Enum.name+'_args;'#13#10;
S:=S+' '+Enum.name+'_args=record'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
if (Length(Enum.name)>maxlen) then maxlen:=Length(Enum.name);
if Length('gen')>Enum.namelen then Enum.namelen:=Length('gen');
S:=' a_gen'+Space(Enum.namelen-Length('gen'))+':p_vnodeop_desc;'#13#10;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=S+' a_'+Name+Space(Enum.namelen-Length(Name))+':'+Enum.ValueFromIndex[x]+';'#13#10;
end;
S:=S+' end;'#13#10#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
//callbacks
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
S:=' '+Enum.name+'_t'+Space(maxlen-Length(Enum.name))+'=function(ap:p_'+Enum.name+'_args):Integer;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//list
//For i:=0 to EnumList.Count-1 do
//begin
// Enum:=TEnum(EnumList.Objects[i]);
//
// S:='//'+Enum.name+Space(maxlen-Length(Enum.name))+':Pointer;'#13#10;
// FileWrite(F,Pchar(S)^,Length(S));
//end;
//S:=#13#10;
//FileWrite(F,Pchar(S)^,Length(S));
//functions header
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
Name:=FixFuncName(Enum.name);
Name:=Upcase(Name);
S:='function '+Name+Space(maxlen-Length(Name))+'(';
FileWrite(F,Pchar(S)^,Length(S));
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=FixFieldName(Name)+':'+Enum.ValueFromIndex[x];
if (x<>Enum.Count-1) then
begin
S:=S+';';
end;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:='):Integer;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
//const
S:=#13#10'const'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//vp_offsets
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
S:=' '+Enum.name+'_vp_offsets'+Space(maxlen-Length(Enum.name))+':array[0..';
//calc count
vpnum:=0;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
Inc(vpnum);
end;
end;
Assert(vpnum<>0);
S:=S+IntToStr(vpnum)+'] of Byte=(';
//offsets
vpnum:=0;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
if (vpnum<>0) then
begin
S:=S+',';
end;
Name:=Enum.Names[x];
Name:='a_'+Name;
S:=S+'Byte(ptrint(@p_'+Enum.name+'_args(nil)^.'+Name+'))';
Inc(vpnum);
end;
end;
S:=S+',Byte(-1));'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
S:=S+' vop_default_desc:t_vnodeop_desc=('#13#10;
S:=S+' vdesc_name :''default'';'#13#10;
S:=S+' vdesc_call :nil;'#13#10;
S:=S+' vdesc_vp_offsets :nil;'#13#10;
S:=S+' vdesc_flags :0;'#13#10;
S:=S+' vdesc_vpp_offset :-1;'#13#10;
S:=S+' );'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//vnodeop_desc
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
//releflags
vpnum:=0;
releflags:='';
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='p_vnode') then
begin
if (Enum.Objects[x]<>nil) then //rele
begin
if (releflags<>'') then
begin
releflags:=releflags+' or ';
end;
releflags:=releflags+'VDESC_VP'+IntToStr(vpnum)+'_WILLRELE';
end;
Inc(vpnum);
end;
end;
//vppwillrele,vpp_offset
vpp_offset:='';
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.ValueFromIndex[x];
if (Name='pp_vnode') then
begin
if (vpp_offset='') then
begin
Name:=Enum.Names[x];
Name:='a_'+Name;
vpp_offset:='Integer(ptrint(@p_'+Enum.name+'_args(nil)^.'+Name+'))';
end;
if (Enum.Objects[x]<>nil) then //rele
begin
if (releflags<>'') then
begin
releflags:=releflags+' or ';
end;
releflags:=releflags+'VDESC_VPP_WILLRELE';
Break;
end;
end;
end;
if (releflags='') then releflags:='0';
if (vpp_offset='') then vpp_offset:='-1';
S:=#13#10;
S:=S+' '+Enum.name+'_desc:t_vnodeop_desc=('#13#10;
S:=S+' vdesc_name :'''+Enum.name+''';'#13#10;
S:=S+' vdesc_call :@p_vop_vector(nil)^.'+Enum.name+';'#13#10;
S:=S+' vdesc_vp_offsets :@'+Enum.name+'_vp_offsets;'#13#10;
S:=S+' vdesc_flags :'+releflags+';'#13#10;
S:=S+' vdesc_vpp_offset :'+vpp_offset+';'#13#10;
S:=S+' );'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=#13#10;
S:=S+'implementation'#13#10;
S:=S+#13#10;
S:=S+'uses'#13#10;
S:=S+' errno,'#13#10;
S:=S+' vfs_subr;'#13#10;
S:=S+#13#10;
S:=S+'function get_vp_cb(vp:p_vnode;offset:Pointer):Pointer; inline;'#13#10;
S:=S+'var'#13#10;
S:=S+' v:p_vop_vector;'#13#10;
S:=S+' p:Pointer;'#13#10;
S:=S+'begin'#13#10;
S:=S+' Result:=nil;'#13#10;
S:=S+' if (vp=nil) then Exit;'#13#10;
S:=S+' v:=vp^.v_op;'#13#10;
S:=S+' while (v<>nil) do'#13#10;
S:=S+' begin'#13#10;
S:=S+' p:=PPointer(Pointer(v)+ptrint(offset))^;'#13#10;
S:=S+' if (p<>nil) then'#13#10;
S:=S+' begin'#13#10;
S:=S+' Exit(p);'#13#10;
S:=S+' end;'#13#10;
S:=S+' p:=v^.vop_bypass;'#13#10;
S:=S+' if (p<>nil) then'#13#10;
S:=S+' begin'#13#10;
S:=S+' Exit(p);'#13#10;
S:=S+' end;'#13#10;
S:=S+' v:=v^.vop_default;'#13#10;
S:=S+' end;'#13#10;
S:=S+'end;'#13#10;
S:=S+#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//functions body
For i:=0 to EnumList.Count-1 do
begin
Enum:=TEnum(EnumList.Objects[i]);
//header
Name:=FixFuncName(Enum.name);
Name:=Upcase(Name);
S:='function '+Name+'(';
FileWrite(F,Pchar(S)^,Length(S));
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=FixFieldName(Name)+':'+Enum.ValueFromIndex[x];
if (x<>Enum.Count-1) then
begin
S:=S+';';
end;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:='):Integer;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//header
//var
S:='var'#13#10;
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=S+' osize,ooffset:Int64;'#13#10;
end;
S:=S+' c:Pointer;'#13#10;
S:=S+' a:'+Enum.name+'_args;'#13#10;
S:=S+' s:Boolean;'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//body
S:='begin'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
Name:=FixFuncName(Enum.name);
Name:=Upcase(Name);
S:=' c:=get_vp_cb('+FixFieldName(Enum.Names[0])+','+Enum.name+'_desc.vdesc_call);'#13#10;
S:=S+' Assert(c<>nil,'+''''+Name+''''+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//set val
S:=' a.a_gen'+Space(Enum.namelen-Length('gen'))+':=@'+Enum.name+'_desc;'#13#10;
For x:=0 to Enum.Count-1 do
begin
Name:=Enum.Names[x];
S:=S+' a.a_'+Name+Space(Enum.namelen-Length(Name))+':='+FixFieldName(Name)+';'#13#10;
end;
FileWrite(F,Pchar(S)^,Length(S));
//pre
if (Enum.pre<>'') then
begin
S:=' '+Enum.pre+'(@'+'a';
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=S+',osize,ooffset';
end;
S:=S+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:=' s:=VFS_PROLOGUE('+FixFieldName(Enum.Names[0])+'^.v_mount);'#13#10;
//call
S:=S+' Result:='+Enum.name+'_t(c)(@a);'#13#10;
S:=S+' VFS_EPILOGUE(s);'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//post
if (Enum.post<>'') then
begin
S:=' '+Enum.post+'(@a,Result';
if (Upcase(Enum.name)='VOP_WRITE') then
begin
S:=S+',osize,ooffset';
end;
S:=S+');'#13#10;
FileWrite(F,Pchar(S)^,Length(S));
end;
S:='end;'#13#10#13#10;
FileWrite(F,Pchar(S)^,Length(S));
//body
end;
S:='end.'#13#10#13#10;
FileWrite(F,Pchar(S)^,Length(S));
FileClose(F);
end;
//
begin
load_if('vnode_if.src');
readln;
end.