+(defun ses-cell-property-get-fun (property-name cell)
+ ;; To speed up property fetching, each time a property is found it is placed
+ ;; in the first position. This way, after the first get, the full property
+ ;; list needs to be scanned only when the property does not exist for that
+ ;; cell.
+ (let* ((plist (aref cell 4))
+ (ret (plist-member plist property-name)))
+ (if ret
+ ;; Property was found.
+ (let ((val (cadr ret)))
+ (if (eq ret plist)
+ ;; Property found is already in the first position, so just return
+ ;; its value.
+ val
+ ;; Property is not in the first position, the following will move it
+ ;; there before returning its value.
+ (let ((next (cddr ret)))
+ (if next
+ (progn
+ (setcdr ret (cdr next))
+ (setcar ret (car next)))
+ (setcdr (last plist 1) nil)))
+ (aset cell 4
+ `(,property-name ,val ,@plist))
+ val)))))
+
+(defmacro ses-cell-property-get (property-name row &optional col)
+ "Get property named PROPERTY-NAME From a CELL or a pair (ROW,COL).
+
+When COL is omitted, CELL=ROW is a cell object. When COL is
+present ROW and COL are the integer coordinates of the cell of
+interest."
+ (declare (debug t))
+ `(ses-cell-property-get-fun
+ ,property-name
+ ,(if col `(ses-get-cell ,row ,col) row)))
+
+(defun ses-cell-property-delq-fun (property-name cell)
+ (let ((ret (plist-get (aref cell 4) property-name)))
+ (if ret
+ (setcdr ret (cddr ret)))))
+
+(defun ses-cell-property-set-fun (property-name property-val cell)
+ (let* ((plist (aref cell 4))
+ (ret (plist-member plist property-name)))
+ (if ret
+ (setcar (cdr ret) property-val)
+ (aset cell 4 `(,property-name ,property-val ,@plist)))))
+
+(defmacro ses-cell-property-set (property-name property-value row &optional col)
+ "From a CELL or a pair (ROW,COL), set the property value of
+the corresponding cell with name PROPERTY-NAME to PROPERTY-VALUE."
+ (if property-value
+ `(ses-cell-property-set-fun ,property-name ,property-value
+ ,(if col `(ses-get-cell ,row ,col) row))
+ `(ses-cell-property-delq-fun ,property-name
+ ,(if col `(ses-get-cell ,row ,col) row))))
+
+(defun ses-cell-property-pop-fun (property-name cell)
+ (let* ((plist (aref cell 4))
+ (ret (plist-member plist property-name)))
+ (if ret
+ (prog1 (cadr ret)
+ (let ((next (cddr ret)))
+ (if next
+ (progn
+ (setcdr ret (cdr next))
+ (setcar ret (car next)))
+ (if (eq plist ret)
+ (aset cell 4 nil)
+ (setcdr (last plist 2) nil))))))))
+
+
+(defmacro ses-cell-property-pop (property-name row &optional col)
+ "From a CELL or a pair (ROW,COL), get and remove the property value of
+the corresponding cell with name PROPERTY-NAME."
+ `(ses-cell-property-pop-fun ,property-name
+ ,(if col `(ses-get-cell ,row ,col) row)))
+
+(defun ses-cell-property-get-handle-fun (property-name cell)
+ (let* ((plist (aref cell 4))
+ (ret (plist-member plist property-name)))
+ (if ret
+ (if (eq ret plist)
+ (cdr ret)
+ (let ((val (cadr ret))
+ (next (cddr ret)))
+ (if next
+ (progn
+ (setcdr ret (cdr next))
+ (setcar ret (car next)))
+ (setcdr (last plist 2) nil))
+ (setq ret (cons val plist))
+ (aset cell 4 (cons property-name ret))
+ ret))
+ (setq ret (cons nil plist))
+ (aset cell 4 (cons property-name ret))
+ ret)))
+
+(defmacro ses-cell-property-get-handle (property-name row &optional col)
+ "From a CELL or a pair (ROW,COL), get a cons cell whose car is
+the property value of the corresponding cell property with name
+PROPERTY-NAME."
+ `(ses-cell-property-get-handle-fun ,property-name
+ ,(if col `(ses-get-cell ,row ,col) row)))
+
+
+(defalias 'ses-cell-property-handle-car 'car)
+(defalias 'ses-cell-property-handle-setcar 'setcar)
+