1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; A game database that stores PGN format games or EPD format positions in
6 ;; This is basically what you expect from a file ending in .pgn or .epd.
9 (defvar chess-file-locations nil
10 "A list of starting positions of individual records of this collection.")
11 (make-variable-buffer-local 'chess-file-locations)
13 (defvar chess-file-type nil
14 "The file format type of this database instance (a symbol).
15 See `chess-file-types' for details.")
16 (make-variable-buffer-local 'chess-file-type)
18 (defvar chess-file-types
19 `((pgn "^\\[Event " chess-pgn-to-game chess-game-to-pgn (?\n ?\n))
20 (epd ,(concat chess-fen-regexp "\\(\\s-+.+\\);\\s-*$")
21 chess-epd-to-game chess-game-to-epd (?\n)))
22 "Alist of different file types.
23 Entries have the form (TYPE BEGIN-REGEXP TO-GAME FROM-GAME SEPARATOR)
24 where TYPE is a symbol (usually either 'pgn or 'epd),
25 BEGIN-REGEXP is the regexp to use for matching the beginning of new records,
26 TO-GAME and FROM-GAME are functions to use for reading and writing a game
27 object from/into the buffer and SEPARATOR is a list of characters to insert
28 inbetween of individual records.")
30 (defun chess-file-handler (event &rest args)
31 "Event handler for file database objects."
34 (with-current-buffer (find-file-noselect (car args))
35 (when (setq chess-file-type
37 ((or (string-match "\\.pgn\\'" (car args))
38 (save-excursion (re-search-forward "^\\[Event" nil t)))
40 ((string-match "\\.epd\\'" (car args))
42 (chess-file-handler 'rescan)
47 (goto-char (point-min))
48 (setq chess-file-locations nil)
49 (while (re-search-forward (nth 1 (assq chess-file-type chess-file-types))
51 (goto-char (match-beginning 0))
52 (push (point) chess-file-locations)
54 (setq chess-file-locations (nreverse chess-file-locations))))
56 ((eq event 'read-only-p)
66 (length chess-file-locations))
69 (let ((index (car args)) game)
70 (when (and (>= index 0)
71 (< index (chess-file-handler 'count)))
72 (goto-char (nth index chess-file-locations))
73 (when (setq game (funcall (nth 2 (assq chess-file-type
75 (chess-game-set-data game 'database (current-buffer))
76 (chess-game-set-data game 'database-index index)
77 (chess-game-set-data game 'database-count
78 (chess-file-handler 'count))
82 (goto-char (point-max))
83 (while (memq (char-before) '(? ?\t ?\n ?\r))
84 (delete-backward-char 1))
85 (apply 'insert (nth 4 (assq chess-file-type chess-file-types)))
86 (push (point) chess-file-locations)
87 (funcall (nth 3 (assq chess-file-type chess-file-types)) (car args))
88 (1- (chess-file-handler 'count)))
91 (let ((index (or (cadr args)
92 (chess-game-data (car args) 'database-index)))
93 (count (chess-file-handler 'count)))
94 (when (and (>= index 0)
96 (goto-char (nth index chess-file-locations))
97 (delete-region (point) (if (= (1+ index) count)
99 (nth (1+ index) chess-file-locations)))
100 (funcall (nth 3 (assq chess-file-type chess-file-types)) (car args))
101 (when (eq chess-file-type 'pgn) (insert ?\n)))))))
103 (provide 'chess-file)
105 ;;; chess-file.el ends here