68acdcbafaa7029637a4fe106ab113ca112fac34
[mes.git] / build-aux / diff.scm
1 #! /bin/sh
2 # -*-scheme-*-
3 exec ${GUILE-guile} -L $(dirname 0) -e '(diff)' -s "$0" "$@"
4 !#
5
6 ;;; Mes --- Maxwell Equations of Software
7 ;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
8 ;;;
9 ;;; mes-snarf.scm: This file is part of Mes.
10 ;;;
11 ;;; Mes is free software; you can redistribute it and/or modify it
12 ;;; under the terms of the GNU General Public License as published by
13 ;;; the Free Software Foundation; either version 3 of the License, or (at
14 ;;; your option) any later version.
15 ;;;
16 ;;; Mes is distributed in the hope that it will be useful, but
17 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;;; GNU General Public License for more details.
20 ;;;
21 ;;; You should have received a copy of the GNU General Public License
22 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
23
24 (define-module (diff)
25   #:use-module (srfi srfi-1)
26   #:use-module (srfi srfi-9)
27   #:use-module (ice-9 rdelim)
28   #:export (main))
29
30 (cond-expand
31  (mes
32   (define %scheme "mes"))
33  (guile-2
34   (define %scheme "guile")
35   (define-macro (mes-use-module . rest) #t))
36  (guile
37   (use-modules (ice-9 syncase))
38   (define %scheme "guile")
39   (define-macro (mes-use-module . rest) #t)))
40
41 (mes-use-module (mes guile))
42
43 (format (current-error-port) "diff[~a]...\n" %scheme)
44
45 (define (plus a)
46   (string-append "+" a))
47 (define (minus a)
48   (string-append "-" a))
49 (define (keep a)
50   (string-append " " a))
51
52 (define-record-type <hunk> (make-hunk context after removed added)
53   hunk?
54   (context hunk.context)
55   (after hunk.after)
56   (removed hunk.removed)
57   (added hunk.added))
58
59 (define (hunk->lines o)
60   (append `(,(format #f "@@ -~a,~a +~a,~a" (length (hunk.removed o)) (+ 3 (car (hunk.context o))) (length (hunk.added o)) (+ 3 (cadr (hunk.context o))))
61             ,@(map keep (filter identity (cddr (hunk.context o)))))
62           (map minus (hunk.removed o))
63           (map plus (hunk.added o))
64           (map keep (hunk.after o))))
65
66 (define (safe-list-head lst n)
67   (list-head lst (min n (length lst))))
68
69 (define (line-equal? a b)
70   (equal? (string-trim-right a) (string-trim-right b)))
71
72 ;; naive diff
73 (define (diff a b)
74   (let ((a-lines (string-split (with-input-from-file a read-string) #\newline))
75         (b-lines (string-split (with-input-from-file b read-string) #\newline)))
76     (let loop ((context '(1 1 #f #f #f)) (a-lines a-lines) (b-lines b-lines))
77       ;;(format (current-error-port) "loop context=~s\n" context)
78       (cond ((and (null? a-lines) (null? b-lines)) '())
79             ((null? a-lines)
80              (list (make-hunk context (safe-list-head a-lines 3) '() b-lines)))
81             ((null? b-lines)
82              (list (make-hunk context (safe-list-head a-lines 3) a-lines '())))
83             ((line-equal? (car a-lines) (car b-lines))
84              (loop `(,(1+ (car context))
85                      ,(1+ (cadr context))
86                      ,@(cdddr context)
87                      ,(car a-lines))
88                    (cdr a-lines) (cdr b-lines)))
89             (else
90              (cond ((and (pair? (cdr b-lines)) (line-equal? (car a-lines) (cadr b-lines)))
91                     (cons (make-hunk context (safe-list-head a-lines 3) '() (list (car b-lines)))
92                           (loop `(,(+ 1 (car context))
93                                   ,(+ 2 (cadr context))
94                                   ,@(cdddr context)
95                                   ,(car a-lines))
96                                 (cdr a-lines) (cddr b-lines))))
97                    ((and (pair? (cdr a-lines)) (line-equal? (cadr a-lines) (car b-lines)))
98                     (cons (make-hunk context (safe-list-head a-lines 3) (list (car a-lines)) '())
99                           (loop `(,(+ 2 (car context))
100                                   ,(+ 1 (cadr context))
101                                   ,@(cddddr context)
102                                   ,(car a-lines)
103                                   ,(cadr a-lines))
104                                 (cddr a-lines) (cdr b-lines))))
105                    (else (cons (make-hunk context (safe-list-head a-lines 3) (list (car a-lines)) (list (car b-lines)))
106                                (loop `(,(1+ (car context))
107                                        ,(1+ (cadr context))
108                                        ,@(cdddr context)
109                                        ,(car a-lines))
110                                      (cdr a-lines) (cdr b-lines))))))))))
111
112 (define (main args)
113   (let* ((files (cdr args))
114          (files (if (string-prefix? "-" (car files)) (cdr files) files))
115          (hunks (apply diff (list-head files 2))))
116     (when (pair? hunks)
117       (display (string-join (append-map hunk->lines hunks) "\n"))
118       (newline)
119       (exit 1))))