applydiff()
| Function group | Execute on client | Platform(s) |
|---|---|---|
| String | NO | All |
Syntax
applydiff(text,patch[,flags=0,linesep])
Description
Applies patch to text. Returns a row of success, text, errortext, errorhunk and hunks. Hunks are located by the lines they expect, not the @@ header. Flags is a sum of kDiff... constants.
This function applies a unified diff to text, and is the counterpart to unifieddiff(), which produces one. patch is read as a series of @@ hunks; anything before the first of them, such as the --- and +++ file headers other tools write, is ignored.
The result is a row rather than the patched text on its own, so that a caller can tell how the patch was read and not merely whether it worked.
| Col name | Type | Description |
|---|---|---|
| success | Boolean | true when every hunk was applied |
| text | Character | the patched text, and empty when the patch was refused |
| errortext | Character | why the patch was refused, in a form you can show to whoever wrote it |
| errorhunk | Integer | which hunk was refused, counting the hunks of patch from one, or zero when none was |
| hunks | List | where each hunk was applied, described below. It is empty unless the patch applied |
A hunk is found by looking for the lines it says it expects its unchanged lines together with the ones it removes rather than by trusting the line numbers in its @@ header. Those are read as a hint at where to start looking, because the text above a hunk often moves after a patch is written, which leaves the header wrong while the hunk itself is still perfectly good. Where those lines are found in more than one place, the occurrence nearest the hint is the one used.
Two occurrences equally near the hint are a coin toss, so the hunk is refused as ambiguous rather than applied somewhere the caller may not have meant. Adding another line or two of context to the hunk is usually enough to tell them apart, and kDiffApplyNearestOnTie asks for the earlier one instead.
The hunks column reports where each hunk went, so that a patch which applied at a different place from the one it named does not do so silently.
| Col name | Description |
|---|---|
| hunk | the hunk's position in patch, counting from one |
| hintline | the line its @@ header claimed |
| appliedat | the line it was actually applied at |
| offset | how far that was from the hint, negative when the hunk moved earlier in the text. Test that every hunk has an offset of zero if you want a patch which applied exactly where it said it would |
flags is the sum of any of the following constants, and defaults to zero.
| Constant | Description |
|---|---|
| kDiffApplyNearestOnTie | Where a hunk could be applied at two places equally near its header, use the earlier one instead of reporting the hunk as ambiguous |
| kDiffApplyAllowNoContext | Apply a hunk which has no context lines to anchor it, placing it at the line named in its header. Without this such a hunk is refused |
| kDiffApplyReverse | Undo the patch: find the lines it would have produced and put back the ones it replaced. Everything above applies unchanged, only in the other direction. Applying a patch and then reversing it returns the text you started with, which is one way to check a patch before you keep the result |
| kDiffKeepTrailingEmptyLine | Treat a line ending at the very end of text as starting an empty last line, rather than as ending the last one. Use it where a line ending at the end of the text is part of the data rather than a terminator.If this patch was created using unifieddiff(), you must have used the constant there as well |
A hunk which only adds lines has nothing to search for, so its header is the only thing saying where it belongs. Placing it is then a guess rather than a match, and it is refused unless you pass kDiffApplyAllowNoContext. Empty text is the exception: there is only one place the lines can go, so such a patch applies without the flag.
A patch is applied whole or not at all. If any hunk cannot be placed, or two hunks lay claim to the same lines, nothing is changed and the function reports which hunk was at fault. Where a hunk matched nowhere, errortext also names the line at which it came closest and how many of its lines differ there, which is usually enough to see the mistake without comparing the whole text by hand.
An empty patch is what unifieddiff() returns for a text compared with itself, so it applies cleanly and changes nothing. A patch which has content but no @@ line is not a patch at all and is refused.
Hunks need not be given in the order they occur in the text. The lines of a hunk may be written with all of its removals before all of its additions, as "diff -u" and "git diff" write them, or with each removed line followed by the line replacing it, as unifieddiff() writes them; both say the same thing. The line counts in an @@ header are not used, since the hunk's own lines already say how long it is, and a header may be written in the shorter @@ -12 +12 @@ form or carry a section heading after its closing @@. An unchanged line which is blank may be written as a single space, as the format intends, or left empty, as editors which strip trailing spaces leave it.
text and patch are split into lines at a carriage return, a line feed, or a carriage return and line feed together, whichever each line happens to end with, so text which has picked up mixed line endings is still read one line per line. A single line ending at the very end of a text is treated as ending the last line rather than starting an empty one, unless kDiffKeepTrailingEmptyLine is passed.
The lines of the patched text are joined with linesep. If you omit it the function uses whichever line ending it finds in text, or in patch when text is empty, so the result is punctuated like the text it came from. Text with no line ending at all gives a result joined with line feeds.
Suppose text holds this method:
Do lList.$define(lAmount)
Calculate lTotal as 0
Calculate lCount as 0
For lList.$line from 1 to lList.$linecount step 1
Calculate lTotal as lTotal+lList.lAmount
End For
Calculate lAverage as lTotal/lCount
Quit method lAverage
and it is to gain a running count, round the average, and stop dividing by zero. The patch unifieddiff() writes for that change is:
@@ -3,6 +3,9 @@
Calculate lCount as 0
For lList.$line from 1 to lList.$linecount step 1
Calculate lTotal as lTotal+lList.lAmount
+Calculate lCount as lCount+1
End For
+If lCount
-Calculate lAverage as lTotal/lCount
+Calculate lAverage as rnd(lTotal/lCount,2)
+End If
Quit method lAverage
The @@ line says the hunk covers six lines of the original beginning at line 3, and nine of the result beginning at line 3. Of the lines below it, those beginning with a space are unchanged and are what the hunk is recognized by, those beginning with "+" are added, and the line which was rewritten appears as the line removed followed by the line replacing it. Note that the three unchanged lines above the change, and the one below it, are there only to say where the change belongs; they are not altered.
Passing that patch with the original text returns the changed method and passing it with the changed method and kDiffApplyReverse returns the original.