[Date Prev][Date Next][Thread Prev][][Date Index][Thread Index]

History bug

I have a 'fix' for a bug that I'm having a hard time reproducing in a
way easy for sharing. The bug becomes obvious only when setting
toggle-debug-on-error and then reloading an old emacs-w3m session. In
that case, function w3m-history-set-plist throws an error because its
arg PLIST is NIL instead of being an expected (nil nil). How exactly
this happened in the first place is unclear to me, but the following
four additional lines (marked with '; <<---') fixes the issue. Note that
without the fix, the line marked '; !!!' can attempt to perform
 (nthcdr -1 ..) because the length of NIL is zero.

(defun w3m-history-set-plist (plist property value)
  "Similar to `plist-put' but PLIST is actually modified.
If VALUE is nil, the pair of PROPERTY and VALUE is removed from PLIST.
Exceptionally, if PLIST is made empty because of removing, it will be
instead set to `(nil nil)'.  Return PLIST itself."
  (unless plist                   ; <<---
    (setq plist (list nil nil)))  ; <<---
  (let ((pair (memq property plist)))
    (if pair
	(if value
	    (setcar (cdr pair) value)
	  (if (eq (car plist) property)
		(setcar plist (nth 2 plist))
		(setcar (cdr plist) (nth 3 plist))
		(setcdr (cdr plist) (nthcdr 4 plist)))
	    (setcdr (nthcdr (- (length plist) (length pair) 1) plist) ; !!!
		    (nthcdr 2 pair))))
      (when value
	(setcdr (nthcdr (1- (length plist)) plist) (list property value)))))

(defun w3m-history-modify-properties (old new &optional replace)
  "Merge NEW plist into OLD plist and return a modified plist.
If REPLACE is non-nil, OLD will be replaced with NEW.  OLD plist is
modified and also the new value is shared in all the history
elements containing OLD plist.  Properties whose values are nil are
removed from OLD plist, but if OLD plist is made empty because of
removing, it will be instead set to `(nil nil)'."
    (if replace
	  (setcar old (car new))
	  (setcdr old (or (cdr new) (list nil))))
      (while new
	(w3m-history-set-plist old (car new) (cadr new))
	(setq new (cddr new))))
    (unless old                   ; <<---
      (setq old (list nil nil)))  ; <<---
    (setq new (copy-sequence old))
    (while new
      (w3m-history-set-plist old (car new) (cadr new))
      (setq new (cddr new)))))

CA45 09B5 5351 7C11 A9D1  7286 0036 9E45 1595 8BC0