From 79a631d1b1958bc802ac0bf35282fe2de7cc9858 Mon Sep 17 00:00:00 2001 From: Erich Eckner Date: Thu, 12 May 2016 16:48:36 +0200 Subject: sollte jetzt gehen und die erwarteten Features haben --- Make.lpr | 2 +- Make.lps | 128 +++---- dateibeziehungen.pas | 991 +++++++++++++++++++++++++-------------------------- tools.pas | 120 +++++-- 4 files changed, 646 insertions(+), 595 deletions(-) diff --git a/Make.lpr b/Make.lpr index 0574565..b0e6ff0 100644 --- a/Make.lpr +++ b/Make.lpr @@ -68,7 +68,7 @@ begin mach.erzeugeRegeln; gibAus('Regeln: '+inttostr(mach.anzMglAbh)+', Dateien: '+inttostr(mach.anzDats),3); mach.findeWasZuTunIst; - gibAus('anzuwendende Regeln: '+inttostr(mach.anzZtAbh),3); + gibAus('anzuwendende Regeln: '+inttostr(mach.anzMglAbh),3); mach.tueWasZuTunIst(hasOption('a','alleSummenErneuern'),hasOption('u','unsicher'),getOptionValue('A','Ausgabe')); terminate; diff --git a/Make.lps b/Make.lps index bc74b0c..eb6820a 100644 --- a/Make.lps +++ b/Make.lps @@ -3,27 +3,30 @@ - + - - - + + + + - + - - - + + + + + @@ -33,7 +36,7 @@ - + @@ -41,71 +44,69 @@ - - - - + + + - + - + - - - + + + - + - + - + - + - - - + + + - + - - + @@ -113,127 +114,134 @@ - + + + + + + + + - + - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + - + - + - + - + - + - + - + - + - - + + - - + + - - + + diff --git a/dateibeziehungen.pas b/dateibeziehungen.pas index d951ff3..fcaec5f 100644 --- a/dateibeziehungen.pas +++ b/dateibeziehungen.pas @@ -10,57 +10,91 @@ uses type tZeilenTyp = (ztSuche,ztZiel,ztQuelle,ztBefehl); - pTAbhaengigkeit = ^tAbhaengigkeit; - tAbhaengigkeit = class; + pTGenerischeAbhaengigkeit = ^tGenerischeAbhaengigkeit; + tGenerischeAbhaengigkeit = class; + pTExpliziteAbhaengigkeit = ^tExpliziteAbhaengigkeit; + tExpliziteAbhaengigkeit = class; - tAbhaengigkeiten = class(tFPList) + tGenerischeAbhaengigkeiten = class(tFPList) private - function rItem(idx: longint): tAbhaengigkeit; inline; - procedure wItem(idx: longint; neu: tAbhaengigkeit); inline; + function rItem(idx: longint): tGenerischeAbhaengigkeit; inline; + procedure wItem(idx: longint; neu: tGenerischeAbhaengigkeit); inline; public - property items[idx: longint]: tAbhaengigkeit + property items[idx: longint]: tGenerischeAbhaengigkeit read rItem write wItem; default; - procedure kopiereVon(original: tAbhaengigkeiten); + procedure kopiereVon(original: tGenerischeAbhaengigkeiten); procedure mrProper; - function add(neu: tAbhaengigkeit): longint; - function last: tAbhaengigkeit; + function add(neu: tGenerischeAbhaengigkeit): longint; + function last: tGenerischeAbhaengigkeit; + end; + + tExpliziteAbhaengigkeiten = class(tFPList) + private + function rItem(idx: longint): tExpliziteAbhaengigkeit; inline; + procedure wItem(idx: longint; neu: tExpliziteAbhaengigkeit); inline; + public + property items[idx: longint]: tExpliziteAbhaengigkeit + read rItem + write wItem; default; + procedure kopiereVon(original: tExpliziteAbhaengigkeiten); + procedure mrProper; + function add(neu: tExpliziteAbhaengigkeit): longint; + function last: tExpliziteAbhaengigkeit; procedure sort; end; - tAbhaengigkeit = class(tObject) + // Die goldene Regel bzgl. Abhängigkeiten ist, + // dass jedes Ziel nur ein Mal erzeugt werden kann und muss (logisch) + // und somit für zwei Regeln mit Zielmengen A und B + // A \cut B \neq \emptyset => A \cut B \in {A,B} + // gilt. Von diesen beiden Regeln ist dann höchstens eine anzuwenden. + + // Mit den Informationen jeder einzelnen Quelle muss die gesamte Regel + // konstruiert werden können. Das beinhaltet: + // - weitere Quellen (per regex matchbar) + // - auszuführende Befehle (darf von "weiteren Quellen" abhängen) + // - erzeugte Ziele (darf von "weiteren Quellen" abhängen) + + tGenerischeAbhaengigkeit = class(tObject) private - _erben,_eltern: tAbhaengigkeiten; _quellens,_zieles: array of tDateienMitDaten; + _dats: tDateienMitDaten; function rQuellen(idx: longint): tDateienMitDaten; function rZiele(idx: longint): tDateienMitDaten; + function quellersetzung(var worin: string; quellen: tDateienMitDaten; momentanePosition: longint): boolean; + function zieleHinzufuegen(ziele, quellen: tDateienMitDaten; zielFkt: string): boolean; + function findeMehrZiele(ziele, quellen: tDateienMitDaten): boolean; + function matchCount: longint; public - quellenREs: array of tRegExpr; // regexes der Quellen - qrePack: array of boolean; // sind mehrere matches obiger regexes zu einem Paket zu bündeln? - zieleFkt, - befehle: tStringlist; + machDatei: string; + quellenREs: array of string; // regexe der Quellen - nur deshalb kein tRegExpr, weil es ohnehin zuerst substituiert werden muss + zieleFkt,befehleFkt: tStringlist; property quellen[idx: longint]: tDateienMitDaten read rQuellen; property ziele[idx: longint]: tDateienMitDaten read rZiele; - function matchCount: longint; - constructor create; overload; -// constructor create(original: tAbhaengigkeit); overload; + constructor create(dats: tDateienMitDaten); destructor destroy; override; - function hatQuelleVonAlsZiel(abh: tAbhaengigkeit): boolean; - function hatErbenMitQuelle(name: string): boolean; - function erbeMitGleichenZielen(zl: tDateienMitDaten): tAbhaengigkeit; - procedure neuerErbe(erb: tAbhaengigkeit); - procedure entferneErben(i: longint); overload; - procedure entferneErben(erb: tAbhaengigkeit); overload; - procedure entferneElterReferenz(elt: tAbhaengigkeit); function findeQuellen(dats: tDateienMitDaten): boolean; + procedure generiereErben(var es: tExpliziteAbhaengigkeiten); + end; + + tExpliziteAbhaengigkeit = class(tObject) + ziele,quellen: tDateienMitDaten; + befehle: tStringlist; + constructor create; + destructor destroy; override; + function hatQuelleVonAlsZiel(abh: tExpliziteAbhaengigkeit): boolean; + function ersetzbarDurch(abh: tExpliziteAbhaengigkeit): boolean; + function pruefeObZuTun: boolean; end; tMach = class private _machDatei,_pruefsummenDatei: string; - _oriAbh,_mglAbh,_ztAbh: tAbhaengigkeiten; + _oriAbh: tGenerischeAbhaengigkeiten; + _mglAbh: tExpliziteAbhaengigkeiten; _dats: tDateienMitDaten; _ign: array of tRegExpr; procedure wMachDatei(md: string); @@ -68,8 +102,6 @@ type function liesMachDatei: boolean; function liesPruefsummenfile: boolean; function sammleDateien(wo: string; rekursiv: boolean): longint; - procedure zieleHinzufuegen(var ziele: tDateienMitDaten; ziel,quelle: string); - procedure findeMehrZiele(var ziele: tDateienMitDaten; zieleFkt: tStringList; quelle: string); public property machDatei: string read _machDatei @@ -84,30 +116,74 @@ type procedure tueWasZuTunIst(allesNeu, unsicher: boolean; ausgabeDatei: string); function anzOriAbh: longint; inline; function anzMglAbh: longint; inline; - function anzZtAbh: longint; inline; function anzDats: longint; inline; end; -function quellersetzung(var worin: string; quelle, inputfile: string): boolean; +procedure allgemeineErsetzungen(var worin: string; machDatei: string); implementation uses lowlevelunit, mystringlistunit, systemunit; -// tAbhaengigkeiten ************************************************************ +// tGenerischeAbhaengigkeiten ************************************************************ + +function tGenerischeAbhaengigkeiten.rItem(idx: longint): tGenerischeAbhaengigkeit; +begin + result:=tGenerischeAbhaengigkeit(get(idx)); +end; + +procedure tGenerischeAbhaengigkeiten.wItem(idx: longint; neu: tGenerischeAbhaengigkeit); +begin + put(idx,neu); +end; + +procedure tGenerischeAbhaengigkeiten.kopiereVon(original: tGenerischeAbhaengigkeiten); +var + i: longint; +begin + clear; + for i:=0 to original.count-1 do + add(original[i]); +end; + +procedure tGenerischeAbhaengigkeiten.mrProper; +var + i: longint; +begin + for i:=0 to count-1 do + items[i].free; + clear; +end; + +function tGenerischeAbhaengigkeiten.add(neu: tGenerischeAbhaengigkeit): longint; +var + i: longint; +begin + for i:=0 to count-1 do + if items[i]=neu then + fehler('Fehler: Ich soll etwas zur Liste hinzufügen, was schon drin ist!'); + result:=inherited add(neu); +end; + +function tGenerischeAbhaengigkeiten.last: tGenerischeAbhaengigkeit; +begin + result:=tGenerischeAbhaengigkeit(inherited last); +end; + +// tExpliziteAbhaengigkeiten ************************************************************ -function tAbhaengigkeiten.rItem(idx: longint): tAbhaengigkeit; +function tExpliziteAbhaengigkeiten.rItem(idx: longint): tExpliziteAbhaengigkeit; begin - result:=tAbhaengigkeit(get(idx)); + result:=tExpliziteAbhaengigkeit(get(idx)); end; -procedure tAbhaengigkeiten.wItem(idx: longint; neu: tAbhaengigkeit); +procedure tExpliziteAbhaengigkeiten.wItem(idx: longint; neu: tExpliziteAbhaengigkeit); begin put(idx,neu); end; -procedure tAbhaengigkeiten.kopiereVon(original: tAbhaengigkeiten); +procedure tExpliziteAbhaengigkeiten.kopiereVon(original: tExpliziteAbhaengigkeiten); var i: longint; begin @@ -116,7 +192,7 @@ begin add(original[i]); end; -procedure tAbhaengigkeiten.mrProper; +procedure tExpliziteAbhaengigkeiten.mrProper; var i: longint; begin @@ -125,7 +201,7 @@ begin clear; end; -function tAbhaengigkeiten.add(neu: tAbhaengigkeit): longint; +function tExpliziteAbhaengigkeiten.add(neu: tExpliziteAbhaengigkeit): longint; var i: longint; begin @@ -135,16 +211,16 @@ begin result:=inherited add(neu); end; -function tAbhaengigkeiten.last: tAbhaengigkeit; +function tExpliziteAbhaengigkeiten.last: tExpliziteAbhaengigkeit; begin - result:=tAbhaengigkeit(inherited last); + result:=tExpliziteAbhaengigkeit(inherited last); end; -procedure tAbhaengigkeiten.sort; +procedure tExpliziteAbhaengigkeiten.sort; var i,j,k,pLen: longint; perm: array of longint; - tmp: tAbhaengigkeit; + tmp: tExpliziteAbhaengigkeit; bedingungen: array of tPoint; nehmbare: array of byte; // 0 = ja, 1 = nein, 2 = nie wieder (schon genommen) fortschritt: boolean; @@ -203,251 +279,366 @@ begin end; end; -// tAbhaengigkeit ************************************************************** +// tGenerischeAbhaengigkeit ************************************************************** -constructor tAbhaengigkeit.create; +constructor tGenerischeAbhaengigkeit.create(dats: tDateienMitDaten); begin inherited create; + _dats:=dats; setlength(quellenREs,0); - setlength(qrePack,0); zieleFkt:=tStringlist.create; - befehle:=tStringlist.create; - _erben:=tAbhaengigkeiten.create; - _eltern:=tAbhaengigkeiten.create; + befehleFkt:=tStringlist.create; + machDatei:=''; setlength(_quellens,0); setlength(_zieles,0); end; -(* -constructor tAbhaengigkeit.create(original: tAbhaengigkeit); -var - i: longint; -begin - inherited create; - setlength(quellenREs,0); - setlength(qrePack,0); - zieleFkt:=tStringlist.create; - zieleFkt.text:=original.zieleFkt.text; - setlength(_quellens,0); - setlength(_zieles,0); - befehle:=tStringlist.create; - befehle.text:=original.befehle.text; - _erben:=tAbhaengigkeiten.create; - _eltern:=tAbhaengigkeiten.create; - original.neuerErbe(self); -end; -*) -destructor tAbhaengigkeit.destroy; + +destructor tGenerischeAbhaengigkeit.destroy; var i: longint; begin - for i:=0 to length(quellenREs)-1 do - quellenREs[i].free; - setlength(quellenREs,0); - setlength(qrePack,0); for i:=0 to length(_quellens)-1 do - setlength(_quellens[i],0); + _quellens[i].free; setLength(_quellens,0); + for i:=0 to length(quellenREs)-1 do + setlength(quellenREs[i],0); + setlength(quellenREs,0); for i:=0 to length(_zieles)-1 do - setlength(_zieles[i],0); + _zieles[i].free; setLength(_zieles,0); zieleFkt.free; - befehle.free; - while _erben.count>0 do - entferneErben(0); - while _eltern.count>0 do - _eltern[0].entferneErben(self); - _erben.free; - _eltern.free; + befehleFkt.free; for i:=0 to length(_quellens)-1 do - setlength(_quellens[i],0); + _quellens[i].free; setlength(_quellens,0); inherited destroy; end; -function tAbhaengigkeit.rQuellen(idx: longint): tDateienMitDaten; +function tGenerischeAbhaengigkeit.rQuellen(idx: longint): tDateienMitDaten; begin result:=_quellens[idx]; end; -function tAbhaengigkeit.rZiele(idx: longint): tDateienMitDaten; +function tGenerischeAbhaengigkeit.rZiele(idx: longint): tDateienMitDaten; begin result:=_zieles[idx]; end; -function tAbhaengigkeit.matchCount: longint; -begin - if length(_quellens)<>length(_zieles) then - fehler('unterschiedlich viele Sätze an Quellen ('+inttostr(length(_quellens))+') und Zielen ('+inttostr(length(_zieles))+').'); - result:=length(_quellens); -end; - -function tAbhaengigkeit.hatQuelleVonAlsZiel(abh: tAbhaengigkeit): boolean; -var - i,j: longint; -begin - result:=true; - if (matchCount>1) or (abh.matchCount>1) then - fehler('hatQuelleVonAlsZiel geht nur für Abhängigkeiten mit einem Satz Quellen und Zielen.'); - if (matchCount=1) and (abh.matchCount=1) then - for i:=0 to length(ziele[0])-1 do - for j:=0 to length(abh.quellen[0])-1 do - if abh.quellen[0][j].name = ziele[0][i].name then - exit; - result:=false; -end; - -function tAbhaengigkeit.hatErbenMitQuelle(name: string): boolean; +function tGenerischeAbhaengigkeit.quellersetzung(var worin: string; quellen: tDateienMitDaten; momentanePosition: longint): boolean; var - i,j: longint; + s,anfang,mitte: string; + i,li,re,qNum: longint; + tmpRE: tRegExpr; begin result:=true; - for i:=0 to _erben.count-1 do - with _erben[i] do begin - if matchCount=0 then - continue; - if matchCount>1 then - fehler('hatErbenMitQuelle geht nur für Abhängigkeiten mit Erben mit je einem Satz Quellen.'); - for j:=0 to length(quellen[0])-1 do - if quellen[0][j].name=name then - exit; + for qNum:=0 to momentanePosition-1 do begin + ersetzeAlleVorkommen(worin,'%in('+inttostr(qNum)+')',quellen[qnum].name); + s:=extractfilename(quellen[qnum].name); + ersetzeAlleVorkommen(worin,'%ifile('+inttostr(qNum)+')',s); + if pos('.',s)>0 then + delete(s,pos('.',s),length(s)); + ersetzeAlleVorkommen(worin,'%basename('+inttostr(qNum)+')',s); + + while pos('%dirname('+inttostr(qNum)+',',worin)>0 do begin + anfang:=erstesArgument(worin,'%dirname('+inttostr(qNum)+',',false); + mitte:=erstesArgument(worin,')',false); + s:=extractfilepath(quellen[qnum].name); + if rightStr(s,1)='/' then + delete(s,length(s),1); + i:=anzCs('/',s)+1; + li:=strtoint(trim(erstesArgument(mitte,',',false))); + if li<0 then li:=li+i; + if mitte='' then + re:=0 + else + re:=strtoint(mitte); + if re<=0 then re:=re+i; + while li>0 do begin + dec(li); + dec(re); + erstesArgument(s,'/',false); + end; + mitte:=''; + while re>0 do begin + dec(re); + mitte:=mitte+'/'+erstesArgument(s,'/',false); + end; + delete(mitte,1,1); + worin:=anfang+mitte+worin; end; + s:=extractfilepath(quellen[qnum].name); + if rightStr(s,1)='/' then + delete(s,length(s),1); + ersetzeAlleVorkommen(worin,'%dirname('+inttostr(qnum)+')',s); + end; + + allgemeineErsetzungen(worin,machDatei); + result:=false; + tmpRE:=tRegExpr.create; + for qNum:=0 to momentanePosition-1 do begin + while pos('%nurmit('+inttostr(qnum)+')''',worin)>0 do begin + anfang:=erstesArgument(worin,'%nurmit('+inttostr(qnum)+')''',false); + tmpRE.expression:=erstesArgument(worin,'''',false); + if not tmpRE.exec(quellen[qnum].name) then begin + tmpRE.free; + exit; + end; + worin:=anfang+worin; + end; + while pos('%nurohne('+inttostr(qnum)+')''',worin)>0 do begin + anfang:=erstesArgument(worin,'%nurohne('+inttostr(qnum)+')''',false); + tmpRE.expression:=erstesArgument(worin,'''',false); + if tmpRE.exec(quellen[qnum].name) then begin + tmpRE.free; + exit; + end; + worin:=anfang+worin; + end; + end; + result:=true; + tmpRE.free; end; -function tAbhaengigkeit.erbeMitGleichenZielen(zl: tDateienMitDaten): tAbhaengigkeit; +function tGenerischeAbhaengigkeit.zieleHinzufuegen(ziele, quellen: tDateienMitDaten; zielFkt: string): boolean; var - i: longint; + i,ebene,ende: longint; + s,t,u: string; + wasda: boolean; begin - result:=nil; - for i:=0 to _erben.count-1 do begin - if _erben[i].matchCount=0 then - continue; - if _erben[i].matchCount>1 then - fehler('erbeMitGleichenZielen geht nur für Abhängigkeiten mit Erben mit je einem Satz Ziele.'); - if gleicheDateinamen(_erben[i].ziele[0],zl) then begin - result:=_erben[i]; - exit; + result:=false; + if pos('{',zielFkt)=0 then begin + if not quellersetzung(zielFkt,quellen,quellen.count) then exit; + zielFkt:=unescape(zielFkt); + wasda:=false; + for i:=0 to _dats.count-1 do + if zielFkt=_dats[i].name then begin + wasda:=true; + ziele.add(_dats[i]); + end; + if not wasda then begin + result:=true; + _dats.add(tDateiMitDatum.create); + _dats.last.name:=zielFkt; + _dats.last.aktuell:=aNichtVorhanden; + ziele.add(_dats[i]); + end; + end + else begin + ende:=pos('{',zielFkt); + ebene:=1; + while (ebene>0) or (zielFkt[ende]<>'}') do begin + inc(ende); + case zielFkt[ende] of + '{': inc(ebene); + '}': dec(ebene); + end{of case}; + end; + s:=copy(zielFkt,1,pos('{',zielFkt)-1); + t:=copy(zielFkt,pos('{',zielFkt)+1,ende-pos('{',zielFkt)-1); + u:=copy(zielFkt,ende+1,length(zielFkt)); + if unescapedpos('..',t)>0 then begin + for i:=strtoint(copy(t,1,unescapedpos('..',t)-1)) to strtoint(copy(t,unescapedpos('..',t)+2,length(t))) do + zieleHinzufuegen(ziele,quellen,s+inttostr(i)+u); + end + else begin + t:=t+','; + while unescapedpos(',',t)>0 do begin + zieleHinzufuegen(ziele,quellen,s+copy(t,1,unescapedpos(',',t)-1)+u); + delete(t,1,unescapedpos(',',t)); + end; end; end; end; -procedure tAbhaengigkeit.neuerErbe(erb: tAbhaengigkeit); -begin - _erben.add(erb); - erb._eltern.add(self); -end; - -procedure tAbhaengigkeit.entferneErben(i: longint); -begin - _erben[i].entferneElterReferenz(self); - _erben.delete(i); -end; - -procedure tAbhaengigkeit.entferneErben(erb: tAbhaengigkeit); +function tGenerischeAbhaengigkeit.findeMehrZiele(ziele, quellen: tDateienMitDaten): boolean; var i: longint; begin - for i:=0 to _erben.count-1 do - if _erben[i]=erb then begin - entferneErben(i); - exit; - end; - fehler('Fehler: Kann Erben nicht finden zum Entfernen!'); + result:=false; + for i:=0 to zieleFkt.count-1 do + if zieleHinzufuegen(ziele,quellen,zieleFkt[i]) then + result:=true; end; -procedure tAbhaengigkeit.entferneElterReferenz(elt: tAbhaengigkeit); -var - i: longint; +function tGenerischeAbhaengigkeit.matchCount: longint; begin - for i:=0 to _eltern.count-1 do - if _eltern[i]=elt then begin - _eltern.delete(i); - exit; - end; - fehler('Fehler: Kann Elter nicht finden zum Entfernen der Referenz!'); + if length(_quellens)<>length(_zieles) then + fehler('unterschiedlich viele Sätze an Quellen ('+inttostr(length(_quellens))+') und Zielen ('+inttostr(length(_zieles))+').'); + result:=length(_quellens); end; -function tAbhaengigkeit.findeQuellen(dats: tDateienMitDaten): boolean; +function tGenerischeAbhaengigkeit.findeQuellen(dats: tDateienMitDaten): boolean; var - i,j,k: longint; - treffer: array of tDateienMitDaten; + i,lastI: longint; idx: array of longint; - tmpQs: tDateienMitDaten; + tmpQs: tDateienMitDaten; // hierin wird die momentan betrachte Kombination von Quellen gespeichert s: string; + tmpRE: tRegExpr; begin + result:=false; for i:=0 to length(_quellens)-1 do - setlength(_quellens[i],0); + _quellens[i].free; setlength(_quellens,0); + for i:=0 to length(_zieles)-1 do + _zieles[i].free; + setlength(_zieles,0); if length(quellenREs)=0 then exit; - setlength(treffer,length(quellenREs)); - for i:=0 to length(treffer)-1 do - for j:=0 to length(dats)-1 do - if quellenREs[i].exec(dats[j].name) then begin - setlength(treffer[i],length(treffer[i])+1); - treffer[i,length(treffer[i])-1]:=dats[j]; - end; - - for i:=0 to length(treffer)-1 do - if length(treffer[i])=0 then - exit; - - setlength(idx,length(treffer)); - idx[0]:=-1; - for i:=1 to length(idx)-1 do - idx[i]:=length(treffer[i])-1; - - j:=0; - for i:=0 to length(idx)-1 do - if qrePack[i] then - j:=j+length(treffer[i]) - else - inc(j); - setlength(tmpQs,j); - - // feste Bestandteile von tmpQs initialisieren - j:=length(treffer); - for i:=0 to length(idx)-1 do - if qrePack[i] then begin - tmpQs[i]:=treffer[i][0]; - for k:=1 to length(treffer[i])-1 do begin - tmpQs[j]:=treffer[i][k]; - inc(j); - end; - end; + tmpRE:=tRegExpr.create; + tmpQs:=tDateienMitDaten.create; + tmpQs.count:=length(quellenREs); + setlength(idx,tmpQs.count); + for i:=0 to length(idx)-1 do begin + idx[i]:=-1; + tmpQs[i]:=nil; + end; + lastI:=-1; repeat - i:=length(idx)-1; - while (i>=0) and qrePack[i] do - dec(i); - if i<0 then break; - repeat - inc(idx[i]); - if idx[i]>=length(treffer[i]) then begin - idx[i]:=0; - repeat + if assigned(tmpQs[0]) then + i:=length(idx)-1 + else + i:=0; + while (i>=0) and (ilastI then begin // wir betrachten eine neue Stelle, + s:=quellenREs[i]; // daher ist der RegEx nicht mehr aktuell + if not quellErsetzung(s,tmpQs,i) then begin // regex-substitution nicht erfolgreich - + idx[i]:=-1; // wird behandelt wie nie passender regex + tmpQs[i]:=nil; dec(i); - until (i<0) or not qrePack[i]; + continue; + end; + tmpRE.expression:=s; + lastI:=i; + end; + repeat + inc(idx[i]); + until (idx[i]>=dats.count) or (tmpRE.exec(dats[idx[i]].name)); + + if idx[i]>=dats.count then begin // Überlauf + idx[i]:=-1; + tmpQs[i]:=nil; + dec(i); continue; end; - break; - until i<0; - if i<0 then break; - // idx und qrePack codieren, welche "treffer" die aktuellen Quellen sind. - for i:=0 to length(idx)-1 do - if not qrePack[i] then - tmpQs[i]:=treffer[i][idx[i]]; + tmpQs[i]:=dats[idx[i]]; + inc(i); // nächste Stelle + if i>=length(idx) then // zu weit? + break; // dann fertig + idx[i]:=-1; // sonst initialisieren + end; + if i<0 then break; // Überlauf auf -1 => fertig + + setlength(_quellens,length(_quellens)+1); + _quellens[length(_quellens)-1]:=tDateienMitDaten.create; + for i:=0 to tmpQs.count-1 do + _quellens[length(_quellens)-1].add(tmpQs[i]); + until false; - for i:=0 to zieleFkt.count-1 do begin - s:=zieleFkt[i]; - if quellersetzung(s,tmpQs,machDatei) then begin + tmpRE.free; + tmpQs.free; + setlength(idx,0); - end; + setlength(_zieles,length(_quellens)); + for i:=0 to length(_zieles)-1 do begin + _zieles[i]:=tDateienMitDaten.create; + if findeMehrZiele(_zieles[i],_quellens[i]) then + result:=true; + end; +end; + +procedure tGenerischeAbhaengigkeit.generiereErben(var es: tExpliziteAbhaengigkeiten); +var + i,j: longint; + s: string; +begin + for i:=0 to matchCount-1 do begin + es.add(tExpliziteAbhaengigkeit.create); + for j:=0 to quellen[i].count-1 do + es.last.quellen.add(quellen[i][j]); + for j:=0 to ziele[i].count-1 do + es.last.ziele.add(ziele[i][j]); + for j:=0 to befehleFkt.count-1 do begin + s:=befehleFkt[j]; + if quellersetzung(s,quellen[i],quellen[i].count) then + es.last.befehle.add(s); end; - until false; - setlength(tmpQs,0); + if es.last.befehle.count=0 then + fehler( + 'Keine Befehle auszuführen für explizite Abhängigkeit!'#10+ + 'Befehle:'#10+ + befehleFkt.text+ + 'Quellen:'#10+ + quellen[i].toString + ); + end; +end; + +// tExpliziteAbhaengigkeit ************************************************************** + +constructor tExpliziteAbhaengigkeit.create; +begin + inherited create; + quellen:=tDateienMitDaten.create; + ziele:=tDateienMitDaten.create; + befehle:=tStringlist.create; +end; + +destructor tExpliziteAbhaengigkeit.destroy; +begin + quellen.free; + ziele.free; + befehle.free; + inherited destroy; +end; + +function tExpliziteAbhaengigkeit.hatQuelleVonAlsZiel(abh: tExpliziteAbhaengigkeit): boolean; +var + i,j: longint; +begin + result:=true; + for i:=0 to ziele.count-1 do + for j:=0 to abh.quellen.count-1 do + if abh.quellen[j].name = ziele[i].name then + exit; + result:=false; +end; + +function tExpliziteAbhaengigkeit.ersetzbarDurch(abh: tExpliziteAbhaengigkeit): boolean; +var + i,j: longint; +begin + result:=true; + for i:=0 to ziele.count-1 do begin + result:=false; + for j:=0 to abh.ziele.count-1 do + if abh.ziele[j].name = ziele[i].name then + result:=true; + if not result then + exit; + end; +end; + +function tExpliziteAbhaengigkeit.pruefeObZuTun: boolean; +var + i: longint; + quA,ziA: tAktualitaet; +begin + quA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Quellen aktuell sind + for i:=0 to quellen.count-1 do + if quellen[i].aktuell<>aAktuell then // nicht aktuelle Quellen + quA:=aWirdErneuert; // werden sicherlich erneuert werden + ziA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Ziele aktuell sind + for i:=0 to ziele.count-1 do + ziA:=min(ziA,ziele[i].aktuell); + + result:=ziAztBefehl) then begin _oriAbh.add(na); - na:=tAbhaengigkeit.create; + na:=tGenerischeAbhaengigkeit.create(_dats); + na.machDatei:=machDatei; end; if s='%%DATEIENDE%%' then break; case wasIst of ztSuche: begin - if not quellersetzung(s,'',machDatei) then begin - gibAus('Fehler: Quellersetzung in '''+s+''' fehlgeschlagen!',3); - aufraeumen; - exit; - end; + allgemeineErsetzungen(s,machDatei); if startetMit('!',s) then begin setlength(_ign,length(_ign)+1); _ign[length(_ign)-1]:=tRegExpr.create; @@ -589,20 +774,14 @@ begin end; while pos(';;',s)>0 do delete(s,pos(';;',s),1); - na.befehle.add(s); + na.befehleFkt.add(s); end; ztZiel: while s<>'' do na.zieleFkt.add(erstesArgument(s)); ztQuelle: begin - if not quellersetzung(s,'',machDatei) then begin - gibAus('Fehler: Quellersetzung in '''+s+''' fehlgeschlagen!',3); - aufraeumen; - exit; - end; setlength(na.quellenREs,length(na.quellenREs)+1); - na.quellenREs[length(na.quellenREs)-1]:=tRegExpr.create; - na.quellenREs[length(na.quellenREs)-1].expression:=s; + na.quellenREs[length(na.quellenREs)-1]:=s; end; end{of case}; wasWar:=wasIst; @@ -643,7 +822,7 @@ begin for gut:=false to true do for i:=0 to gutschlecht[gut].count-1 do begin gefunden:=false; - for j:=0 to length(_dats)-1 do + for j:=0 to _dats.count-1 do if _dats[j].name=gutschlecht[gut][i] then begin if gut then _dats[j].aktuell:=aAktuell @@ -654,10 +833,9 @@ begin end; if not gefunden then begin if not gut then begin // dateien mit ungültiger Prüfsumme können auch nicht vorhanden sein, - setlength(_dats,length(_dats)+1); // dann werden sie einfach eingefügt - _dats[length(_dats)-1]:=tDateiMitDatum.create; - _dats[length(_dats)-1].name:=gutschlecht[gut][i]; - _dats[length(_dats)-1].aktuell:=aNichtVorhanden; + _dats.add(tDateiMitDatum.create); // dann werden sie einfach eingefügt + _dats.last.name:=gutschlecht[gut][i]; + _dats.last.aktuell:=aNichtVorhanden; continue; end; gibAus('Fehler: In der Summendatei gibt es eine Datei mit gültiger Prüfsumme, die ich nicht finden kann: '''+gutschlecht[gut][i]+'''!',3); @@ -693,10 +871,9 @@ begin end else begin inc(result); - setlength(_dats,length(_dats)+1); - _dats[length(_dats)-1]:=tDateiMitDatum.create; - _dats[length(_dats)-1].name:=extractfilepath(wo)+sr.name; - _dats[length(_dats)-1].aktuell:=aVeraltet; + _dats.add(tDateiMitDatum.create); + _dats.last.name:=extractfilepath(wo)+sr.name; + _dats.last.aktuell:=aVeraltet; end; end; err:=FindNext(sr); @@ -704,192 +881,64 @@ begin findClose(sr); end; -procedure tMach.zieleHinzufuegen(var ziele: tDateienMitDaten; ziel,quelle: string); -var - i,ebene,ende: longint; - s,t,u: string; - wasda: boolean; -begin - if pos('{',ziel)=0 then begin - if not quellersetzung(ziel,quelle,machDatei) then exit; - ziel:=unescape(ziel); - i:=0; - wasda:=false; - while i0) or (ziel[ende]<>'}') do begin - inc(ende); - case ziel[ende] of - '{': inc(ebene); - '}': dec(ebene); - end{of case}; - end; - s:=copy(ziel,1,pos('{',ziel)-1); - t:=copy(ziel,pos('{',ziel)+1,ende-pos('{',ziel)-1); - u:=copy(ziel,ende+1,length(ziel)); - if unescapedpos('..',t)>0 then begin - for i:=strtoint(copy(t,1,unescapedpos('..',t)-1)) to strtoint(copy(t,unescapedpos('..',t)+2,length(t))) do - zieleHinzufuegen(ziele,s+inttostr(i)+u,quelle); - end - else begin - t:=t+','; - while unescapedpos(',',t)>0 do begin - zieleHinzufuegen(ziele,s+copy(t,1,unescapedpos(',',t)-1)+u,quelle); - delete(t,1,unescapedpos(',',t)); - end; - end; - end; -end; - -procedure tMach.findeMehrZiele(var ziele: tDateienMitDaten; zieleFkt: tStringList; quelle: string); -var - i: longint; -begin - for i:=0 to zieleFkt.count-1 do - zieleHinzufuegen(ziele,zieleFkt[i],quelle); -end; - procedure tMach.erzeugeRegeln; var - i,j,k,l: longint; - neues: boolean; - s: string; - tmpZiele: tDateienMitDaten; - erb: tAbhaengigkeit; + i: longint; + neues: boolean; begin repeat neues:=false; - for i:=0 to _oriAbh.count-1 do begin - _oriAbh[i].findeQuellen(_dats); - - for j:=0 to _oriAbh[i].matchCount-1 do - if _oriAbh[i].quellenRE.exec(_dats[j].name) then begin - // Falls diese Quelle schon in eine Regel einfließt, brauchen - // wir nichts mehr zu machen, da es für jede Quelle höchstens - // eine Regel gibt. - if _oriAbh[i].hatErbenMitQuelle(_dats[j].name) then continue; - - // Andernfalls müssen wir schauen, ob es zu dem Ziel / den Zielen - // der Quelle schon eine Regel gibt. - setlength(tmpZiele,0); - findeMehrZiele(tmpZiele,_oriAbh[i].zieleFkt,_dats[j].name); - - if length(tmpZiele)=0 then begin - gibAus('Fehler: Keine Ziele für Abhängigkeit!',3); - gibAus('Quelle:',3); - gibAus(''''+_dats[j].name+'''',3); - gibAus('Ziele:',3); - for k:=0 to _oriAbh[i].zieleFkt.count-1 do - gibAus(' '''+_oriAbh[i].zieleFkt[k]+'''',3); - fehler('... ich beende.'); - end; - - erb:=_oriAbh[i].erbeMitGleichenZielen(tmpZiele); - if assigned(erb) then begin - // es gibt schon eine Regel für die Ziele der Quelle, - // dann wird dieser Regel nur die Quelle hinzugefügt - setlength(erb.quellen,length(erb.quellen)+1); - erb.quellen[length(erb.quellen)-1]:=_dats[j]; - // und womöglich die befehle generiert - for l:=0 to _oriAbh[i].befehle.count-1 do begin - s:=_oriAbh[i].befehle[l]; - if quellersetzung(s,_dats[j].name,machDatei) then begin - if l=0 then erb.befehle.clear; - erb.befehle.add(s); - end; - end; - neues:=true; - continue; - end; - - // Ziel(e) ist/sind neu - _mglAbh.add(tAbhaengigkeit.create); - _oriAbh[i].neuerErbe(_mglAbh.last); - setlength(_mglAbh.last.quellen,1); - _mglAbh.last.quellen[0]:=_dats[j]; - _mglAbh.last.zieleFkt:=tStringlist.create; - _mglAbh.last.zieleFkt.text:=_oriAbh[i].zieleFkt.text; - setlength(_mglAbh.last.ziele,length(tmpZiele)); - for k:=0 to length(tmpZiele)-1 do - _mglAbh.last.ziele[k]:=tmpZiele[k]; - _mglAbh.last.befehle.clear; - for k:=0 to _oriAbh[i].befehle.count-1 do begin - s:=_oriAbh[i].befehle[k]; - if quellersetzung(s,_dats[j].name,machDatei) then - _mglAbh.last.befehle.add(s); - end; - end; + for i:=0 to _oriAbh.count-1 do + if _oriAbh[i].findeQuellen(_dats) then + neues:=true; // neue Dateien sind entstanden until not neues; + + for i:=0 to _oriAbh.count-1 do + _oriAbh[i].generiereErben(_mglAbh); end; procedure tMach.findeWasZuTunIst; var - i,j,k: longint; - ziA,quA: tAktualitaet; - neues: boolean; + i,j: longint; + neues: boolean; + zuTun: array of boolean; begin + setlength(zuTun,_mglAbh.count); + for i:=0 to length(zuTun)-1 do + zuTun[i]:=false; + // schauen, welche Regeln angewandt werden müssen repeat neues:=false; - for i:=_mglAbh.count-1 downto 0 do begin - for j:=0 to length(_mglAbh[i].quellen)-1 do - findeMehrZiele(_mglAbh[i].ziele,_mglAbh[i].zieleFkt,_mglAbh[i].quellen[j].name); - if length(_mglAbh[i].ziele)=0 then begin // immer noch keine ziele - gibAus('Warnung: Keine Ziele für diese Abhängigkeit!',3); - gibAus('quellen:',3); - for k:=0 to length(_mglAbh[i].quellen)-1 do - gibAus(' '''+_mglAbh[i].quellen[k].name+'''',3); - gibAus('zieleFkt:',3); - for k:=0 to _mglAbh[i].zieleFkt.count-1 do - gibAus(' '''+_mglAbh[i].zieleFkt[k]+'''',3); - gibAus(' - wird ignoriert.',3); - _mglAbh[i].free; - _mglAbh.delete(i); - continue; - end; + for i:=0 to length(zuTun)-1 do + if not zuTun[i] then + if _mglAbh[i].pruefeObZuTun then begin + zuTun[i]:=true; + neues:=true; + end; + until not neues; - quA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Quellen aktuell sind - for j:=0 to length(_mglAbh[i].quellen)-1 do - if _mglAbh[i].quellen[j].aktuell<>aAktuell then // nicht aktuelle Quellen - quA:=aWirdErneuert; // werden sicherlich erneuert werden - ziA:=aAktuell; // bis auf weiteres gehen wir davon aus, dass die Ziele aktuell sind - for j:=0 to length(_mglAbh[i].ziele)-1 do - ziA:=min(ziA,_mglAbh[i].ziele[j].aktuell); - - if ziAj) and _mglAbh[i].ersetzbarDurch(_mglAbh[j]) then begin + _mglAbh[j].quellen.append(_mglAbh[i].quellen); + zuTun[i]:=false; + break; + end; + + for i:=length(zuTun)-1 downto 0 do + if not zuTun[i] then begin + _mglAbh[i].free; + _mglAbh.delete(i); end; - until not neues; + setlength(zuTun,0); // anzuwendende Regeln sortieren - _ztAbh.sort; + _mglAbh.sort; end; procedure tMach.tueWasZuTunIst(allesNeu, unsicher: boolean; ausgabeDatei: string); @@ -905,7 +954,7 @@ begin befehle:=tStringlist.create; geaenderteDateien:=tStringlist.create; sumDateien:=dateienMitGueltigerSumme(pruefsummenDatei); - for i:=0 to length(_dats)-1 do begin + for i:=0 to _dats.count-1 do begin gefunden:=(_dats[i].name=pruefsummenDatei) or (_dats[i].name=ausgabeDatei); for j:=0 to sumDateien.count-1 do if sumDateien[j]=_dats[i].name then begin @@ -919,20 +968,20 @@ begin sumDateien.free; if allesNeu then for i:=0 to _mglAbh.count-1 do begin - for j:=0 to length(_mglAbh[i].ziele)-1 do + for j:=0 to _mglAbh[i].ziele.count-1 do geaenderteDateien.add(_mglAbh[i].ziele[j].name); - for j:=0 to length(_mglAbh[i].quellen)-1 do + for j:=0 to _mglAbh[i].quellen.count-1 do geaenderteDateien.add(_mglAbh[i].quellen[j].name); end; - for i:=0 to _ztAbh.count-1 do begin - for j:=0 to length(_ztAbh[i].ziele)-1 do - geaenderteDateien.add(_ztAbh[i].ziele[j].name); - for j:=0 to length(_ztAbh[i].quellen)-1 do - geaenderteDateien.add(_ztAbh[i].quellen[j].name); + for i:=0 to _mglAbh.count-1 do begin + for j:=0 to _mglAbh[i].ziele.count-1 do + geaenderteDateien.add(_mglAbh[i].ziele[j].name); + for j:=0 to _mglAbh[i].quellen.count-1 do + geaenderteDateien.add(_mglAbh[i].quellen[j].name); end; - for i:=0 to _ztAbh.count-1 do - for j:=0 to _ztAbh[i].befehle.count-1 do - befehle.add(_ztAbh[i].befehle[j]); + for i:=0 to _mglAbh.count-1 do + for j:=0 to _mglAbh[i].befehle.count-1 do + befehle.add(_mglAbh[i].befehle[j]); if not unsicher then begin lokTest:=tRegExpr.create; if extractfilepath(ausgabeDatei)=extractfilepath(pruefsummenDatei) then @@ -966,7 +1015,7 @@ begin befehle.add('echo " fertig"'); end; - if _ztAbh.count=0 then + if _mglAbh.count=0 then befehle.add('echo "Es gibt hier nichts zu tun!"'); if ausgabeDatei='' then begin gibAus('befehle:',3); @@ -994,74 +1043,22 @@ begin result:=_mglAbh.count; end; -function tMach.anzZtAbh: longint; -begin - result:=_ztAbh.count; -end; - function tMach.anzDats: longint; begin - result:=length(_dats); + result:=_dats.count; end; -// allgemeine Funktionen ******************************************************* +// allgemeine Funktionen -function quellersetzung(var worin: string; quelle, inputfile: string): boolean; +procedure allgemeineErsetzungen(var worin: string; machDatei: string); var + i: longint; s,anfang,mitte: string; - i,li,re: longint; begin - result:=true; - if quelle<>'' then begin - while pos('%in',worin)>0 do - worin:=copy(worin,1,pos('%in',worin)-1)+quelle+copy(worin,pos('%in',worin)+3,length(worin)); - s:=extractfilename(quelle); - while pos('%ifile',worin)>0 do - worin:=copy(worin,1,pos('%ifile',worin)-1)+s+copy(worin,pos('%ifile',worin)+6,length(worin)); - if pos('.',s)>0 then begin - while s[length(s)]<>'.' do delete(s,length(s),1); - delete(s,length(s),1); - end; - while pos('%basename',worin)>0 do - worin:=copy(worin,1,pos('%basename',worin)-1)+s+copy(worin,pos('%basename',worin)+9,length(worin)); - while pos('%dirname(',worin)>0 do begin - anfang:=erstesArgument(worin,'%dirname('); - mitte:=erstesArgument(worin,')'); - s:=extractfilepath(quelle); - if rightStr(s,1)='/' then - delete(s,length(s),1); - i:=anzCs('/',s)+1; - li:=strtoint(erstesArgument(mitte,',')); - if li<0 then li:=li+i; - if mitte='' then - re:=0 - else - re:=strtoint(mitte); - if re<=0 then re:=re+i; - while li>0 do begin - dec(li); - dec(re); - erstesArgument(s,'/'); - end; - mitte:=''; - while re>0 do begin - dec(re); - mitte:=mitte+'/'+erstesArgument(s,'/'); - end; - delete(mitte,1,1); - worin:=anfang+mitte+worin; - end; - s:=extractfilepath(quelle); - if rightStr(s,1)='/' then - delete(s,length(s),1); - while pos('%dirname',worin)>0 do - worin:=copy(worin,1,pos('%dirname',worin)-1)+s+copy(worin,pos('%dirname',worin)+8,length(worin)); - end; - s:=extractfilepath(inputfile); + s:=extractfilepath(machDatei); if rightStr(s,1)='/' then delete(s,length(s),1); - while pos('%DIRNAME',worin)>0 do - worin:=copy(worin,1,pos('%DIRNAME',worin)-1)+s+copy(worin,pos('%DIRNAME',worin)+8,length(worin)); + ersetzeAlleVorkommen(worin,'%DIRNAME',s); while pos('%num''',worin)>0 do begin anfang:=erstesArgument(worin,'%num'''); mitte:=erstesArgument(worin,''''); @@ -1077,24 +1074,6 @@ begin end; worin:=anfang+mitte+worin; end; - if quelle<>'' then begin - result:=false; - while pos('%nurmit''',worin)>0 do begin - anfang:=erstesArgument(worin,'%nurmit'''); - mitte:=erstesArgument(worin,''''); - if pos(mitte,quelle)=0 then - exit; - worin:=anfang+worin; - end; - while pos('%nurohne''',worin)>0 do begin - anfang:=erstesArgument(worin,'%nurohne'''); - mitte:=erstesArgument(worin,''''); - if pos(mitte,quelle)>0 then - exit; - worin:=anfang+worin; - end; - result:=true; - end; end; end. diff --git a/tools.pas b/tools.pas index 4ba44a7..3b9671b 100644 --- a/tools.pas +++ b/tools.pas @@ -18,7 +18,20 @@ type name: ansiString; aktuell: tAktualitaet; end; - tDateienMitDaten = array of tDateiMitDatum; + tDateienMitDaten = class(tFPList) + function rItem(idx: longint): tDateiMitDatum; inline; + procedure wItem(idx: longint; neu: tDateiMitDatum); inline; + public + property items[idx: longint]: tDateiMitDatum + read rItem + write wItem; default; + procedure mrProper; + function add(neu: tDateiMitDatum): longint; + function last: tDateiMitDatum; + function gleicheNamenWie(dmd: tDateienMitDaten): boolean; + function toString: string; override; + procedure append(dmd: tDateienMitDaten); + end; function min(a1,a2: tAktualitaet): tAktualitaet; inline; overload; function max(a1,a2: tAktualitaet): tAktualitaet; inline; overload; @@ -29,8 +42,7 @@ procedure testeObBefehlLokal(bef, ordner: string; lokTest: tRegExpr); function extrahiereAlleDateien(woraus: string): tMyStringList; function unescape(s: string): string; function escape(s,toe: string; ec: char): string; -function bashMatch(was,worauf: string): boolean; -function gleicheDateinamen(dl1,dl2: tDateienMitDaten): boolean; +procedure ersetzeAlleVorkommen(var worin: string; was,wodurch: string); // Routinen für sha512-Prüfsummen @@ -42,6 +54,77 @@ implementation uses lowlevelunit; +// tDateienMitDaten ************************************************************ + +function tDateienMitDaten.rItem(idx: longint): tDateiMitDatum; +begin + result:=tDateiMitDatum(get(idx)); +end; + +procedure tDateienMitDaten.wItem(idx: longint; neu: tDateiMitDatum); +begin + put(idx,neu); +end; + +procedure tDateienMitDaten.mrProper; +var + i: longint; +begin + for i:=0 to count-1 do + items[i].free; + clear; +end; + +function tDateienMitDaten.add(neu: tDateiMitDatum): longint; +begin + result:=inherited add(neu); +end; + +function tDateienMitDaten.last: tDateiMitDatum; +begin + result:=tDateiMitDatum(inherited last); +end; + +function tDateienMitDaten.gleicheNamenWie(dmd: tDateienMitDaten): boolean; +var + i,j: longint; +begin + result:=count=dmd.count; + if not result then + exit; + for i:=0 to count-1 do begin + result:=false; + for j:=0 to dmd.count-1 do + result:=result or (items[i].name = dmd[j].name); + if not result then exit; + end; +end; + +function tDateienMitDaten.toString: string; +var + i: longint; +begin + result:=''; + for i:=0 to count-1 do + result:=result+''''+items[i].name+''''#10; +end; + +procedure tDateienMitDaten.append(dmd: tDateienMitDaten); +var + i,j: longint; + found: boolean; +begin + for i:=0 to dmd.count-1 do begin + found:=false; + for j:=0 to count-1 do + found:=found or (items[j].name = dmd[i].name); + if not found then + add(dmd[i]); + end; +end; + +// allgemeine Funktionen + function min(a1,a2: tAktualitaet): tAktualitaet; begin if a10 do begin + worin:= + leftStr(worin,pos(was,worin)-1) + + wodurch + + rightStr(worin,length(worin)-pos(was,worin)-length(was)+1); end; end; -- cgit v1.2.3-54-g00ecf