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.