Alexyz21:
13.0.4 [more]
Код:
[/more] при отключенном Numbers выбираются полные дубликаты в соответствии с указанными настройками. Не следует ожидать, что ВсеПД должны быть = ПД<> + ПД==, причём расхождение может быть очень существенным. Для того, чтобы понять почему так происходит, нужно внимательно сравнить файлы на панели - каждый последующий с предыдущим.
13.0.4 [more]
Код:
-- 13.0.4 local F = far.Flags local ffi = require'ffi' local C = ffi.C local NULL = ffi.cast("void*",0) local PANEL_ACTIVE = ffi.cast("HANDLE",-1) local PanelMode,Desc1,Indi1 = 999,"Select duplicates","!?" local guid = "FE9B8874-9651-434C-8182-72329F2371A5" local uGuid = win.Uuid(guid) local BS,ts = string.byte("\\"),{nil,true,9999,true,false,2,2,false} local freport = win.GetEnv("Temp").."\\Report.txt" ffi.cdef[[ void free (void*); int wcscmp(const wchar_t*, const wchar_t*); int _wcsicmp(const wchar_t*, const wchar_t*); int wcsncmp(const wchar_t*, const wchar_t*, size_t); int _wcsnicmp(const wchar_t*, const wchar_t*, size_t); ]] local function ToWChar(str) str=win.Utf8ToUtf16(str) local res=ffi.new("wchar_t[?]",#str/2+1) ffi.copy(res,str) return res end local function GetStartAndLenW(name) local ptr = C.wcsrchr(name,BS) name = ptr==nil and name or ptr+1 local len = tonumber(C.wcslen(name)) if ts[2] and ts[3]<0 and -ts[3]<len then local res=ffi.new("wchar_t[?]",len+1) ffi.copy(res,name+len+ts[3],-ts[3]*2) ffi.copy(res-ts[3],name,(len+ts[3])*2) return res,len else return name,len end end local function StartAndLenW(name) local ptr = C.wcsrchr(name,BS) name = ptr==nil and name or ptr+1 local len = tonumber(C.wcslen(name)) if ts[2] and ts[3]<0 and -ts[3]<len then return name+len+ts[3],-ts[3],name,len elseif ts[2] and ts[3]>0 and ts[3]<len then return name,ts[3],name,len else return name,len,name,len end end local Compare = function(p1,p2) local st1,ln1 = GetStartAndLenW(p1.FileName) local st2,ln2 = GetStartAndLenW(p2.FileName) local sz1,sz2,fa1,fa2 if (ts[5] or not ts[2]) and ts[6]~=2 then sz1,sz2 = tonumber(p1.FileSize),tonumber(p2.FileSize) end if (ts[5] or not ts[2]) and ts[7]~=2 then fa1,fa2 = tonumber(p1.FileAttributes),tonumber(p2.FileAttributes) end local res = ts[4] and C._wcsicmp(st1,st2) or C.wcscmp(st1,st2) if res==0 and sz1 then res=sz1-sz2 elseif res==0 and fa1 then res=fa1-fa2 end return res<0 and -1 or res>0 and 1 or 0 end local Items = { --[[01]] {F.DI_DOUBLEBOX, 3,1, 65,8, 0, 0,0, 0, "Select duplicates of FileName. Help: F1"}, --[[02]] {F.DI_CHECKBOX, 5,2, 26,2, 0, 0,0, 0, "Num&ber of symbols"}, --[[03]] {F.DI_EDIT, 27,2, 32,2, 0, 0,0, 0, ""}, --[[04]] {F.DI_CHECKBOX, 5,3, 20,3, 0, 0,0, 0, "Ignore &case"}, --[[05]] {F.DI_CHECKBOX, 38,3, 62,3, 0, 0,0, 0, "Ignore Full &Duplicates"}, --[[06]] {F.DI_CHECKBOX, 5,4, 21,4, 0, 0,0, F.DIF_3STATE, "&Sizes of FD:"}, --[[07]] {F.DI_CHECKBOX, 5,5, 26,5, 0, 0,0, F.DIF_3STATE, "&Attributes of FD:"}, --[[08]] {F.DI_CHECKBOX, 5,7, 15,7, 0, 0,0, 0, "Re&port"}, --[[09]] {F.DI_TEXT, -1,6, 0,0, 0, 0,0, F.DIF_SEPARATOR,""}, --[[10]] {F.DI_BUTTON, 0,7, 0,0, 0, 0,0, F.DIF_DEFAULTBUTTON+F.DIF_CENTERGROUP,"&Ok"}, --[[11]] {F.DI_BUTTON, 0,7, 0,0, 0, 0,0, F.DIF_CENTERGROUP,"Ca&ncel"} } local tts={} local function DlgProc(hDlg,Msg,Param1,Param2) local function Set1() hDlg:send(F.DM_ENABLE,5,tts[2] and 1 or 0) hDlg:send(F.DM_ENABLE,6,(tts[5] or not tts[2]) and 1 or 0) hDlg:send(F.DM_ENABLE,7,(tts[5] or not tts[2]) and 1 or 0) end if Msg==F.DN_INITDIALOG then for i=2,#Items-3 do tts[i]=ts[i] end Set1() hDlg:send(F.DM_SETTEXT,3,tts[3]) hDlg:send(F.DM_SETCHECK,2,tts[2] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) hDlg:send(F.DM_SETCHECK,4,tts[4] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) hDlg:send(F.DM_SETCHECK,5,tts[5] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) hDlg:send(F.DM_SETCHECK,6,tts[6]==0 and F.BSTATE_UNCHECKED or tts[6]==1 and F.BSTATE_CHECKED or tts[6]==2 and F.BSTATE_3STATE) hDlg:send(F.DM_SETTEXT,6,"&Sizes of FD: "..(tts[6]==0 and "<>" or tts[6]==1 and "==" or "--")) hDlg:send(F.DM_SETCHECK,7,tts[7]==0 and F.BSTATE_UNCHECKED or tts[7]==1 and F.BSTATE_CHECKED or tts[7]==2 and F.BSTATE_3STATE) hDlg:send(F.DM_SETTEXT,7,"&Attributes of FD: "..(tts[7]==0 and "<>" or tts[7]==1 and "==" or "--")) hDlg:send(F.DM_SETCHECK,8,tts[8] and F.BSTATE_CHECKED or F.BSTATE_UNCHECKED) elseif Msg==F.DN_BTNCLICK and (Param1==2 or Param1==4 or Param1==5 or Param1==8) then tts[Param1] = Param2~=0 if Param1==2 or Param1==5 then Set1() end elseif Msg==F.DN_BTNCLICK and (Param1==6 or Param1==7) then tts[Param1] = Param2 hDlg:send(F.DM_SETTEXT,Param1,(Param1==6 and "&Sizes of FD: " or "&Attributes of FD: ")..(Param2==0 and "<>" or Param2==1 and "==" or "--")) elseif Msg==F.DN_EDITCHANGE and Param1==3 then -- Number symbols tts[3] = tonumber(hDlg:send(F.DM_GETTEXT,3)) or tts[3] else return end return true end Macro { description="! Select Duplicates FileName in Branch panel"; name="SDFN"; area="Shell"; action=function() if far.Dialog(uGuid,-1,-1,69,10,nil,Items,nil,DlgProc)==#Items-1 then local t0=far.FarClock() for i=2,#Items-3 do ts[i]=tts[i] end local pBL0,pBL1 = ffi.cast("BOOL*",0),ffi.cast("BOOL*",1) --local PInfo=panel.GetPanelInfo(nil,1) local PInfo=ffi.new("struct PanelInfo") PInfo.StructSize=ffi.sizeof(PInfo) local pc=ffi.cast("struct PluginStartupInfo*",far.CPluginStartupInfo()).PanelControl if pc(PANEL_ACTIVE,"FCTL_GETPANELINFO",0,PInfo)==1 then local pin,pif = tonumber(PInfo.ItemsNumber),tonumber(PInfo.Flags) if pin>1 then if bit.band(pif,F.PFLAGS_SELECTEDFIRST)>0 then Keys("ShiftF12") end if bit.band(pif,F.PFLAGS_NUMERICSORT)>0 then pc(PANEL_ACTIVE,"FCTL_SETNUMERICSORT",0,NULL) end local pfcss=bit.band(pif,F.PFLAGS_CASESENSITIVESORT)==0 if ts[4] and not pfcss or not ts[4] and pfcss then pc(PANEL_ACTIVE,"FCTL_SETCASESENSITIVESORT",ts[4] and 0 or 1,NULL) end if bit.band(pif,F.PFLAGS_REVERSESORTORDER)==0 then pc(PANEL_ACTIVE,"FCTL_SETSORTORDER",1,NULL) end Panel.LoadCustomSortMode(PanelMode,{Description=Desc1;Indicator=Indi1;Compare=Compare}) Panel.SetCustomSortMode(PanelMode,0) local tsel,st0,ln0,st1,ln1,st2,ln2,st3,ln3,sz0,sz1,fa0,fa1 = {} local function Comp(stA,lnA,stB,lnB) return ts[4] and C._wcsicmp(stA,stB) or C.wcscmp(stA,stB) end local function Proc(i,x) if ts[5] and x then elseif ts[2] or not ts[2] and x then pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i-1,pBL1) pc(PANEL_ACTIVE,"FCTL_SETSELECTION",i,pBL1) if #tsel==0 or Comp(tsel[#tsel][2],tsel[#tsel][3],st1,ln1)~=0 then table.insert(tsel,{2,st1,ln1,win.Utf16ToUtf8(ffi.string(st1,ln1*2))}) else tsel[#tsel][1]=tsel[#tsel][1]+1 end end end local function PGPI(i) local ppi = ffi.new("struct FarGetPluginPanelItem") ppi.StructSize = ffi.sizeof("struct FarGetPluginPanelItem") ppi.Size = pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,NULL) if ppi.Size~=0 then local buf = ffi.new("char[?]",ppi.Size) ppi.Item = ffi.cast("struct PluginPanelItem*",buf) pc(PANEL_ACTIVE,"FCTL_GETPANELITEM",i,ppi) st1,ln1,st3,ln3=StartAndLenW(ffi.cast("const unsigned short*",ppi.Item.FileName)) if ts[6] then sz1=tonumber(ppi.Item.FileSize) end if ts[7] then fa1=tonumber(ppi.Item.FileAttributes) end --ffi.gc(buf,nil) end end PGPI(0) pc(PANEL_ACTIVE,"FCTL_BEGINSELECTION",0,NULL) for i=1,pin-1 do st0,ln0,st2,ln2,sz0,fa0 = st1,ln1,st3,ln3,sz1,fa1 PGPI(i) if ts[4] and (ts[2] and C._wcsnicmp(st1,st0,ts[3])==0 or C._wcsicmp(st1,st0)==0) then Proc(i,C._wcsicmp(st3,st2)==0 and not (ts[6]==0 and sz1==sz0 or ts[6]==1 and sz1~=sz0 or ts[6]==2 and false) and not (ts[7]==0 and fa1==fa0 or ts[7]==1 and fa1~=fa0 or ts[7]==2 and false)) elseif not ts[4] and (ts[2] and C.wcsncmp(st1,st0,ts[3])==0 or C.wcscmp(st1,st0)==0) then Proc(i,C.wcscmp(st3,st2)==0 and not (ts[6]==0 and sz1==sz0 or ts[6]==1 and sz1~=sz0 or ts[6]==2 and false) and not (ts[7]==0 and fa1==fa0 or ts[7]==1 and fa1~=fa0 or ts[7]==2 and false)) end end pc(PANEL_ACTIVE,"FCTL_ENDSELECTION",0,NULL) pc(PANEL_ACTIVE,"FCTL_REDRAWPANEL",0,NULL) --Keys("ShiftF12") if ts[8] then table.sort(tsel,function(a,b) return a[1]<b[1] end) local h = io.open(freport,"wb") io.close(h) h = io.open(freport,"ab") h:write("Items: "..#tsel.. "\nExecution time: "..(far.FarClock()-t0).. " mcs\nNumber of symbols: "..(ts[2] and ts[3] or "all").. "\nIgnore case: "..tostring(ts[4]).. "\nIgnore Full Duplicates: "..tostring(ts[5]).. ((ts[5] or not ts[2]) and ("\nSizes of FD: "..(ts[6]==0 and "<>" or ts[6]==1 and "==" or "--")) or "").. ((ts[5] or not ts[2]) and ("\nAttributes of FD: "..(ts[7]==0 and "<>" or ts[7]==1 and "==" or "--")) or "").. "\n\n") for i=#tsel,1,-1 do h:write(tsel[i][1].."\t"..tsel[i][4].."\n") table.remove(tsel) end io.close(h) far.Message("mcs: "..far.FarClock()-t0,"SDFN") end end end end end; } Macro { description = "SDFN - Help"; area = "Dialog"; key = "F1"; condition=function() return Area.Dialog and Dlg.Id==guid end; action=function() if Dlg.CurPos<=3 then far.Message("The number of first or last symbols to compare","Help: Number of symbols") elseif Dlg.CurPos==4 then far.Message("Case of letters in FileName will be ignored","Help: Ignore case") elseif Dlg.CurPos==5 then far.Message("Full duplicates of FileName will be ignored","Help: Ignore Full Duplicates") elseif Dlg.CurPos==6 then far.Message("-- ignore, == equal, <> is not equal","Help: Sizes of FD") elseif Dlg.CurPos==7 then far.Message("-- ignore, == equal, <> is not equal","Help: Attributes of FD") elseif Dlg.CurPos==8 then far.Message("mcs - total time of execution in mcs\nReport will be saved to:\n"..freport,"Help: Report",nil,"l") end end; } |