]> code.delx.au - gnu-emacs/blobdiff - lisp/play/decipher.el
Revision: miles@gnu.org--gnu-2005/emacs--unicode--0--patch-57
[gnu-emacs] / lisp / play / decipher.el
index f256a1494b4b26bf6417a52c44db6c57f05fec98..9ef8d0fd01f949caf35805778a8e31c2157fb9ae 100644 (file)
@@ -1,8 +1,8 @@
-;;; decipher.el --- Cryptanalyze monoalphabetic substitution ciphers
+;;; decipher.el --- cryptanalyze monoalphabetic substitution ciphers
 ;;
-;; Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 2003, 2005 Free Software Foundation, Inc.
 ;;
-;; Author: Christopher J. Madsen <ac608@yfn.ysu.edu>
+;; Author: Christopher J. Madsen <chris_madsen@geocities.com>
 ;; Keywords: games
 ;;
 ;; This file is part of GNU Emacs.
 ;; GNU General Public License for more details.
 ;;
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
+;;; Commentary:
+;;
 ;;; Quick Start:
 ;;
 ;; To decipher a message, type or load it into a buffer and type
 ;;   Helen Fouche Gaines
 ;;   ISBN 0-486-20097-3
 
-;;; Commentary:
-;;
-;; If you want Decipher to use its Font Lock mode, you should use
-;;     (setq decipher-use-font-lock t)
-;; See the variable `decipher-use-font-lock' if you want to customize
-;; the faces used.
-;;
 ;; This package is designed to help you crack simple substitution
 ;; ciphers where one letter stands for another.  It works for ciphers
 ;; with or without word divisions.  (You must set the variable
 ;;
 ;; The buffer is made read-only so it can't be modified by normal
 ;; Emacs commands.
+;;
+;; Decipher supports Font Lock mode.  To use it, you can also add
+;;     (add-hook 'decipher-mode-hook 'turn-on-font-lock)
+;; See the variable `decipher-font-lock-keywords' if you want to customize
+;; the faces used.  I'd like to thank Simon Marshall for his help in making
+;; Decipher work well with Font Lock.
 
 ;;; Things To Do:
 ;;
 (eval-when-compile
   (require 'cl))
 
-(eval-when-compile
-  (require 'font-lock))
-
-(defvar decipher-use-font-lock (featurep 'font-lock)
-  "Non-nil means Decipher should use its Font Lock mode.
-Do *not* turn on font-lock-mode yourself, it's too slow when used with
-Decipher.  Decipher contains special code to keep the buffer fontified
-without using Font Lock mode directly.
-
-You should set this in your `.emacs' file or before loading Decipher;
-use `\\[decipher-toggle-font-lock]' after Decipher is loaded.
-
-Ciphertext uses `font-lock-keyword-face', plaintext uses
-`font-lock-string-face', comments use `font-lock-comment-face', and
-checkpoints use `font-lock-reference-face'.
-
-For example, to display ciphertext in the `bold' face, use
-  (add-hook 'decipher-mode-hook
-            (lambda () (set (make-local-variable 'font-lock-keyword-face)
-                            'bold)))
-in your `.emacs' file.")
+(defgroup decipher nil
+  "Cryptanalyze monoalphabetic substitution ciphers."
+  :prefix "decipher-"
+  :group 'games)
 
-(defvar decipher-force-uppercase t
+(defcustom decipher-force-uppercase t
   "*Non-nil means to convert ciphertext to uppercase.
-Nil means the case of the ciphertext is preserved.
-This variable must be set before typing `\\[decipher]'.")
+nil means the case of the ciphertext is preserved.
+This variable must be set before typing `\\[decipher]'."
+  :type 'boolean
+  :group 'decipher)
+
 
-(defvar decipher-ignore-spaces nil
+(defcustom decipher-ignore-spaces nil
   "*Non-nil means to ignore spaces and punctuation when counting digrams.
-You should set this to `nil' if the cipher message is divided into words,
-or `t' if it is not.
-This variable is buffer-local.")
+You should set this to nil if the cipher message is divided into words,
+or t if it is not.
+This variable is buffer-local."
+  :type 'boolean
+  :group 'decipher)
 (make-variable-buffer-local 'decipher-ignore-spaces)
 
-(defvar decipher-undo-limit 5000
+(defcustom decipher-undo-limit 5000
   "The maximum number of entries in the undo list.
 When the undo list exceeds this number, 100 entries are deleted from
-the tail of the list.")
+the tail of the list."
+  :type 'integer
+  :group 'decipher)
+
+(defcustom decipher-mode-hook nil
+  "Hook to run upon entry to decipher."
+  :type 'hook
+  :group 'decipher)
 
 ;; End of user modifiable variables
 ;;--------------------------------------------------------------------
 
 (defvar decipher-font-lock-keywords
-  '(("^:.*\n"  . font-lock-keyword-face)
-    ("^>.*\n"  . font-lock-string-face)
-    ("^%!.*\n" . font-lock-reference-face)
-    ("^%.*\n"  . font-lock-comment-face)
-    ("\\`(\\([a-z]+\\) +\\([A-Z]+\\).+
-)\\([A-Z ]*\\)\\([a-z ]*\\)"
+  '(("^:.*"  . font-lock-keyword-face)
+    ("^>.*"  . font-lock-string-face)
+    ("^%!.*" . font-lock-constant-face)
+    ("^%.*"  . font-lock-comment-face)
+    ("\\`(\\([a-z]+\\) +\\([A-Z]+\\)"
      (1 font-lock-string-face)
-     (2 font-lock-keyword-face)
-     (3 font-lock-keyword-face)
-     (4 font-lock-string-face)))
+     (2 font-lock-keyword-face))
+    ("^)\\([A-Z ]+\\)\\([a-z ]+\\)"
+     (1 font-lock-keyword-face)
+     (2 font-lock-string-face)))
   "Expressions to fontify in Decipher mode.
-See the variable `decipher-use-font-lock'.")
+
+Ciphertext uses `font-lock-keyword-face', plaintext uses
+`font-lock-string-face', comments use `font-lock-comment-face', and
+checkpoints use `font-lock-constant-face'.  You can customize the
+display by changing these variables.  For best results, I recommend
+that all faces use the same background color.
+
+For example, to display ciphertext in the `bold' face, use
+  (add-hook 'decipher-mode-hook
+            (lambda () (set (make-local-variable 'font-lock-keyword-face)
+                            'bold)))
+in your `.emacs' file.")
+
 (defvar decipher-mode-map nil
   "Keymap for Decipher mode.")
 (if (not decipher-mode-map)
@@ -161,10 +170,8 @@ See the variable `decipher-use-font-lock'.")
       (define-key decipher-mode-map "R" 'decipher-restore-checkpoint)
       (define-key decipher-mode-map "U" 'decipher-undo)
       (define-key decipher-mode-map " " 'decipher-keypress)
-      (substitute-key-definition 'undo  'decipher-undo
-                                 decipher-mode-map global-map)
-      (substitute-key-definition 'advertised-undo  'decipher-undo
-                                 decipher-mode-map global-map)
+      (define-key decipher-mode-map [remap undo] 'decipher-undo)
+      (define-key decipher-mode-map [remap advertised-undo] 'decipher-undo)
       (let ((key ?a))
         (while (<= key ?z)
           (define-key decipher-mode-map (vector key) 'decipher-keypress)
@@ -298,23 +305,16 @@ The most useful commands are:
       (setq case-fold-search nil))      ;Case is significant when searching
   (use-local-map decipher-mode-map)
   (set-syntax-table decipher-mode-syntax-table)
-  (decipher-read-alphabet)
+  (unless (= (point-min) (point-max))
+    (decipher-read-alphabet))
   (set (make-local-variable 'font-lock-defaults)
        '(decipher-font-lock-keywords t))
   ;; Make the buffer writable when we exit Decipher mode:
-  (make-local-hook 'change-major-mode-hook)
   (add-hook 'change-major-mode-hook
             (lambda () (setq buffer-read-only nil
                              buffer-undo-list nil))
             nil t)
-  ;; If someone turns on Font Lock, turn it off and use our code instead:
-  (make-local-hook 'font-lock-mode-hook)
-  (add-hook 'font-lock-mode-hook 'decipher-turn-on-font-lock t t)
-  (run-hooks 'decipher-mode-hook)
-  (and decipher-use-font-lock
-       ;; Fontify buffer after calling the mode hooks,
-       ;; in case they change the font-lock variables:
-       (font-lock-fontify-buffer))
+  (run-mode-hooks 'decipher-mode-hook)
   (setq buffer-read-only t))
 (put 'decipher-mode 'mode-class 'special)
 
@@ -423,13 +423,17 @@ The most useful commands are:
               (setcdr (nthcdr (1- new-size) decipher-undo-list) nil)
               (setq decipher-undo-list-size new-size))))))
 
+(defun decipher-copy-cons (cons)
+  (if cons
+      (cons (car cons) (cdr cons))))
+
 (defun decipher-get-undo (cipher-char plain-char)
   ;; Return an undo record that will undo the result of
   ;;   (decipher-set-map CIPHER-CHAR PLAIN-CHAR)
-  ;; We must use copy-list because the original cons cells will be
+  ;; We must copy the cons cell because the original cons cells will be
   ;; modified using setcdr.
-  (let ((cipher-map (copy-list (rassoc cipher-char decipher-alphabet)))
-        (plain-map  (copy-list (assoc  plain-char  decipher-alphabet))))
+  (let ((cipher-map (decipher-copy-cons (rassoc cipher-char decipher-alphabet)))
+        (plain-map  (decipher-copy-cons (assoc  plain-char  decipher-alphabet))))
     (cond ((equal ?\  plain-char)
            cipher-map)
           ((equal cipher-char (cdr plain-map))
@@ -475,21 +479,18 @@ The most useful commands are:
                 (decipher-set-map (cdr mapping) ?\  t))
             (setcdr mapping cipher-char)
             (search-forward-regexp (concat "^([a-z]*" plain-string))
-            (and decipher-use-font-lock
-                 (put-text-property 0 1 'face font-lock-keyword-face
-                                    cipher-string))
-            (decipher-insert cipher-string)
+            (decipher-insert cipher-char)
             (beginning-of-line)))
       (search-forward-regexp (concat "^([a-z]+   [A-Z]*" cipher-string))
-      (and decipher-use-font-lock
-           (put-text-property 0 1 'face font-lock-string-face plain-string))
-      (decipher-insert plain-string)
+      (decipher-insert plain-char)
       (setq case-fold-search t          ;Case is not significant
             cipher-string    (downcase cipher-string))
-      (while (search-forward-regexp "^:" nil t)
-        (setq bound (save-excursion (end-of-line) (point)))
-        (while (search-forward cipher-string bound 'end)
-          (decipher-insert plain-char))))))
+      (let ((font-lock-fontify-region-function 'ignore))
+        ;; insert-and-inherit will pick the right face automatically
+        (while (search-forward-regexp "^:" nil t)
+          (setq bound (save-excursion (end-of-line) (point)))
+          (while (search-forward cipher-string bound 'end)
+            (decipher-insert plain-char)))))))
 
 (defun decipher-insert (char)
   ;; Insert CHAR in the row below point.  It replaces any existing
@@ -544,9 +545,7 @@ Type `\\[decipher-restore-checkpoint]' to restore a checkpoint."
       (insert "\n%" (make-string 69 ?\-)
               "\n% Checkpoints:\n% abcdefghijklmnopqrstuvwxyz\n"))
     (beginning-of-line)
-    (insert "%!" alphabet "! " desc ?\n))
-  (and decipher-use-font-lock
-       (font-lock-fontify-buffer)))
+    (insert "%!" alphabet "! " desc ?\n)))
 
 (defun decipher-restore-checkpoint ()
   "Restore the cipher alphabet from a checkpoint.
@@ -621,12 +620,10 @@ You should use this if you edit the ciphertext."
       (decipher-read-alphabet)
       (setq alphabet decipher-alphabet)
       (goto-char (point-min))
-      (and (re-search-forward "^).+$" nil t)
+      (and (re-search-forward "^).+" nil t)
            (replace-match ")" nil nil))
-      (while (re-search-forward "^>.+$" nil t)
+      (while (re-search-forward "^>.+" nil t)
         (replace-match ">" nil nil))
-      (and decipher-use-font-lock
-           (font-lock-fontify-buffer))
       (decipher-read-alphabet)
       (while (setq mapping (pop alphabet))
         (or (equal ?\  (cdr mapping))
@@ -635,19 +632,6 @@ You should use this if you edit the ciphertext."
         decipher-undo-list-size  0)
   (message "Reprocessing buffer...done"))
 
-(defun decipher-toggle-font-lock (&optional arg)
-  "Toggle Decipher's Font Lock mode in the current buffer.
-With arg, turn Font Lock mode on if and only if arg is positive.
-See the variable `decipher-use-font-lock' for more information."
-  (interactive "P")
-  (or (eq major-mode 'decipher-mode)
-      (error "This buffer is not in Decipher mode"))
-  (let ((on-p (if arg (> (prefix-numeric-value arg) 0)
-                (not decipher-use-font-lock))))
-    (if on-p (font-lock-fontify-buffer)
-      (font-lock-unfontify-region (point-min) (point-max)))
-    (make-local-variable 'decipher-use-font-lock)
-    (setq decipher-use-font-lock on-p)))
 ;;--------------------------------------------------------------------
 ;; Miscellaneous functions:
 ;;--------------------------------------------------------------------
@@ -664,10 +648,6 @@ See the variable `decipher-use-font-lock' for more information."
         (backward-char)
         (push (cons plain-char (following-char)) decipher-alphabet)
         (decf plain-char)))))
-(defun decipher-turn-on-font-lock ()
-  "Turn on Decipher's Font Lock code and turn off normal Font Lock mode."
-  (font-lock-mode 0)
-  (decipher-toggle-font-lock 1))
 
 ;;;===================================================================
 ;;; Analyzing ciphertext:
@@ -705,7 +685,7 @@ ciphertext."
       (set-buffer (decipher-stats-buffer))
       (goto-char (point-min))
       (or (re-search-forward (format "^%c: " cipher-char) nil t)
-          (error "Character `%c' is not used in ciphertext." cipher-char))
+          (error "Character `%c' is not used in ciphertext" cipher-char))
       (forward-line -1)
       (setq start (point))
       (forward-line 3)
@@ -1018,7 +998,7 @@ Creates the statistics buffer if it doesn't exist."
         major-mode       'decipher-stats-mode
         mode-name        "Decipher-Stats")
   (use-local-map decipher-stats-mode-map)
-  (run-hooks 'decipher-stats-mode-hook))
+  (run-mode-hooks 'decipher-stats-mode-hook))
 (put 'decipher-stats-mode 'mode-class 'special)
 
 ;;--------------------------------------------------------------------
@@ -1089,4 +1069,5 @@ if it can't, it signals an error."
 ;;;          (delete-backward-char 1)
 ;;;          (insert ")\n"))))))
 
+;;; arch-tag: 8f094d88-ffe1-4f99-afe3-a5e81dd939d9
 ;;; decipher.el ends here