2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 SubHunk() : start(-1), length(0), accepted(Vng::Undecided
), added(0), removed(0) { }
28 Vng::Acceptance accepted
;
35 Private() : lineNumber(-1), ref(1), linesBefore(0), linesAfter(0)
37 SubHunk
*sh
= new SubHunk();
48 int linesBefore
, linesAfter
;
50 QList
<SubHunk
*> subhunks
;
52 QByteArray
patchForAccepted(bool inverse
);
60 Hunk::Hunk(const Hunk
&other
)
72 void Hunk::addLine(const QByteArray
&line
)
76 if(d
->header
.isEmpty()) {
79 QRegExp
regexp("^@@ -[\\d,]+ \\+(\\d+)\\b");
80 if (regexp
.indexIn(header
) != -1)
81 d
->lineNumber
= regexp
.cap(1).toInt();
84 if (line
[0] == '\\') { // "\ No newline at end of file"
86 d
->diff
.chop(1); // TODO should that be 2 on Windows?
89 else if (line
[0] != ' ') {
90 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
91 if (last
->start
< 0) {
92 last
->start
= d
->diff
.size();
93 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
95 else if (last
->start
+ last
->length
< d
->diff
.size()) {
97 d
->subhunks
.append(last
);
98 last
->start
= d
->diff
.size();
99 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
101 last
->length
+=line
.length();
102 if (line
[0] == '-') {
115 d
->diff
.append(line
);
118 Hunk
& Hunk::operator=(const Hunk
&other
)
127 int Hunk::lineNumber() const
129 return d
->lineNumber
;
132 int Hunk::lineNumber(int subHunk
) const
134 Q_ASSERT(subHunk
< d
->subhunks
.count());
135 SubHunk
*sh
= d
->subhunks
[subHunk
];
136 return sh
->lineNumber
;
139 QByteArray
Hunk::patch() const
144 bool Hunk::isEmpty() const
146 return d
->diff
.isEmpty();
149 Vng::Acceptance
Hunk::acceptance() const
151 Vng::Acceptance a
= Vng::Undecided
;
152 for (int i
= 0; i
< d
->subhunks
.count(); i
++) {
153 SubHunk
*sh
= d
->subhunks
[i
];
154 if (a
!= sh
->accepted
) {
155 if (a
== Vng::Undecided
)
158 return Vng::MixedAcceptance
;
164 void Hunk::setAcceptance(Vng::Acceptance acceptance
)
166 foreach(SubHunk
*sh
, d
->subhunks
)
167 sh
->accepted
= acceptance
;
170 Vng::Acceptance
Hunk::acceptance(int subHunk
) const
172 Q_ASSERT(subHunk
< d
->subhunks
.count());
173 SubHunk
*sh
= d
->subhunks
[subHunk
];
177 void Hunk::setAcceptance(int subhunk
, Vng::Acceptance accepted
)
179 Q_ASSERT(subhunk
< d
->subhunks
.count());
180 SubHunk
*sh
= d
->subhunks
[subhunk
];
181 sh
->accepted
= accepted
;
184 QByteArray
Hunk::header() const
189 QByteArray
Hunk::subHunk(int index
) const
191 if (d
->subhunks
.count() == 0)
193 Q_ASSERT(index
>= 0);
194 Q_ASSERT(index
< d
->subhunks
.count());
195 SubHunk
*sh
= d
->subhunks
[index
];
196 return d
->diff
.mid(sh
->start
, sh
->length
);
199 int Hunk::subHunkCount() const
201 return d
->subhunks
.count();
204 QByteArray
Hunk::rejectedPatch() const
206 return d
->patchForAccepted(true);
209 QByteArray
Hunk::acceptedPatch() const
211 return d
->patchForAccepted(false);
214 QByteArray
Hunk::Private::patchForAccepted(bool inverse
)
217 QDataStream
out (&patch
, QIODevice::WriteOnly
);
218 const char *myDiff
= diff
.data();
219 const char *space
= " ";
220 int offsetInDiff
= 0; // position in diff
221 int before
= linesBefore
; // for the header
222 foreach(SubHunk
*sh
, subhunks
) {
223 out
.writeRawData(myDiff
+ offsetInDiff
, sh
->start
- offsetInDiff
); // write until start
224 if (!inverse
&& sh
->accepted
== Vng::Accepted
|| inverse
&& sh
->accepted
!= Vng::Accepted
) {
225 out
.writeRawData(myDiff
+ sh
->start
, sh
->length
);
228 const int end
= sh
->start
+ sh
->length
;
229 bool startOfLine
= true;
231 int lastLineStart
= 0;
232 for (int x
= sh
->start
; x
< end
; x
++) {
235 skipLine
= myDiff
[x
] == '-';
237 out
.writeRawData(space
, 1);
238 lastLineStart
= x
+ 1;
242 if (myDiff
[x
] == '\n') {
245 out
.writeRawData(myDiff
+ lastLineStart
, x
- lastLineStart
+ 1);
248 before
+= sh
->added
- sh
->removed
;
250 offsetInDiff
= sh
->start
+ sh
->length
;
252 out
.writeRawData(myDiff
+ offsetInDiff
, diff
.size() - offsetInDiff
);
255 QString header
= "@@ -"+ QString::number(lineNumber
) +","+ QString::number(before
)
256 +" +"+ QString::number(lineNumber
) +","+ QString::number(linesAfter
) + " @@\n";
259 answer
.append(header
);
260 answer
.append(patch
);
264 int Hunk::linesAdded() const
267 foreach(SubHunk
*sh
, d
->subhunks
)
272 int Hunk::linesRemoved() const
275 foreach(SubHunk
*sh
, d
->subhunks
)
276 total
+= sh
->removed
;