Add error checks to various exported procedures, since mistakes in
authorChris Hanson <org/chris-hanson/cph>
Wed, 25 Aug 1993 05:49:38 +0000 (05:49 +0000)
committerChris Hanson <org/chris-hanson/cph>
Wed, 25 Aug 1993 05:49:38 +0000 (05:49 +0000)
these arguments cause obscure bugs and because the procedures can
afford the time.  Also abstract a few common patterns.

v7/src/edwin/txtprp.scm

index 59469f6a4e720ad9106d969195675eb50b3a47d5..79fb274b747b584857f40be4c65b51f932f0e5df 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;;    $Id: txtprp.scm,v 1.7 1993/08/23 21:14:35 cph Exp $
+;;;    $Id: txtprp.scm,v 1.8 1993/08/25 05:49:38 cph Exp $
 ;;;
 ;;;    Copyright (c) 1993 Massachusetts Institute of Technology
 ;;;
@@ -45,7 +45,7 @@
 ;;;; Based on the text-properties in GNU Emacs
 
 (declare (usual-integrations))
-
+\f
 (define-structure (interval
                   (constructor make-interval
                                (total-length start properties size)))
   total-length
   start
   properties
-  size
-  )
-\f
-;; export
+  size)
+
 (define (add-text-properties group start end plist)
-  (record-property-changes!
-   (step (if (group-text-properties group)
-            (find-interval group start)
-            (create-initial-interval group))
-        start
-        end
-        (lambda (i)
-          (add-properties plist i))
-        (lambda (i)
-          (not (add-properties? plist (interval-properties i))))
-        group)
-   group))
+  (validate-region-arguments group start end 'ADD-TEXT-PROPERTIES)
+  (step group start end
+       (lambda (i)
+         (add-properties plist i))
+       (lambda (i)
+         (not (add-properties? plist (interval-properties i))))))
 
-;; export
 (define (set-text-properties group start end plist)
-  (record-property-changes!
-   (step (if (group-text-properties group)
-            (find-interval group start)
-            (create-initial-interval group))
-        start
-        end
-        (lambda (i)
-          (set-properties plist i))
-        (lambda (i)
-          (not (set-properties? plist (interval-properties i))))
-        group)
-   group))
+  (validate-region-arguments group start end 'SET-TEXT-PROPERTIES)
+  (step group start end
+       (lambda (i)
+         (set-properties plist i))
+       (lambda (i)
+         (not (set-properties? plist (interval-properties i))))))
 
