/applications/wiki/src/wiki_diff.erl

https://github.com/schemeway/yaws · Erlang · 92 lines · 64 code · 20 blank · 8 comment · 0 complexity · 160a3e9527f6fc28b42d5f4f186eed50 MD5 · raw file

  1. -module(wiki_diff).
  2. %% File : diff.erl
  3. %% Author : Joe Armstrong (joe@bluetail.com)
  4. %% Purpose : Diff of two files (like Diff and patch).
  5. %% diff(New, Old) -> Patch
  6. %% patch(New, Patch) -> Old
  7. %% patchL(New, [Patch]) -> Old'
  8. %% -compile(export_all).
  9. -export([diff/2, diff_files/2, patch/2, patchL/2]).
  10. -export([test/0]).
  11. -import(lists, [foldl/3, reverse/1]).
  12. test() ->
  13. diff_files("diff.erl", "diff.erl.old").
  14. diff_files(F1, F2) ->
  15. {ok, B1} = file:read_file(F1),
  16. {ok, B2} = file:read_file(F2),
  17. diff(binary_to_list(B1), binary_to_list(B2)).
  18. diff(New, Old) ->
  19. Patch = diff(str2lines(Old), str2lines(New), []),
  20. %% io:format("Patch size=~p~n",[size(Patch)]),
  21. check(Patch, New, Old),
  22. Patch.
  23. check(Patch, New, Old) ->
  24. case patch(New, Patch) of
  25. Old ->
  26. true;
  27. _ ->
  28. exit(oops)
  29. end.
  30. patchL(New, Patches) ->
  31. foldl(fun(Patch, N) -> patch(N, Patch) end, New, Patches).
  32. patch(New, Patch) ->
  33. sneaky_flatten(patch1(binary_to_term(Patch), str2lines(New))).
  34. patch1([{L1,L2}|T], New) -> [get_lines(L1, L2, New)|patch1(T, New)];
  35. patch1([H|T], New) -> [H|patch1(T, New)];
  36. patch1([], _) -> [].
  37. get_lines(_, L2, [{L2,S}|_]) -> S;
  38. get_lines(L1, L2, [{L1,S}|T]) -> [S|get_lines(L1+1, L2, T)];
  39. get_lines(L1, L2, [_|T]) -> get_lines(L1, L2, T).
  40. sneaky_flatten(L) ->
  41. binary_to_list(list_to_binary(L)).
  42. diff([], _, Patch) ->
  43. term_to_binary(reverse(Patch));
  44. diff(Old = [{_,Str}|T], New, Patch) ->
  45. case match(Old, New) of
  46. {yes, Ln, Ln, Old1} ->
  47. case Str of
  48. "\n" ->
  49. diff(Old1, New, [Str|Patch]);
  50. _ ->
  51. diff(Old1, New, [{Ln,Ln}|Patch])
  52. end;
  53. {yes, L1, L2, Old1} ->
  54. diff(Old1, New, [{L1,L2}|Patch]);
  55. no ->
  56. diff(T, New, [Str|Patch])
  57. end.
  58. match(X=[{Ln,Str}|T], [{L1,Str}|T1]) -> extend_match(T, T1, L1, L1);
  59. match(X, [_|T]) -> match(X, T);
  60. match(X, []) -> no.
  61. extend_match([{_,S}|T1], [{L2,S}|T2], L1, _) -> extend_match(T1, T2, L1, L2);
  62. extend_match(X, _, L1, L2) -> {yes, L1, L2, X}.
  63. str2lines(L) -> str2lines(L, 1, [], []).
  64. str2lines([H|T], Line, C, L) ->
  65. case H of
  66. $\n -> str2lines(T, Line+1,[],[{Line,reverse([$\n|C])}|L]);
  67. _ -> str2lines(T, Line, [H|C], L)
  68. end;
  69. str2lines([], Line, [], L) ->
  70. reverse(L);
  71. str2lines([], Line, C, L) ->
  72. reverse([{Line,reverse(C)}|L]).