]> code.delx.au - gnu-emacs/blobdiff - lisp/hexl.el
; Revert "Use eldoc-documentation-functions"
[gnu-emacs] / lisp / hexl.el
index fdafd97cdab0cb44111b039bbff11d416d0b90f6..5f099a5afd5e8a49d6727021f2e992c1aeb01888 100644 (file)
@@ -1,9 +1,10 @@
 ;;; hexl.el --- edit a file in a hex dump format using the hexl filter -*- lexical-binding: t -*-
 
-;; Copyright (C) 1989, 1994, 1998, 2001-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1989, 1994, 1998, 2001-2016 Free Software Foundation,
+;; Inc.
 
 ;; Author: Keith Gabryelski <ag@wheaties.ai.mit.edu>
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: data
 
 ;; This file is part of GNU Emacs.
@@ -41,7 +42,7 @@
 ;;; Code:
 
 (require 'eldoc)
-(eval-when-compile (require 'cl))
+(eval-when-compile (require 'cl-lib))
 
 ;;
 ;; vars here
   "Edit a file in a hex dump format using the hexl filter."
   :group 'data)
 
+(defcustom hexl-bits 16
+  "The bit grouping that hexl will use."
+  :type '(choice (const 8 )
+                 (const 16)
+                 (const 32)
+                 (const 64))
+  :group 'hexl
+  :version "24.3")
 
 (defcustom hexl-program "hexl"
   "The program that will hexlify and dehexlify its stdin.
@@ -67,7 +76,9 @@ and \"-de\" when dehexlifying a buffer."
 
 (defcustom hexl-options (format "-hex %s" hexl-iso)
   "Space separated options to `hexl-program' that suit your needs.
-Quoting cannot be used, so the arguments cannot themselves contain spaces."
+Quoting cannot be used, so the arguments cannot themselves contain spaces.
+If you wish to set the `-group-by-X-bits' options, set `hexl-bits' instead,
+as that will override any bit grouping options set here."
   :type 'string
   :group 'hexl)
 
@@ -80,17 +91,17 @@ Quoting cannot be used, so the arguments cannot themselves contain spaces."
 (defcustom hexl-mode-hook '(hexl-follow-line hexl-activate-ruler)
   "Normal hook run when entering Hexl mode."
   :type 'hook
-  :options '(hexl-follow-line hexl-activate-ruler turn-on-eldoc-mode)
+  :options '(hexl-follow-line hexl-activate-ruler eldoc-mode)
   :group 'hexl)
 
 (defface hexl-address-region
   '((t (:inherit header-line)))
-  "Face used in address area of hexl-mode buffer."
+  "Face used in address area of Hexl mode buffer."
   :group 'hexl)
 
 (defface hexl-ascii-region
   '((t (:inherit header-line)))
-  "Face used in ascii area of hexl-mode buffer."
+  "Face used in ASCII area of Hexl mode buffer."
   :group 'hexl)
 
 (defvar hexl-max-address 0
@@ -212,10 +223,34 @@ Quoting cannot be used, so the arguments cannot themselves contain spaces."
      (2 'hexl-ascii-region t t)))
   "Font lock keywords used in `hexl-mode'.")
 
+(defun hexl-rulerize (string bits)
+  (let ((size (/ bits 4)) (strlen (length string)) (pos 0) (ruler ""))
+    (while (< pos strlen)
+      (setq ruler (concat ruler " " (substring string pos (+ pos size))))
+      (setq pos (+ pos size)))
+    (substring ruler 1) ))
+
+(defvar hexl-rulers
+  (mapcar
+   (lambda (bits)
+     (cons bits
+           (concat " 87654321  "
+                   (hexl-rulerize "00112233445566778899aabbccddeeff" bits)
+                   "  0123456789abcdef")))
+   '(8 16 32 64)))
 ;; routines
 
 (put 'hexl-mode 'mode-class 'special)
 
+;; 10 chars for the "address: "
+;; 32 chars for the hexlified bytes
+;; 1 char for the space
+;; 16 chars for the character display
+;; X chars for the spaces (128 bits divided by the hexl-bits)
+;; 1 char for the newline.
+(defun hexl-line-displen ()
+  "The length of a hexl display line (varies with `hexl-bits')."
+  (+ 60 (/ 128 (or hexl-bits 16))))
 
 (defun hexl-mode--minor-mode-p (var)
   (memq var '(ruler-mode hl-line-mode)))
@@ -248,10 +283,10 @@ using the function `hexlify-buffer'.
 Each line in the buffer has an \"address\" (displayed in hexadecimal)
 representing the offset into the file that the characters on this line
 are at and 16 characters from the file (displayed as hexadecimal
-values grouped every 16 bits) and as their ASCII values.
+values grouped every `hexl-bits' bits, and as their ASCII values).
 
 If any of the characters (displayed as ASCII characters) are
-unprintable (control or meta characters) they will be replaced as
+unprintable (control or meta characters) they will be replaced by
 periods.
 
 If `hexl-mode' is invoked with an argument the buffer is assumed to be
@@ -259,7 +294,7 @@ in hexl format.
 
 A sample format:
 
-  HEX ADDR: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f     ASCII-TEXT
+  HEX ADDR: 0011 2233 4455 6677 8899 aabb ccdd eeff     ASCII-TEXT
   --------  ---- ---- ---- ---- ---- ---- ---- ----  ----------------
   00000000: 5468 6973 2069 7320 6865 786c 2d6d 6f64  This is hexl-mod
   00000010: 652e 2020 4561 6368 206c 696e 6520 7265  e.  Each line re
@@ -275,9 +310,9 @@ A sample format:
   000000b0: 7461 626c 6520 6368 6172 6163 7465 7220  table character
   000000c0: 7265 6769 6f6e 2e0a                      region..
 
-Movement is as simple as movement in a normal Emacs text buffer.  Most
-cursor movement bindings are the same (ie. Use \\[hexl-backward-char], \\[hexl-forward-char], \\[hexl-next-line], and \\[hexl-previous-line]
-to move the cursor left, right, down, and up).
+Movement is as simple as movement in a normal Emacs text buffer.
+Most cursor movement bindings are the same: use \\[hexl-backward-char], \\[hexl-forward-char], \\[hexl-next-line], and \\[hexl-previous-line]
+to move the cursor left, right, down, and up.
 
 Advanced cursor movement commands (ala \\[hexl-beginning-of-line], \\[hexl-end-of-line], \\[hexl-beginning-of-buffer], and \\[hexl-end-of-buffer]) are
 also supported.
@@ -301,7 +336,7 @@ into the buffer at the current point.
 \\[hexl-insert-decimal-char] will insert a given decimal value (if it is between 0 and 255)
 into the buffer at the current point.
 
-\\[hexl-mode-exit] will exit hexl-mode.
+\\[hexl-mode-exit] will exit `hexl-mode'.
 
 Note: saving the file with any of the usual Emacs commands
 will actually convert it back to binary format while saving.
@@ -330,10 +365,7 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
         (hexlify-buffer)
         (restore-buffer-modified-p modified))
       (set (make-local-variable 'hexl-max-address)
-           (let* ((full-lines (/ (buffer-size) 68))
-                  (last-line (% (buffer-size) 68))
-                  (last-line-bytes (% last-line 52)))
-             (+ last-line-bytes (* full-lines 16) -1)))
+           (+ (* (/ (1- (buffer-size)) (hexl-line-displen)) 16) 15))
       (condition-case nil
          (hexl-goto-address original-point)
        (error nil)))
@@ -363,8 +395,8 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
     (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t)
 
     ;; Set a callback function for eldoc.
-    (hexl-mode--setq-local 'eldoc-documentation-function
-                           #'hexl-print-current-point-info)
+    (add-function :before-until (local 'eldoc-documentation-function)
+                  #'hexl-print-current-point-info)
     (eldoc-add-command-completions "hexl-")
     (eldoc-remove-command "hexl-save-buffer"
                          "hexl-current-address")
@@ -374,7 +406,7 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
 
 
 (defun hexl-isearch-search-function ()
-  (if (and (not isearch-regexp) (not isearch-word))
+  (if (and (not isearch-regexp) (not isearch-regexp-function))
       (lambda (string &optional bound noerror count)
        (funcall
         (if isearch-forward 're-search-forward 're-search-backward)
@@ -389,8 +421,7 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
                                   " \\(?: .+\n[a-f0-9]+: \\)?"))
              textre))
         bound noerror count))
-    (let ((isearch-search-fun-function nil))
-      (isearch-search-fun))))
+    (isearch-search-fun-default)))
 
 (defvar hexl-in-save-buffer nil)
 
@@ -432,7 +463,7 @@ and edit the file in `hexl-mode'."
     (let ((completion-ignored-extensions nil))
       (read-file-name "Filename: " nil nil 'ret-must-match))))
   ;; Ignore the user's setting of default major-mode.
-  (letf (((default-value 'major-mode) 'fundamental-mode))
+  (cl-letf (((default-value 'major-mode) 'fundamental-mode))
     (find-file-literally filename))
   (if (not (eq major-mode 'hexl-mode))
       (hexl-mode)))
@@ -510,17 +541,20 @@ Ask the user for confirmation."
 (defun hexl-current-address (&optional validate)
   "Return current hexl-address."
   (interactive)
-  (let ((current-column (- (% (- (point) (point-min) -1) 68) 11))
+  (let ((current-column
+         (- (% (- (point) (point-min) -1) (hexl-line-displen)) 11))
        (hexl-address 0))
     (if (< current-column 0)
        (if validate
            (error "Point is not on a character in the file")
          (setq current-column 0)))
     (setq hexl-address
-         (+ (* (/ (- (point) (point-min) -1) 68) 16)
-            (if (>= current-column 41)
-                (- current-column 41)
-              (/ (- current-column  (/ current-column 5)) 2))))
+          (+ (* (/ (- (point) (point-min) -1)
+                   (hexl-line-displen)) 16)
+            (if (>= current-column (- (hexl-ascii-start-column) 10))
+                (- current-column (- (hexl-ascii-start-column) 10))
+               (/ (- current-column
+                     (/ current-column (1+ (/ hexl-bits 4)))) 2))))
     (when (called-interactively-p 'interactive)
       (message "Current address is %d/0x%08x" hexl-address hexl-address))
     hexl-address))
@@ -531,10 +565,18 @@ This function is intended to be used as eldoc callback."
   (let ((addr (hexl-current-address)))
     (format "Current address is %d/0x%08x" addr addr)))
 
+(defun hexl-ascii-start-column ()
+  "Column at which the ASCII portion of the hexl display starts."
+  (+ 43 (/ 128 hexl-bits)))
+
 (defun hexl-address-to-marker (address)
   "Return buffer position for ADDRESS."
   (interactive "nAddress: ")
-  (+ (* (/ address 16) 68) 10 (point-min) (/ (* (% address 16) 5) 2)))
+  (let ((N (* (% address 16) 2)))
+    (+ (* (/ address 16) (hexl-line-displen)) ; hexl line no * display length
+       10                      ; 10 chars for the "address: " prefix
+       (point-min)             ; base offset (point usually starts at 1, not 0)
+       (+ N (/ N (/ hexl-bits 4))) )) ) ; char offset into hexl display line
 
 (defun hexl-goto-address (address)
   "Go to hexl-mode (decimal) address ADDRESS.
@@ -545,7 +587,7 @@ Signal error if ADDRESS is out of range."
   (goto-char (hexl-address-to-marker address)))
 
 (defun hexl-goto-hex-address (hex-address)
-  "Go to hexl-mode address (hex string) HEX-ADDRESS.
+  "Go to Hexl mode address (hex string) HEX-ADDRESS.
 Signal error if HEX-ADDRESS is out of range."
   (interactive "sHex Address: ")
   (hexl-goto-address (hexl-hex-string-to-integer hex-address)))
@@ -574,17 +616,17 @@ Signal error if HEX-ADDRESS is out of range."
 ;; move point functions
 
 (defun hexl-backward-char (arg)
-  "Move to left ARG bytes (right if ARG negative) in hexl-mode."
+  "Move to left ARG bytes (right if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-goto-address (- (hexl-current-address) arg)))
 
 (defun hexl-forward-char (arg)
-  "Move to right ARG bytes (left if ARG negative) in hexl-mode."
+  "Move to right ARG bytes (left if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-goto-address (+ (hexl-current-address) arg)))
 
 (defun hexl-backward-short (arg)
-  "Move to left ARG shorts (right if ARG negative) in hexl-mode."
+  "Move to left ARG shorts (right if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-goto-address (let ((address (hexl-current-address)))
                       (if (< arg 0)
@@ -616,12 +658,12 @@ Signal error if HEX-ADDRESS is out of range."
                       address)))
 
 (defun hexl-forward-short (arg)
-  "Move to right ARG shorts (left if ARG negative) in hexl-mode."
+  "Move to right ARG shorts (left if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-backward-short (- arg)))
 
 (defun hexl-backward-word (arg)
-  "Move to left ARG words (right if ARG negative) in hexl-mode."
+  "Move to left ARG words (right if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-goto-address (let ((address (hexl-current-address)))
                       (if (< arg 0)
@@ -653,18 +695,18 @@ Signal error if HEX-ADDRESS is out of range."
                       address)))
 
 (defun hexl-forward-word (arg)
-  "Move to right ARG words (left if ARG negative) in hexl-mode."
+  "Move to right ARG words (left if ARG negative) in Hexl mode."
   (interactive "p")
   (hexl-backward-word (- arg)))
 
 (defun hexl-previous-line (arg)
-  "Move vertically up ARG lines [16 bytes] (down if ARG negative) in hexl-mode.
+  "Move vertically up ARG lines [16 bytes] (down if ARG negative) in Hexl mode.
 If there is no byte at the target address move to the last byte in that line."
   (interactive "p")
   (hexl-next-line (- arg)))
 
 (defun hexl-next-line (arg)
-  "Move vertically down ARG lines [16 bytes] (up if ARG negative) in hexl-mode.
+  "Move vertically down ARG lines [16 bytes] (up if ARG negative) in Hexl mode.
 If there is no byte at the target address move to the last byte in that line."
   (interactive "p")
   (hexl-goto-address (let ((address (+ (hexl-current-address) (* arg 16))))
@@ -698,12 +740,12 @@ With prefix arg N, puts point N bytes of the way from the true beginning."
   (hexl-goto-address (- hexl-max-address (1- arg))))
 
 (defun hexl-beginning-of-line ()
-  "Goto beginning of line in hexl mode."
+  "Goto beginning of line in Hexl mode."
   (interactive)
-  (goto-char (+ (* (/ (point) 68) 68) 11)))
+  (goto-char (+ (* (/ (point) (hexl-line-displen)) (hexl-line-displen)) 11)))
 
 (defun hexl-end-of-line ()
-  "Goto end of line in hexl mode."
+  "Goto end of line in Hexl mode."
   (interactive)
   (hexl-goto-address (let ((address (logior (hexl-current-address) 15)))
                       (if (> address hexl-max-address)
@@ -776,6 +818,17 @@ You may also type octal digits, to insert a character with that code."
 
 ;00000000: 0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
 
+(defun hexl-options (&optional test)
+  "Combine `hexl-bits' with `hexl-options', altering `hexl-options' as needed
+to produce the command line options to pass to the hexl command."
+  (let ((opts (or test hexl-options)))
+    (when (memq hexl-bits '(8 16 32 64))
+      (when (string-match "\\(.*\\)-group-by-[0-9]+-bits\\(.*\\)" opts)
+        (setq opts (concat (match-string 1 opts)
+                           (match-string 2 opts))))
+      (setq opts (format "%s -group-by-%d-bits " opts hexl-bits)) )
+    opts))
+
 ;;;###autoload
 (defun hexlify-buffer ()
   "Convert a binary buffer to hexl format.
@@ -798,7 +851,7 @@ This discards the buffer's undo information."
            (mapcar (lambda (s)
                      (if (not (multibyte-string-p s)) s
                        (encode-coding-string s locale-coding-system)))
-                   (split-string hexl-options)))
+                   (split-string (hexl-options))))
     (if (> (point) (hexl-address-to-marker hexl-max-address))
        (hexl-goto-address hexl-max-address))))
 
@@ -815,7 +868,7 @@ This discards the buffer's undo information."
        (buffer-undo-list t))
     (apply 'call-process-region (point-min) (point-max)
           (expand-file-name hexl-program exec-directory)
-          t t nil "-de" (split-string hexl-options))))
+          t t nil "-de" (split-string (hexl-options)))))
 
 (defun hexl-char-after-point ()
   "Return char for ASCII hex digits at point."
@@ -882,13 +935,14 @@ and their encoded form is inserted byte by byte."
                     (mapconcat (function (lambda (c) (format "%x" c)))
                                internal " "))
               (if (yes-or-no-p
-                   (format
+                   (format-message
                     "Insert char 0x%x's internal representation \"%s\"? "
                     ch internal-hex))
                   (setq encoded internal)
                 (error
-                 "Can't encode `0x%x' with this buffer's coding system; try \\[hexl-insert-hex-string]"
-                 ch)))
+                 "Can't encode `0x%x' with this buffer's coding system; %s"
+                 ch
+                 (substitute-command-keys "try \\[hexl-insert-hex-string]"))))
             (while (> num 0)
               (mapc
                (function (lambda (c) (hexl-insert-char c 1))) encoded)
@@ -911,13 +965,12 @@ CH must be a unibyte character whose value is between 0 and 255."
       (error "Invalid character 0x%x -- must be in the range [0..255]" ch))
   (let ((address (hexl-current-address t)))
     (while (> num 0)
-      (let ((hex-position
-            (+ (* (/ address 16) 68)
-               10 (point-min)
-               (* 2 (% address 16))
-               (/ (% address 16) 2)))
+      (let ((hex-position (hexl-address-to-marker address))
            (ascii-position
-            (+ (* (/ address 16) 68) 51 (point-min) (% address 16)))
+            (+ (* (/ address 16) (hexl-line-displen))
+                (hexl-ascii-start-column)
+                (point-min)
+                (% address 16)))
            at-ascii-position)
        (if (= (point) ascii-position)
            (setq at-ascii-position t))
@@ -933,7 +986,7 @@ CH must be a unibyte character whose value is between 0 and 255."
        (if at-ascii-position
            (progn
              (beginning-of-line)
-             (forward-char 51)
+             (forward-char (hexl-ascii-start-column))
              (forward-char (% address 16)))))
       (setq num (1- num)))))
 
@@ -1041,16 +1094,16 @@ This function is assumed to be used as callback function for `hl-line-mode'."
 
 (defun hexl-follow-ascii-find ()
   "Find and highlight the ASCII element corresponding to current point."
-  (let ((pos (+ 51
+  (let ((pos (+ (hexl-ascii-start-column)
                (- (point) (current-column))
                (mod (hexl-current-address) 16))))
     (move-overlay hexl-ascii-overlay pos (1+ pos))
     ))
 
 (defun hexl-mode-ruler ()
-  "Return a string ruler for hexl mode."
+  "Return a string ruler for Hexl mode."
   (let* ((highlight (mod (hexl-current-address) 16))
-        (s " 87654321  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789abcdef")
+        (s (cdr (assq hexl-bits hexl-rulers)))
         (pos 0))
     (set-text-properties 0 (length s) nil s)
     ;; Turn spaces in the header into stretch specs so they work
@@ -1062,12 +1115,12 @@ This function is assumed to be used as callback function for `hl-line-mode'."
                         `(space :align-to ,(1- pos))
                         s))
     ;; Highlight the current column.
-    (put-text-property (+ 11 (/ (* 5 highlight) 2))
-                      (+ 13 (/ (* 5 highlight) 2))
-                      'face 'highlight s)
+    (let ( (offset (+ (* 2 highlight) (/ (* 8 highlight) hexl-bits))) )
+      (put-text-property (+ 11 offset) (+ 13 offset) 'face 'highlight s))
     ;; Highlight the current ascii column
-    (put-text-property (+ 13 39 highlight) (+ 13 40 highlight)
-                      'face 'highlight s)
+    (put-text-property (+ (hexl-ascii-start-column) highlight 1)
+                       (+ (hexl-ascii-start-column) highlight 2)
+                       'face 'highlight s)
     s))
 
 ;; startup stuff.