-;; export
 (define (remove-text-properties group start end plist)
+  (validate-region-arguments group start end 'REMOVE-TEXT-PROPERTIES)
+  (step group start end
+       (lambda (i)
+         (remove-properties plist i))
+       (lambda (i)
+         (not (remove-properties? plist (interval-properties i))))))
+
+(define (validate-region-arguments group start end procedure)
+  (validate-group group procedure)
+  (validate-group-index group start procedure)
+  (validate-group-index group end procedure)
+  (if (not (fix:<= start end))
+      (error "Indexes incorrectly related:" start end procedure)))
+
+(define (validate-point-arguments group index procedure)
+  (validate-group group procedure)
+  (validate-group-index group index procedure))
+
+(define (validate-group group procedure)
+  (if (not (group? group))
+      (error:wrong-type-argument group "group" procedure)))
+
+(define (validate-group-index group index procedure)
+  (if (not (fix:fixnum? index))
+      (error:wrong-type-argument index "fixnum" procedure))
+  (if (not (and (fix:<= (group-start-index group) index)
+               (fix:<= index (group-end-index group))))
+      (error:bad-range-argument index procedure)))
+\f
+;;; This also needs to test whether or not the left split is
+;;; necessary.  Maybe rather than a separate test we could grab the
+;;; plist before, let the proc do its magic, and then take action
+;;; afterword.
+
+(define (step group start end proc test)
+  (define (loop i lst)
+    ;; we now know that we are starting on the begining of an interval
+    (let ((next (next-interval i))
+         (p (interval-properties i))
+         (start (interval-start i)))
+      (let ((end* (if next
+                     (interval-start next)
+                     (fix:+ (interval-start i)
+                            (interval-length i)))))
+       (cond ((fix:= end end*)
+              (if (proc i)
+                  (cons (list start end p) lst)
+                  lst))
+             ((fix:< end end*)
+              (if (proc (split-interval-left i end group))
+                  (cons (list start end lst) lst)
+                  lst))
+             (else
+              (loop next
+                    (if (proc i)
+                        (cons (list start end* p) lst)
+                        lst)))))))
   (record-property-changes!
-   (step (if (group-text-properties group)
-            (find-interval group start)
-            (create-initial-interval group))
-        start
-        end
-        (lambda (i)
-          (remove-properties plist i))
-        (lambda (i)
-          (not (remove-properties? plist (interval-properties i))))
-        group)
+   (let ((i
+         (if (group-text-properties group)
+             (find-interval group start)
+             (create-initial-interval group))))
+     (let ((start* (interval-start i)))
+       (cond ((group-start-changes-index group)
+             (lambda (gsc)
+               (set-group-start-changes-index!
+                group
+                (if (fix:< start gsc) start gsc))
+               (set-group-end-changes-index!
+                group
+                (let ((gec (group-end-changes-index group)))
+                  (if (fix:> end gec) end gec)))))
+            (else
+             (set-group-start-changes-index! group start)
+             (set-group-end-changes-index! group end)))
+       (if (fix:= start start*)
+          (loop i '())
+          (let ((no-split? (test i))
+                (next (next-interval i)))
+            (cond ((and no-split?
+                        (or (not next) (<= end (interval-start next))))
+                   '())
+                  (no-split?
+                   (loop next
+                         '()))
+                  (else
+                   (loop (split-interval-right i start group)
+                         '())))))))
    group))
 
 (define (record-property-changes! p group)
        true)
       false))
 \f
-;; export
 (define (text-properties-at index group)
+  (validate-point-arguments group index 'TEXT-PROPERTIES-AT)
   (if (group-text-properties group)
       (interval-properties (find-interval group index))
       default-properties))
 
 (define (get-property-at prop index group)
+  (validate-point-arguments group index 'GET-PROPERTY-AT)
   (if (group-text-properties group)
       (get-property prop (interval-properties (find-interval group index)))
       #f))
 ;;; The next four procedures are all about the same
 ;;; and none have been tested.
 
-;; export
 (define (next-property-change group index)
+  (validate-point-arguments group index 'NEXT-PROPERTY-CHANGE)
   (and (group-text-properties group)
        (let ((z (find-interval group index)))
         (let ((p1 (interval-properties z)))
                      (loop (next-interval next))
                      (interval-start next))))))))
 
-;; export
 (define (next-specific-property-change group index prop)
+  (validate-point-arguments group index 'NEXT-SPECIFIC-PROPERTY-CHANGE)
   (and (group-text-properties group)
        (let ((z (find-interval group index)))
         (let ((p (assq prop (interval-properties z))))
                      (loop (next-interval next))
                      (interval-start next))))))))
 
-;; export
 (define (previous-property-change group index)
+  (validate-point-arguments group index 'PREVIOUS-PROPERTY-CHANGE)
   (and (group-text-properties group)
        (let ((z (find-interval group index)))
         (let ((p1 (interval-properties z)))
                                                  (interval-properties prev))
                      (loop (previous-interval prev))
                      (interval-start prev))))))))
-;; export
+
 (define (prev-specific-property-change group index prop)
+  (validate-point-arguments group index 'PREV-SPECIFIC-PROPERTY-CHANGE)
   (and (group-text-properties group)
        (let ((z (find-interval group index)))
         (let ((p (assq prop (interval-properties z))))
 ;;; immediately adjacent to one another, insertions may occur in
 ;;; between the regions, but not inside of them.
 
-;; export
 (define (text-not-insertable? group start)
   (and (not (let ((root (group-text-properties group)))
              (or (not root)
                             (interval-property (next-interval interval)
                                                'READ-ONLY #f)))))))))
 
-;; export
-#|
-(define (update-intervals-for-insertion! group start amount)
-  (let ((root (group-text-properties group)))
-    (cond ((not root)
-          unspecific)
-         ((fix:= start 0)
-          (left-insert (leftmost-interval root) amount group))
-         ((fix:= start (interval-total-length root))
-          (right-insert (rightmost-interval root) amount group))
-         (else
-          (let ((interval (find-interval group start)))
-            (cond ((fix:= start (interval-start interval))
-                   (left-insert interval amount group))
-                  ((fix:< start (interval-end interval))
-                   (add-amount-up-tree interval amount))
-                  (else
-                   (right-insert interval amount group))))))))
-|#
 (define (update-intervals-for-insertion! group start amount)
   (if (group-text-properties group)
       (begin
        (add-amount-up-tree (find-interval group start) amount)
        (set-text-properties group start (fix:+ start amount) '()))))
-  
-;; export
+
 (define (text-not-deleteable? group start end)
   (and (group-text-properties group)
        (not (eq? 'FULLY (group-writable? group)))
               (and next
                    (fix:> end (interval-start next))
                    (loop next)))))))
-\f
-;; export
-#|
-(define (update-intervals-for-deletion! group start end)
-  (if (group-text-properties group)
-      (let loop ((start start))
-       (let ((interval (find-interval group start)))
-         (let ((start* (interval-start interval))
-               (length (interval-length interval)))
-           (let ((end* (fix:+ start* length)))
-             (if (fix:<= end end*)
-                 (if (and (fix:= start start*)
-                          (fix:= end end*))
-                     (delete-interval interval group)
-                     (add-amount-up-tree interval
-                                         (fix:- 0 (fix:- end start))))
-                 (begin
-                   (if (fix:= start start*)
-                       (delete-interval interval group)
-                       (add-amount-up-tree interval
-                                           (fix:- 0 (fix:- end* start))))
-                   (loop end*)))))))))
-|#
+
 (define (update-intervals-for-deletion! group start end)
   (if (group-text-properties group)
       (letrec ((loop
 ;;; These procedures are called from the undo code to preserve the
 ;;; properties in text that is being deleted.
 
-;; export
 (define (group-extract-properties group start end)
   (and (group-text-properties group)
        (let loop ((interval (find-interval group start))
                     (let ((next (next-interval interval)))
                       (loop next (interval-start next)))))))))
 
-;; export
 (define (group-reinsert-properties! group index end-index properties)
   index
   end-index
   (if properties
-      (for-each (lambda (x) (set-text-properties
-                            group
-                            (vector-ref x 0)
-                            (vector-ref x 1)
-                            (vector-ref x 2)))
+      (for-each (lambda (x)
+                 (set-text-properties group
+                                      (vector-ref x 0)
+                                      (vector-ref x 1)
+                                      (vector-ref x 2)))
                properties)))
 \f
-;;; this also needs to test weather or not the left split is necessary.
-;;; maybe rather than a seperate test we could grab the plist before,
-;;; let the proc do its magic, and then take action afterword.
-(define (step i start end proc test group)
-
-  (define (loop i lst)
-    ;; we now know that we are starting on the begining of an interval
-    (let ((next (next-interval i))
-         (p (interval-properties i))
-         (start (interval-start i)))
-      (let ((end* (if next
-                     (interval-start next)
-                     (fix:+ (interval-start i)
-                            (interval-length i)))))
-       (cond ((fix:= end end*)
-              (if (proc i)
-                  (cons (list start end p) lst)
-                  lst))
-             ((fix:< end end*)
-              (if (proc (split-interval-left i end group))
-                  (cons (list start end lst) lst)
-                  lst))
-             (else
-              (loop next
-                    (if (proc i)
-                        (cons (list start end* p) lst)
-                        lst)))))))
-  (let ((start* (interval-start i)))
-    (cond ((group-start-changes-index group)
-          (lambda (gsc)
-            (set-group-start-changes-index!
-             group
-             (if (fix:< start gsc) start gsc))
-            (set-group-end-changes-index!
-             group
-             (let ((gec (group-end-changes-index group)))
-               (if (fix:> end gec) end gec)))))
-         (else
-          (set-group-start-changes-index! group start)
-          (set-group-end-changes-index! group end)))
-    (if (fix:= start start*)
-       (loop i '())
-       (let ((no-split? (test i))
-             (next (next-interval i)))
-         (cond ((and no-split?
-                     (or (not next) (<= end (interval-start next))))
-                '())
-               (no-split?
-                (loop next
-                      '()))
-               (else
-                (loop (split-interval-right i start group)
-                      '())))))))
-\f
 ;;;; Property Lists
 ;;;; these are complicated becase of the desire to recognize
 ;;;; unnecessary changes
 (define-integrable default-properties '())
 
-;; export
 (define (get-property prop plist)
   (assq prop plist))
 
        (smart-connect! p b a)
        (connect-left! b a)
        (connect-right! a y)
-       
+
        (set-interval-total-length! a (fix:+ (fix:+ lx la) ly))
        (set-interval-total-length! b (fix:+ (fix:+ (fix:+ lx la) ly)
                                             (fix:+ lz lb)))
 
   ;;     a                 b
   ;;    / \               / \
-  ;;   X   c             /   \ 
+  ;;   X   c             /   \
   ;;      / \   -->     a     c
-  ;;     b   Z         / \   / \ 
+  ;;     b   Z         / \   / \
   ;;    / \           X  Y1 Y2  Z
   ;;   Y1  Y2
   (define-integrable (double-left a)
           (lc (interval-length c))
           (lx (left-total-length a))
           (ly1 (left-total-length b))
-          (ly2 (right-total-length b)) 
+          (ly2 (right-total-length b))
           (lz (right-total-length c))
           (nx (size (interval-left a)))
           (ny1 (size (interval-left b)))
       (connect-right! b c)
       (connect-right! a y1)
       (connect-left! c y2)
-      
+
       (set-interval-total-length! a (fix:+ (fix:+ lx ly1) la))
       (set-interval-total-length! b
                                  (fix:+ (fix:+ (fix:+ lx ly1) (fix:+ ly2 lz))