+;;; GETF, REMF, and REMPROP
+;;;
+
+(defun getf (place indicator &optional default)
+ "Return PLACE's PROPNAME property, or DEFAULT if not present."
+ (while (and place (not (eq (car place) indicator)))
+ (setq place (cdr (cdr place))))
+ (if place
+ (car (cdr place))
+ default))
+
+(defmacro getf$setf$method (place indicator default &rest newval)
+ "SETF method for GETF. Not for public use."
+ (case (length newval)
+ (0 (setq newval default default nil))
+ (1 (setq newval (car newval)))
+ (t (error "Wrong number of arguments to (setf (getf ...)) form")))
+ (let ((psym (gentemp)) (isym (gentemp)) (vsym (gentemp)))
+ (list 'let (list (list psym place)
+ (list isym indicator)
+ (list vsym newval))
+ (list 'while
+ (list 'and psym
+ (list 'not
+ (list 'eq (list 'car psym) isym)))
+ (list 'setq psym (list 'cdr (list 'cdr psym))))
+ (list 'if psym
+ (list 'setcar (list 'cdr psym) vsym)
+ (list 'setf place
+ (list 'nconc place (list 'list isym newval))))
+ vsym)))
+
+(defsetf getf
+ getf$setf$method)
+
+(defmacro remf (place indicator)
+ "Remove from the property list at PLACE its PROPNAME property.
+Returns non-nil if and only if the property existed."
+ (let ((psym (gentemp)) (isym (gentemp)))
+ (list 'let (list (list psym place) (list isym indicator))
+ (list 'cond
+ (list (list 'eq isym (list 'car psym))
+ (list 'setf place (list 'cdr (list 'cdr psym)))
+ t)
+ (list t
+ (list 'setq psym (list 'cdr psym))
+ (list 'while
+ (list 'and (list 'cdr psym)
+ (list 'not
+ (list 'eq (list 'car (list 'cdr psym))
+ isym)))
+ (list 'setq psym (list 'cdr (list 'cdr psym))))
+ (list 'cond
+ (list (list 'cdr psym)
+ (list 'setcdr psym
+ (list 'cdr
+ (list 'cdr (list 'cdr psym))))
+ t)))))))
+
+(defun remprop (symbol indicator)
+ "Remove SYMBOL's PROPNAME property, returning non-nil if it was present."
+ (remf (symbol-plist symbol) indicator))
+
+\f