-;;; 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)
(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)
(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)
(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))
(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
(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.
(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))
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:
;;--------------------------------------------------------------------
(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:
(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)
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)
;;--------------------------------------------------------------------
;;; (delete-backward-char 1)
;;; (insert ")\n"))))))
+;;; arch-tag: 8f094d88-ffe1-4f99-afe3-a5e81dd939d9
;;; decipher.el ends here