X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a378799a5c515979869f148ac6a019357a2073b5..fdffd346262841cb194225ea0acd8059c57ec2d4:/lisp/play/decipher.el diff --git a/lisp/play/decipher.el b/lisp/play/decipher.el index f256a1494b..9ef8d0fd01 100644 --- a/lisp/play/decipher.el +++ b/lisp/play/decipher.el @@ -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 +;; Author: Christopher J. Madsen ;; Keywords: games ;; ;; This file is part of GNU Emacs. @@ -18,9 +18,12 @@ ;; 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 @@ -36,13 +39,6 @@ ;; 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 @@ -75,6 +71,12 @@ ;; ;; 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: ;; @@ -91,61 +93,68 @@ (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