Add ability to use xdg-open, i.e. your desktop default browser.
[bpt/emacs.git] / lisp / hexl.el
CommitLineData
55535639 1;;; hexl.el --- edit a file in a hex dump format using the hexl filter
e5167999 2
0d30b337 3;; Copyright (C) 1989, 1994, 1998, 2001, 2002, 2003, 2004,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
a2535589 5
3a801d0c 6;; Author: Keith Gabryelski <ag@wheaties.ai.mit.edu>
b7f66977
RS
7;; Maintainer: FSF
8;; Keywords: data
3a801d0c 9
a2535589
JA
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
a2535589 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
a2535589
JA
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
a2535589 24
e5167999
ER
25;;; Commentary:
26
e41b2db1
ER
27;; This package implements a major mode for editing binary files. It uses
28;; a program called hexl, supplied with the GNU Emacs distribution, that
29;; can filter a binary into an editable format or from the format back into
30;; binary. For full instructions, invoke `hexl-mode' on an empty buffer and
a0164df5 31;; do M-x `describe-mode'.
e41b2db1 32;;
a0164df5 33;; NOTE: Remember to change `hexl-program' or `hexl-options' if needed.
a2535589
JA
34;;
35;; Currently hexl only supports big endian hex output with 16 bit
36;; grouping.
37;;
38;; -iso in `hexl-options' will allow iso characters to display in the
37dc4767 39;; ASCII region of the screen (if your Emacs supports this) instead of
a2535589
JA
40;; changing them to dots.
41
e5167999
ER
42;;; Code:
43
01ff9136 44(require 'eldoc)
14acf2f5 45(eval-when-compile (require 'cl))
01ff9136 46
a2535589
JA
47;;
48;; vars here
49;;
50
00ed33e7
RS
51(defgroup hexl nil
52 "Edit a file in a hex dump format using the hexl filter."
53 :group 'data)
54
55
56(defcustom hexl-program "hexl"
65e5f4bc 57 "The program that will hexlify and dehexlify its stdin.
57f07931 58`hexl-program' will always be concatenated with `hexl-options'
00ed33e7
RS
59and \"-de\" when dehexlifying a buffer."
60 :type 'string
61 :group 'hexl)
a2535589 62
00ed33e7 63(defcustom hexl-iso ""
37dc4767 64 "If your Emacs can handle ISO characters, this should be set to
00ed33e7
RS
65\"-iso\" otherwise it should be \"\"."
66 :type 'string
67 :group 'hexl)
a2535589 68
00ed33e7 69(defcustom hexl-options (format "-hex %s" hexl-iso)
b8c49a19
SM
70 "Space separated options to `hexl-program' that suit your needs.
71Quoting cannot be used, so the arguments cannot themselves contain spaces."
00ed33e7
RS
72 :type 'string
73 :group 'hexl)
a2535589 74
db6c5b92
SE
75(defcustom hexl-follow-ascii t
76 "If non-nil then highlight the ASCII character corresponding to point."
77 :type 'boolean
cd32a7ba
DN
78 :group 'hexl
79 :version "20.3")
db6c5b92 80
9fd76d04
MY
81(defcustom hexl-mode-hook '(hexl-follow-line hexl-activate-ruler)
82 "Normal hook run when entering Hexl mode."
83 :type 'hook
84 :options '(hexl-follow-line hexl-activate-ruler turn-on-eldoc-mode)
85 :group 'hexl)
86
2d77d354 87(defface hexl-address-region
9fd76d04 88 '((t (:inherit header-line)))
5232b4cd 89 "Face used in address area of hexl-mode buffer."
9fd76d04
MY
90 :group 'hexl)
91
2d77d354 92(defface hexl-ascii-region
9fd76d04 93 '((t (:inherit header-line)))
5232b4cd 94 "Face used in ascii area of hexl-mode buffer."
9fd76d04
MY
95 :group 'hexl)
96
a2535589
JA
97(defvar hexl-max-address 0
98 "Maximum offset into hexl buffer.")
99
100(defvar hexl-mode-map nil)
101
3fc29559 102;; Variable declarations for suppressing warnings from the byte-compiler.
b27ce24f
RS
103(defvar ruler-mode)
104(defvar ruler-mode-ruler-function)
105(defvar hl-line-mode)
3fc29559
MY
106(defvar hl-line-range-function)
107(defvar hl-line-face)
b27ce24f 108
3fc29559
MY
109;; Variables where the original values are stored to.
110(defvar hexl-mode-old-hl-line-mode)
6ac2ae62
MY
111(defvar hexl-mode-old-hl-line-range-function)
112(defvar hexl-mode-old-hl-line-face)
f39c6650
RS
113(defvar hexl-mode-old-local-map)
114(defvar hexl-mode-old-mode-name)
115(defvar hexl-mode-old-major-mode)
b27ce24f 116(defvar hexl-mode-old-ruler-mode)
3fc29559 117(defvar hexl-mode-old-ruler-function)
87b3b78a 118(defvar hexl-mode-old-isearch-search-fun-function)
0e4889b2
RS
119(defvar hexl-mode-old-require-final-newline)
120(defvar hexl-mode-old-syntax-table)
639b8e4d 121(defvar hexl-mode-old-font-lock-keywords)
cfea581f 122(defvar hexl-mode-old-eldoc-documentation-function)
f39c6650 123
db6c5b92
SE
124(defvar hexl-ascii-overlay nil
125 "Overlay used to highlight ASCII element corresponding to current point.")
126(make-variable-buffer-local 'hexl-ascii-overlay)
127
639b8e4d
MY
128(defvar hexl-font-lock-keywords
129 '(("^\\([0-9a-f]+:\\).\\{40\\} \\(.+$\\)"
130 ;; "^\\([0-9a-f]+:\\).+ \\(.+$\\)"
2d77d354
MY
131 (1 'hexl-address-region t t)
132 (2 'hexl-ascii-region t t)))
639b8e4d
MY
133 "Font lock keywords used in `hexl-mode'.")
134
a2535589
JA
135;; routines
136
2d902813
RS
137(put 'hexl-mode 'mode-class 'special)
138
31c75fa7 139;;;###autoload
a2535589 140(defun hexl-mode (&optional arg)
330bd7c3
PR
141 "\\<hexl-mode-map>A mode for editing binary files in hex dump format.
142This is not an ordinary major mode; it alters some aspects
fe0a77c6 143of the current mode's behavior, but not all; also, you can exit
330bd7c3 144Hexl mode and return to the previous mode using `hexl-mode-exit'.
a2535589
JA
145
146This function automatically converts a buffer into the hexl format
147using the function `hexlify-buffer'.
148
8a1281b5 149Each line in the buffer has an \"address\" (displayed in hexadecimal)
a2535589
JA
150representing the offset into the file that the characters on this line
151are at and 16 characters from the file (displayed as hexadecimal
152values grouped every 16 bits) and as their ASCII values.
153
154If any of the characters (displayed as ASCII characters) are
155unprintable (control or meta characters) they will be replaced as
156periods.
157
8a1281b5
RS
158If `hexl-mode' is invoked with an argument the buffer is assumed to be
159in hexl format.
a2535589
JA
160
161A sample format:
162
163 HEX ADDR: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f ASCII-TEXT
164 -------- ---- ---- ---- ---- ---- ---- ---- ---- ----------------
165 00000000: 5468 6973 2069 7320 6865 786c 2d6d 6f64 This is hexl-mod
166 00000010: 652e 2020 4561 6368 206c 696e 6520 7265 e. Each line re
167 00000020: 7072 6573 656e 7473 2031 3620 6279 7465 presents 16 byte
168 00000030: 7320 6173 2068 6578 6164 6563 696d 616c s as hexadecimal
169 00000040: 2041 5343 4949 0a61 6e64 2070 7269 6e74 ASCII.and print
170 00000050: 6162 6c65 2041 5343 4949 2063 6861 7261 able ASCII chara
171 00000060: 6374 6572 732e 2020 416e 7920 636f 6e74 cters. Any cont
172 00000070: 726f 6c20 6f72 206e 6f6e 2d41 5343 4949 rol or non-ASCII
71296446 173 00000080: 2063 6861 7261 6374 6572 730a 6172 6520 characters.are
a2535589
JA
174 00000090: 6469 7370 6c61 7965 6420 6173 2070 6572 displayed as per
175 000000a0: 696f 6473 2069 6e20 7468 6520 7072 696e iods in the prin
71296446 176 000000b0: 7461 626c 6520 6368 6172 6163 7465 7220 table character
a2535589
JA
177 000000c0: 7265 6769 6f6e 2e0a region..
178
89c24779 179Movement is as simple as movement in a normal Emacs text buffer. Most
a2535589
JA
180cursor movement bindings are the same (ie. Use \\[hexl-backward-char], \\[hexl-forward-char], \\[hexl-next-line], and \\[hexl-previous-line]
181to move the cursor left, right, down, and up).
182
183Advanced cursor movement commands (ala \\[hexl-beginning-of-line], \\[hexl-end-of-line], \\[hexl-beginning-of-buffer], and \\[hexl-end-of-buffer]) are
184also supported.
185
186There are several ways to change text in hexl mode:
187
188ASCII characters (character between space (0x20) and tilde (0x7E)) are
189bound to self-insert so you can simply type the character and it will
190insert itself (actually overstrike) into the buffer.
191
192\\[hexl-quoted-insert] followed by another keystroke allows you to insert the key even if
193it isn't bound to self-insert. An octal number can be supplied in place
194of another key to insert the octal number's ASCII representation.
195
196\\[hexl-insert-hex-char] will insert a given hexadecimal value (if it is between 0 and 0xFF)
197into the buffer at the current point.
198
199\\[hexl-insert-octal-char] will insert a given octal value (if it is between 0 and 0377)
200into the buffer at the current point.
201
202\\[hexl-insert-decimal-char] will insert a given decimal value (if it is between 0 and 255)
203into the buffer at the current point.
204
a2535589
JA
205\\[hexl-mode-exit] will exit hexl-mode.
206
31c75fa7
RS
207Note: saving the file with any of the usual Emacs commands
208will actually convert it back to binary format while saving.
a2535589 209
330bd7c3 210You can use \\[hexl-find-file] to visit a file in Hexl mode.
a2535589
JA
211
212\\[describe-bindings] for advanced commands."
213 (interactive "p")
330bd7c3 214 (unless (eq major-mode 'hexl-mode)
753c1309
RS
215 (let ((modified (buffer-modified-p))
216 (inhibit-read-only t)
312d24fb 217 (original-point (- (point) (point-min))))
753c1309
RS
218 (and (eobp) (not (bobp))
219 (setq original-point (1- original-point)))
312d24fb
SM
220 ;; If `hexl-mode' is invoked with an argument the buffer is assumed to
221 ;; be in hexl format.
222 (when (memq arg '(1 nil))
7851eb98
EZ
223 ;; If the buffer's EOL type is -dos, we need to account for
224 ;; extra CR characters added when hexlify-buffer writes the
225 ;; buffer to a file.
312d24fb 226 ;; FIXME: This doesn't take into account multibyte coding systems.
7851eb98 227 (when (eq (coding-system-eol-type buffer-file-coding-system) 1)
312d24fb 228 (setq original-point (+ (count-lines (point-min) (point))
7851eb98
EZ
229 original-point))
230 (or (bolp) (setq original-point (1- original-point))))
753c1309 231 (hexlify-buffer)
37dc4767 232 (restore-buffer-modified-p modified))
312d24fb
SM
233 (set (make-local-variable 'hexl-max-address)
234 (let* ((full-lines (/ (buffer-size) 68))
235 (last-line (% (buffer-size) 68))
236 (last-line-bytes (% last-line 52)))
237 (+ last-line-bytes (* full-lines 16) -1)))
55391f5e
RS
238 (condition-case nil
239 (hexl-goto-address original-point)
240 (error nil)))
753c1309 241
0e4889b2
RS
242 ;; We do not turn off the old major mode; instead we just
243 ;; override most of it. That way, we can restore it perfectly.
a2535589
JA
244 (make-local-variable 'hexl-mode-old-local-map)
245 (setq hexl-mode-old-local-map (current-local-map))
246 (use-local-map hexl-mode-map)
247
248 (make-local-variable 'hexl-mode-old-mode-name)
249 (setq hexl-mode-old-mode-name mode-name)
250 (setq mode-name "Hexl")
251
87b3b78a
SM
252 (set (make-local-variable 'hexl-mode-old-isearch-search-fun-function)
253 isearch-search-fun-function)
254 (set (make-local-variable 'isearch-search-fun-function)
255 'hexl-isearch-search-function)
256
a2535589
JA
257 (make-local-variable 'hexl-mode-old-major-mode)
258 (setq hexl-mode-old-major-mode major-mode)
259 (setq major-mode 'hexl-mode)
260
b27ce24f
RS
261 (make-local-variable 'hexl-mode-old-ruler-mode)
262 (setq hexl-mode-old-ruler-mode
263 (and (boundp 'ruler-mode) ruler-mode))
264
265 (make-local-variable 'hexl-mode-old-hl-line-mode)
266 (setq hexl-mode-old-hl-line-mode
267 (and (boundp 'hl-line-mode) hl-line-mode))
268
0e4889b2
RS
269 (make-local-variable 'hexl-mode-old-syntax-table)
270 (setq hexl-mode-old-syntax-table (syntax-table))
271 (set-syntax-table (standard-syntax-table))
272
87b3b78a 273 (add-hook 'write-contents-functions 'hexl-save-buffer nil t)
31c75fa7 274
0e4889b2
RS
275 (make-local-variable 'hexl-mode-old-require-final-newline)
276 (setq hexl-mode-old-require-final-newline require-final-newline)
277 (make-local-variable 'require-final-newline)
278 (setq require-final-newline nil)
279
639b8e4d
MY
280 (make-local-variable 'hexl-mode-old-font-lock-keywords)
281 (setq hexl-mode-old-font-lock-keywords font-lock-defaults)
639b8e4d
MY
282 (setq font-lock-defaults '(hexl-font-lock-keywords t))
283
0e4889b2 284 ;; Add hooks to rehexlify or dehexlify on various events.
a30cc07b 285 (add-hook 'before-revert-hook 'hexl-before-revert-hook nil t)
c3de2bf0
RS
286 (add-hook 'after-revert-hook 'hexl-after-revert-hook nil t)
287
db6c5b92
SE
288 (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t)
289
01ff9136 290 ;; Set a callback function for eldoc.
cfea581f
JPW
291 (make-local-variable 'hexl-mode-old-eldoc-documentation-function)
292 (setq hexl-mode-old-eldoc-documentation-function
293 (bound-and-true-p eldoc-documentation-function))
294
881e0a3c 295 (set (make-local-variable 'eldoc-documentation-function)
01ff9136
MY
296 'hexl-print-current-point-info)
297 (eldoc-add-command-completions "hexl-")
625c1523 298 (eldoc-remove-command "hexl-save-buffer"
01ff9136
MY
299 "hexl-current-address")
300
db6c5b92 301 (if hexl-follow-ascii (hexl-follow-ascii 1)))
36555efc 302 (run-mode-hooks 'hexl-mode-hook))
a2535589 303
87b3b78a
SM
304
305(defun hexl-isearch-search-function ()
306 (if (and (not isearch-regexp) (not isearch-word))
307 (lambda (string &optional bound noerror count)
308 (funcall
309 (if isearch-forward 're-search-forward 're-search-backward)
37dc4767
SM
310 (let ((textre
311 (if (> (length string) 80)
312 (regexp-quote string)
313 (mapconcat (lambda (c) (regexp-quote (string c))) string
314 "\\(?:\n\\(?:[:a-f0-9]+ \\)+ \\)?"))))
315 (if (string-match "\\` ?\\([a-f0-9]+ \\)*[a-f0-9]+ ?\\'" string)
316 (concat textre "\\|"
317 (mapconcat 'regexp-quote (split-string string " ")
318 " \\(?: .+\n[a-f0-9]+: \\)?"))
319 textre))
87b3b78a
SM
320 bound noerror count))
321 (let ((isearch-search-fun-function nil))
322 (isearch-search-fun))))
323
f77c618f
CY
324(defun hexl-before-revert-hook ()
325 (remove-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer t))
326
c3de2bf0 327(defun hexl-after-revert-hook ()
f77c618f 328 (hexl-mode))
c3de2bf0 329
ac2e902d
JB
330(defvar hexl-in-save-buffer nil)
331
a2535589
JA
332(defun hexl-save-buffer ()
333 "Save a hexl format buffer as binary in visited file if modified."
334 (interactive)
ac2e902d 335 (if hexl-in-save-buffer nil
37dc4767
SM
336 (restore-buffer-modified-p
337 (if (buffer-modified-p)
338 (let ((buf (generate-new-buffer " hexl"))
339 (name (buffer-name))
340 (start (point-min))
341 (end (point-max))
342 modified)
343 (with-current-buffer buf
344 (insert-buffer-substring name start end)
345 (set-buffer name)
346 (dehexlify-buffer)
347 ;; Prevent infinite recursion.
348 (let ((hexl-in-save-buffer t))
349 (save-buffer))
350 (setq modified (buffer-modified-p))
351 (delete-region (point-min) (point-max))
352 (insert-buffer-substring buf start end)
353 (kill-buffer buf)
354 modified))
355 (message "(No changes need to be saved)")
356 nil))
ac2e902d
JB
357 ;; Return t to indicate we have saved t
358 t))
a2535589 359
31c75fa7 360;;;###autoload
a2535589 361(defun hexl-find-file (filename)
7f9da0f3
EZ
362 "Edit file FILENAME as a binary file in hex dump format.
363Switch to a buffer visiting file FILENAME, creating one if none exists,
364and edit the file in `hexl-mode'."
e49a45ad
MB
365 (interactive
366 (list
367 (let ((completion-ignored-extensions nil))
368 (read-file-name "Filename: " nil nil 'ret-must-match))))
14acf2f5
SM
369 ;; Ignore the user's setting of default major-mode.
370 (letf (((default-value 'major-mode) 'fundamental-mode))
3db6aff6 371 (find-file-literally filename))
a2535589
JA
372 (if (not (eq major-mode 'hexl-mode))
373 (hexl-mode)))
374
375(defun hexl-mode-exit (&optional arg)
31c75fa7 376 "Exit Hexl mode, returning to previous mode.
a2535589
JA
377With arg, don't unhexlify buffer."
378 (interactive "p")
379 (if (or (eq arg 1) (not arg))
380 (let ((modified (buffer-modified-p))
900014dd 381 (inhibit-read-only t)
a2535589 382 (original-point (1+ (hexl-current-address))))
a2535589 383 (dehexlify-buffer)
87b3b78a 384 (remove-hook 'write-contents-functions 'hexl-save-buffer t)
37dc4767 385 (restore-buffer-modified-p modified)
7851eb98
EZ
386 (goto-char original-point)
387 ;; Maybe adjust point for the removed CR characters.
388 (when (eq (coding-system-eol-type buffer-file-coding-system) 1)
389 (setq original-point (- original-point
390 (count-lines (point-min) (point))))
391 (or (bobp) (setq original-point (1+ original-point))))
a2535589 392 (goto-char original-point)))
0e4889b2 393
f77c618f 394 (remove-hook 'before-revert-hook 'hexl-before-revert-hook t)
0e4889b2
RS
395 (remove-hook 'after-revert-hook 'hexl-after-revert-hook t)
396 (remove-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer t)
8e7df2e6
SE
397 (remove-hook 'post-command-hook 'hexl-follow-ascii-find t)
398 (setq hexl-ascii-overlay nil)
0e4889b2 399
b27ce24f
RS
400 (if (and (boundp 'ruler-mode) ruler-mode (not hexl-mode-old-ruler-mode))
401 (ruler-mode 0))
3fc29559
MY
402 (when (boundp 'hexl-mode-old-ruler-function)
403 (setq ruler-mode-ruler-function hexl-mode-old-ruler-function))
404
b27ce24f
RS
405 (if (and (boundp 'hl-line-mode) hl-line-mode (not hexl-mode-old-hl-line-mode))
406 (hl-line-mode 0))
3fc29559
MY
407 (when (boundp 'hexl-mode-old-hl-line-range-function)
408 (setq hl-line-range-function hexl-mode-old-hl-line-range-function))
a30cc07b 409 (when (boundp 'hexl-mode-old-hl-line-face)
3fc29559 410 (setq hl-line-face hexl-mode-old-hl-line-face))
a30cc07b 411
cfea581f
JPW
412 (when (boundp 'hexl-mode-old-eldoc-documentation-function)
413 (setq eldoc-documentation-function
414 hexl-mode-old-eldoc-documentation-function))
415
0e4889b2 416 (setq require-final-newline hexl-mode-old-require-final-newline)
a2535589 417 (setq mode-name hexl-mode-old-mode-name)
87b3b78a 418 (setq isearch-search-fun-function hexl-mode-old-isearch-search-fun-function)
a2535589 419 (use-local-map hexl-mode-old-local-map)
0e4889b2 420 (set-syntax-table hexl-mode-old-syntax-table)
639b8e4d 421 (setq font-lock-defaults hexl-mode-old-font-lock-keywords)
a2535589 422 (setq major-mode hexl-mode-old-major-mode)
8eeac2ce
RS
423 (force-mode-line-update))
424
425(defun hexl-maybe-dehexlify-buffer ()
426 "Convert a hexl format buffer to binary.
427Ask the user for confirmation."
428 (if (y-or-n-p "Convert contents back to binary format? ")
429 (let ((modified (buffer-modified-p))
430 (inhibit-read-only t)
431 (original-point (1+ (hexl-current-address))))
432 (dehexlify-buffer)
87b3b78a 433 (remove-hook 'write-contents-functions 'hexl-save-buffer t)
37dc4767 434 (restore-buffer-modified-p modified)
8eeac2ce 435 (goto-char original-point))))
a2535589 436
6bbb008e 437(defun hexl-current-address (&optional validate)
a2535589
JA
438 "Return current hexl-address."
439 (interactive)
87b3b78a 440 (let ((current-column (- (% (- (point) (point-min) -1) 68) 11))
a2535589 441 (hexl-address 0))
6bbb008e
RS
442 (if (< current-column 0)
443 (if validate
444 (error "Point is not on a character in the file")
445 (setq current-column 0)))
446 (setq hexl-address
87b3b78a 447 (+ (* (/ (- (point) (point-min) -1) 68) 16)
6bbb008e
RS
448 (if (>= current-column 41)
449 (- current-column 41)
450 (/ (- current-column (/ current-column 5)) 2))))
32226619 451 (when (called-interactively-p 'interactive)
01ff9136 452 (message "Current address is %d/0x%08x" hexl-address hexl-address))
a2535589
JA
453 hexl-address))
454
01ff9136
MY
455(defun hexl-print-current-point-info ()
456 "Return current hexl-address in string.
12d96c20 457This function is intended to be used as eldoc callback."
01ff9136
MY
458 (let ((addr (hexl-current-address)))
459 (format "Current address is %d/0x%08x" addr addr)))
460
a2535589 461(defun hexl-address-to-marker (address)
059c2e18 462 "Return buffer position for ADDRESS."
a2535589 463 (interactive "nAddress: ")
87b3b78a 464 (+ (* (/ address 16) 68) 10 (point-min) (/ (* (% address 16) 5) 2)))
a2535589
JA
465
466(defun hexl-goto-address (address)
61dd70aa 467 "Go to hexl-mode (decimal) address ADDRESS.
5232b4cd 468Signal error if ADDRESS is out of range."
a2535589
JA
469 (interactive "nAddress: ")
470 (if (or (< address 0) (> address hexl-max-address))
55391f5e 471 (error "Out of hexl region"))
a2535589
JA
472 (goto-char (hexl-address-to-marker address)))
473
474(defun hexl-goto-hex-address (hex-address)
4c8c7ae9 475 "Go to hexl-mode address (hex string) HEX-ADDRESS.
a2535589
JA
476Signal error if HEX-ADDRESS is out of range."
477 (interactive "sHex Address: ")
478 (hexl-goto-address (hexl-hex-string-to-integer hex-address)))
479
480(defun hexl-hex-string-to-integer (hex-string)
481 "Return decimal integer for HEX-STRING."
482 (interactive "sHex number: ")
483 (let ((hex-num 0))
484 (while (not (equal hex-string ""))
485 (setq hex-num (+ (* hex-num 16)
486 (hexl-hex-char-to-integer (string-to-char hex-string))))
487 (setq hex-string (substring hex-string 1)))
488 hex-num))
489
490(defun hexl-octal-string-to-integer (octal-string)
491 "Return decimal integer for OCTAL-STRING."
492 (interactive "sOctal number: ")
493 (let ((oct-num 0))
494 (while (not (equal octal-string ""))
495 (setq oct-num (+ (* oct-num 8)
496 (hexl-oct-char-to-integer
497 (string-to-char octal-string))))
498 (setq octal-string (substring octal-string 1)))
499 oct-num))
500
501;; move point functions
502
503(defun hexl-backward-char (arg)
504 "Move to left ARG bytes (right if ARG negative) in hexl-mode."
505 (interactive "p")
506 (hexl-goto-address (- (hexl-current-address) arg)))
507
508(defun hexl-forward-char (arg)
5232b4cd 509 "Move to right ARG bytes (left if ARG negative) in hexl-mode."
a2535589
JA
510 (interactive "p")
511 (hexl-goto-address (+ (hexl-current-address) arg)))
512
513(defun hexl-backward-short (arg)
514 "Move to left ARG shorts (right if ARG negative) in hexl-mode."
515 (interactive "p")
516 (hexl-goto-address (let ((address (hexl-current-address)))
517 (if (< arg 0)
518 (progn
519 (setq arg (- arg))
520 (while (> arg 0)
521 (if (not (equal address (logior address 3)))
522 (if (> address hexl-max-address)
523 (progn
524 (message "End of buffer.")
525 (setq address hexl-max-address))
526 (setq address (logior address 3)))
527 (if (> address hexl-max-address)
528 (progn
529 (message "End of buffer.")
530 (setq address hexl-max-address))
531 (setq address (+ address 4))))
532 (setq arg (1- arg)))
533 (if (> address hexl-max-address)
534 (progn
535 (message "End of buffer.")
536 (setq address hexl-max-address))
537 (setq address (logior address 3))))
538 (while (> arg 0)
539 (if (not (equal address (logand address -4)))
540 (setq address (logand address -4))
541 (if (not (equal address 0))
542 (setq address (- address 4))
543 (message "Beginning of buffer.")))
544 (setq arg (1- arg))))
545 address)))
546
547(defun hexl-forward-short (arg)
5232b4cd 548 "Move to right ARG shorts (left if ARG negative) in hexl-mode."
a2535589
JA
549 (interactive "p")
550 (hexl-backward-short (- arg)))
551
552(defun hexl-backward-word (arg)
553 "Move to left ARG words (right if ARG negative) in hexl-mode."
554 (interactive "p")
555 (hexl-goto-address (let ((address (hexl-current-address)))
556 (if (< arg 0)
557 (progn
558 (setq arg (- arg))
559 (while (> arg 0)
560 (if (not (equal address (logior address 7)))
561 (if (> address hexl-max-address)
562 (progn
563 (message "End of buffer.")
564 (setq address hexl-max-address))
565 (setq address (logior address 7)))
566 (if (> address hexl-max-address)
567 (progn
568 (message "End of buffer.")
569 (setq address hexl-max-address))
570 (setq address (+ address 8))))
571 (setq arg (1- arg)))
572 (if (> address hexl-max-address)
573 (progn
574 (message "End of buffer.")
575 (setq address hexl-max-address))
576 (setq address (logior address 7))))
577 (while (> arg 0)
578 (if (not (equal address (logand address -8)))
579 (setq address (logand address -8))
580 (if (not (equal address 0))
581 (setq address (- address 8))
582 (message "Beginning of buffer.")))
583 (setq arg (1- arg))))
584 address)))
585
586(defun hexl-forward-word (arg)
5232b4cd 587 "Move to right ARG words (left if ARG negative) in hexl-mode."
a2535589
JA
588 (interactive "p")
589 (hexl-backward-word (- arg)))
590
591(defun hexl-previous-line (arg)
4c8c7ae9 592 "Move vertically up ARG lines [16 bytes] (down if ARG negative) in hexl-mode.
5232b4cd 593If there is no byte at the target address move to the last byte in that line."
a2535589
JA
594 (interactive "p")
595 (hexl-next-line (- arg)))
596
597(defun hexl-next-line (arg)
4c8c7ae9
JB
598 "Move vertically down ARG lines [16 bytes] (up if ARG negative) in hexl-mode.
599If there is no byte at the target address move to the last byte in that line."
a2535589 600 (interactive "p")
e8a57935 601 (hexl-goto-address (let ((address (+ (hexl-current-address) (* arg 16))))
a2535589
JA
602 (if (and (< arg 0) (< address 0))
603 (progn (message "Out of hexl region.")
604 (setq address
605 (% (hexl-current-address) 16)))
606 (if (and (> address hexl-max-address)
607 (< (% hexl-max-address 16) (% address 16)))
608 (setq address hexl-max-address)
609 (if (> address hexl-max-address)
610 (progn (message "Out of hexl region.")
611 (setq
612 address
613 (+ (logand hexl-max-address -16)
614 (% (hexl-current-address) 16)))))))
615 address)))
616
617(defun hexl-beginning-of-buffer (arg)
4c8c7ae9
JB
618 "Move to the beginning of the hexl buffer.
619Leaves `hexl-mark' at previous position.
620With prefix arg N, puts point N bytes of the way from the true beginning."
a2535589
JA
621 (interactive "p")
622 (push-mark (point))
623 (hexl-goto-address (+ 0 (1- arg))))
624
625(defun hexl-end-of-buffer (arg)
4c8c7ae9 626 "Go to `hexl-max-address' minus ARG."
a2535589
JA
627 (interactive "p")
628 (push-mark (point))
629 (hexl-goto-address (- hexl-max-address (1- arg))))
630
631(defun hexl-beginning-of-line ()
632 "Goto beginning of line in hexl mode."
633 (interactive)
634 (goto-char (+ (* (/ (point) 68) 68) 11)))
635
636(defun hexl-end-of-line ()
637 "Goto end of line in hexl mode."
638 (interactive)
639 (hexl-goto-address (let ((address (logior (hexl-current-address) 15)))
640 (if (> address hexl-max-address)
641 (setq address hexl-max-address))
642 address)))
643
644(defun hexl-scroll-down (arg)
645 "Scroll hexl buffer window upward ARG lines; or near full window if no ARG."
646 (interactive "P")
647 (if (null arg)
648 (setq arg (1- (window-height)))
649 (setq arg (prefix-numeric-value arg)))
650 (hexl-scroll-up (- arg)))
651
652(defun hexl-scroll-up (arg)
d565f6aa
EZ
653 "Scroll hexl buffer window upward ARG lines; or near full window if no ARG.
654If there's no byte at the target address, move to the first or last line."
a2535589
JA
655 (interactive "P")
656 (if (null arg)
657 (setq arg (1- (window-height)))
658 (setq arg (prefix-numeric-value arg)))
d565f6aa
EZ
659 (let* ((movement (* arg 16))
660 (address (hexl-current-address))
661 (dest (+ address movement)))
662 (cond
663 ;; If possible, try to stay at the same offset from the beginning
664 ;; of the 16-byte group, even if we move to the first or last
665 ;; group.
666 ((and (> dest hexl-max-address)
667 (>= (% hexl-max-address 16) (% address 16)))
668 (setq dest (+ (logand hexl-max-address -16) (% address 16))))
669 ((> dest hexl-max-address)
670 (setq dest hexl-max-address))
671 ((< dest 0)
672 (setq dest (% address 16))))
673 (if (/= dest (+ address movement))
674 (message "Out of hexl region."))
675 (hexl-goto-address dest)
676 (recenter 0)))
a2535589
JA
677
678(defun hexl-beginning-of-1k-page ()
5232b4cd 679 "Go to beginning of 1KB boundary."
a2535589
JA
680 (interactive)
681 (hexl-goto-address (logand (hexl-current-address) -1024)))
682
683(defun hexl-end-of-1k-page ()
5232b4cd 684 "Go to end of 1KB boundary."
a2535589
JA
685 (interactive)
686 (hexl-goto-address (let ((address (logior (hexl-current-address) 1023)))
687 (if (> address hexl-max-address)
688 (setq address hexl-max-address))
689 address)))
690
691(defun hexl-beginning-of-512b-page ()
65e5f4bc 692 "Go to beginning of 512 byte boundary."
a2535589
JA
693 (interactive)
694 (hexl-goto-address (logand (hexl-current-address) -512)))
695
696(defun hexl-end-of-512b-page ()
65e5f4bc 697 "Go to end of 512 byte boundary."
a2535589
JA
698 (interactive)
699 (hexl-goto-address (let ((address (logior (hexl-current-address) 511)))
700 (if (> address hexl-max-address)
701 (setq address hexl-max-address))
702 address)))
703
704(defun hexl-quoted-insert (arg)
705 "Read next input character and insert it.
02aec07b
EZ
706Useful for inserting control characters and non-ASCII characters given their
707numerical code.
708You may also type octal digits, to insert a character with that code."
a2535589 709 (interactive "p")
02aec07b 710 (hexl-insert-multibyte-char (read-quoted-char) arg))
a2535589
JA
711
712;00000000: 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF
713
f4e3d4eb 714;;;###autoload
a2535589 715(defun hexlify-buffer ()
aa3757b8
RS
716 "Convert a binary buffer to hexl format.
717This discards the buffer's undo information."
a2535589 718 (interactive)
62222158 719 (and (consp buffer-undo-list)
aa3757b8 720 (or (y-or-n-p "Converting to hexl format discards undo info; ok? ")
62222158
SM
721 (error "Aborted"))
722 (setq buffer-undo-list nil))
a749e5e5
EZ
723 ;; Don't decode text in the ASCII part of `hexl' program output.
724 (let ((coding-system-for-read 'raw-text)
0716afa2 725 (coding-system-for-write buffer-file-coding-system)
aa3757b8 726 (buffer-undo-list t))
b8c49a19
SM
727 (apply 'call-process-region (point-min) (point-max)
728 (expand-file-name hexl-program exec-directory)
4a729d58
SM
729 t t nil
730 ;; Manually encode the args, otherwise they're encoded using
731 ;; coding-system-for-write (i.e. buffer-file-coding-system) which
732 ;; may not be what we want (e.g. utf-16 on a non-utf-16 system).
312d24fb
SM
733 (mapcar (lambda (s)
734 (if (not (multibyte-string-p s)) s
735 (encode-coding-string s locale-coding-system)))
4a729d58 736 (split-string hexl-options)))
059c2e18
PR
737 (if (> (point) (hexl-address-to-marker hexl-max-address))
738 (hexl-goto-address hexl-max-address))))
a2535589
JA
739
740(defun dehexlify-buffer ()
aa3757b8
RS
741 "Convert a hexl format buffer to binary.
742This discards the buffer's undo information."
a2535589 743 (interactive)
62222158 744 (and (consp buffer-undo-list)
aa3757b8 745 (or (y-or-n-p "Converting from hexl format discards undo info; ok? ")
62222158
SM
746 (error "Aborted"))
747 (setq buffer-undo-list nil))
a749e5e5 748 (let ((coding-system-for-write 'raw-text)
0716afa2 749 (coding-system-for-read buffer-file-coding-system)
aa3757b8 750 (buffer-undo-list t))
b8c49a19
SM
751 (apply 'call-process-region (point-min) (point-max)
752 (expand-file-name hexl-program exec-directory)
753 t t nil "-de" (split-string hexl-options))))
a2535589
JA
754
755(defun hexl-char-after-point ()
756 "Return char for ASCII hex digits at point."
686fc9ab
RS
757 (hexl-htoi (char-after (point))
758 (char-after (1+ (point)))))
a2535589
JA
759
760(defun hexl-htoi (lh rh)
761 "Hex (char) LH (char) RH to integer."
762 (+ (* (hexl-hex-char-to-integer lh) 16)
763 (hexl-hex-char-to-integer rh)))
764
765(defun hexl-hex-char-to-integer (character)
766 "Take a char and return its value as if it was a hex digit."
767 (if (and (>= character ?0) (<= character ?9))
768 (- character ?0)
769 (let ((ch (logior character 32)))
770 (if (and (>= ch ?a) (<= ch ?f))
771 (- ch (- ?a 10))
19e31f7c 772 (error "Invalid hex digit `%c'" ch)))))
a2535589
JA
773
774(defun hexl-oct-char-to-integer (character)
775 "Take a char and return its value as if it was a octal digit."
776 (if (and (>= character ?0) (<= character ?7))
777 (- character ?0)
19e31f7c 778 (error "Invalid octal digit `%c'" character)))
a2535589
JA
779
780(defun hexl-printable-character (ch)
781 "Return a displayable string for character CH."
9c23ca47
JB
782 (format "%c" (if (equal hexl-iso "")
783 (if (or (< ch 32) (>= ch 127))
a2535589
JA
784 46
785 ch)
9c23ca47 786 (if (or (< ch 32) (and (>= ch 127) (< ch 160)))
a2535589
JA
787 46
788 ch))))
789
02aec07b
EZ
790(defun hexl-insert-multibyte-char (ch num)
791 "Insert a possibly multibyte character CH NUM times.
792
793Non-ASCII characters are first encoded with `buffer-file-coding-system',
794and their encoded form is inserted byte by byte."
795 (let ((charset (char-charset ch))
796 (coding (if (or (null buffer-file-coding-system)
797 ;; coding-system-type equals t means undecided.
798 (eq (coding-system-type buffer-file-coding-system) t))
b56a5ae0 799 (default-value 'buffer-file-coding-system)
02aec07b
EZ
800 buffer-file-coding-system)))
801 (cond ((and (> ch 0) (< ch 256))
802 (hexl-insert-char ch num))
803 ((eq charset 'unknown)
804 (error
165b4283 805 "0x%x -- invalid character code; use \\[hexl-insert-hex-string]"
02aec07b
EZ
806 ch))
807 (t
808 (let ((encoded (encode-coding-char ch coding))
809 (internal (string-as-unibyte (char-to-string ch)))
810 internal-hex)
811 ;; If encode-coding-char returns nil, it means our character
812 ;; cannot be safely encoded with buffer-file-coding-system.
813 ;; In that case, we offer to insert the internal representation
814 ;; of that character, byte by byte.
815 (when (null encoded)
816 (setq internal-hex
817 (mapconcat (function (lambda (c) (format "%x" c)))
818 internal " "))
819 (if (yes-or-no-p
820 (format
821 "Insert char 0x%x's internal representation \"%s\"? "
822 ch internal-hex))
823 (setq encoded internal)
824 (error
165b4283 825 "Can't encode `0x%x' with this buffer's coding system; try \\[hexl-insert-hex-string]"
02aec07b
EZ
826 ch)))
827 (while (> num 0)
828 (mapc
829 (function (lambda (c) (hexl-insert-char c 1))) encoded)
830 (setq num (1- num))))))))
831
a2535589 832(defun hexl-self-insert-command (arg)
02aec07b
EZ
833 "Insert this character.
834Interactively, with a numeric argument, insert this character that many times.
835
836Non-ASCII characters are first encoded with `buffer-file-coding-system',
837and their encoded form is inserted byte by byte."
a2535589 838 (interactive "p")
8989a920 839 (hexl-insert-multibyte-char last-command-event arg))
a2535589
JA
840
841(defun hexl-insert-char (ch num)
02aec07b
EZ
842 "Insert the character CH NUM times in a hexl buffer.
843
844CH must be a unibyte character whose value is between 0 and 255."
845 (if (or (< ch 0) (> ch 255))
45ad49ba 846 (error "Invalid character 0x%x -- must be in the range [0..255]" ch))
6bbb008e 847 (let ((address (hexl-current-address t)))
a2535589 848 (while (> num 0)
6bbb008e
RS
849 (let ((hex-position
850 (+ (* (/ address 16) 68)
87b3b78a 851 10 (point-min)
6bbb008e
RS
852 (* 2 (% address 16))
853 (/ (% address 16) 2)))
854 (ascii-position
87b3b78a 855 (+ (* (/ address 16) 68) 51 (point-min) (% address 16)))
6bbb008e
RS
856 at-ascii-position)
857 (if (= (point) ascii-position)
858 (setq at-ascii-position t))
859 (goto-char hex-position)
860 (delete-char 2)
861 (insert (format "%02x" ch))
862 (goto-char ascii-position)
863 (delete-char 1)
864 (insert (hexl-printable-character ch))
865 (or (eq address hexl-max-address)
866 (setq address (1+ address)))
867 (hexl-goto-address address)
868 (if at-ascii-position
869 (progn
870 (beginning-of-line)
871 (forward-char 51)
872 (forward-char (% address 16)))))
a2535589
JA
873 (setq num (1- num)))))
874
875;; hex conversion
876
877(defun hexl-insert-hex-char (arg)
02aec07b 878 "Insert a character given by its hexadecimal code ARG times at point."
a2535589
JA
879 (interactive "p")
880 (let ((num (hexl-hex-string-to-integer (read-string "Hex number: "))))
02aec07b 881 (if (< num 0)
19e31f7c 882 (error "Hex number out of range")
02aec07b 883 (hexl-insert-multibyte-char num arg))))
a2535589 884
9f6bff44
GM
885(defun hexl-insert-hex-string (str arg)
886 "Insert hexadecimal string STR at point ARG times.
887Embedded whitespace, dashes, and periods in the string are ignored."
888 (interactive "sHex string: \np")
889 (setq str (replace-regexp-in-string "[- \t.]" "" str))
890 (let ((chars '()))
891 (let ((len (length str))
892 (idx 0))
893 (if (eq (logand len 1) 1)
894 (let ((num (hexl-hex-string-to-integer (substring str 0 1))))
895 (setq chars (cons num chars))
896 (setq idx 1)))
897 (while (< idx len)
898 (let* ((nidx (+ idx 2))
899 (num (hexl-hex-string-to-integer (substring str idx nidx))))
900 (setq chars (cons num chars))
901 (setq idx nidx))))
902 (setq chars (nreverse chars))
903 (while (> arg 0)
904 (let ((chars chars))
905 (while chars
906 (hexl-insert-char (car chars) 1)
907 (setq chars (cdr chars))))
908 (setq arg (- arg 1)))))
909
a2535589 910(defun hexl-insert-decimal-char (arg)
02aec07b 911 "Insert a character given by its decimal code ARG times at point."
a2535589 912 (interactive "p")
027a4b6b 913 (let ((num (string-to-number (read-string "Decimal Number: "))))
02aec07b 914 (if (< num 0)
19e31f7c 915 (error "Decimal number out of range")
02aec07b 916 (hexl-insert-multibyte-char num arg))))
a2535589
JA
917
918(defun hexl-insert-octal-char (arg)
02aec07b 919 "Insert a character given by its octal code ARG times at point."
a2535589
JA
920 (interactive "p")
921 (let ((num (hexl-octal-string-to-integer (read-string "Octal Number: "))))
02aec07b 922 (if (< num 0)
19e31f7c 923 (error "Decimal number out of range")
02aec07b 924 (hexl-insert-multibyte-char num arg))))
a2535589 925
db6c5b92
SE
926(defun hexl-follow-ascii (&optional arg)
927 "Toggle following ASCII in Hexl buffers.
928With prefix ARG, turn on following if and only if ARG is positive.
929When following is enabled, the ASCII character corresponding to the
930element under the point is highlighted.
931Customize the variable `hexl-follow-ascii' to disable this feature."
932 (interactive "P")
71296446 933 (let ((on-p (if arg
db6c5b92
SE
934 (> (prefix-numeric-value arg) 0)
935 (not hexl-ascii-overlay))))
936
db6c5b92
SE
937 (if on-p
938 ;; turn it on
939 (if (not hexl-ascii-overlay)
940 (progn
941 (setq hexl-ascii-overlay (make-overlay 1 1)
942 hexl-follow-ascii t)
943 (overlay-put hexl-ascii-overlay 'face 'highlight)
944 (add-hook 'post-command-hook 'hexl-follow-ascii-find nil t)))
945 ;; turn it off
946 (if hexl-ascii-overlay
947 (progn
948 (delete-overlay hexl-ascii-overlay)
949 (setq hexl-ascii-overlay nil
950 hexl-follow-ascii nil)
951 (remove-hook 'post-command-hook 'hexl-follow-ascii-find t)
952 )))))
953
9fd76d04 954(defun hexl-activate-ruler ()
37dc4767 955 "Activate `ruler-mode'."
9fd76d04 956 (require 'ruler-mode)
3fc29559
MY
957 (unless (boundp 'hexl-mode-old-ruler-function)
958 (set (make-local-variable 'hexl-mode-old-ruler-function)
959 ruler-mode-ruler-function))
625c1523 960 (set (make-local-variable 'ruler-mode-ruler-function)
9fd76d04
MY
961 'hexl-mode-ruler)
962 (ruler-mode 1))
963
964(defun hexl-follow-line ()
37dc4767 965 "Activate `hl-line-mode'."
9fd76d04 966 (require 'hl-line)
3fc29559
MY
967 (unless (boundp 'hexl-mode-old-hl-line-range-function)
968 (set (make-local-variable 'hexl-mode-old-hl-line-range-function)
969 hl-line-range-function))
970 (unless (boundp 'hexl-mode-old-hl-line-face)
971 (set (make-local-variable 'hexl-mode-old-hl-line-face)
972 hl-line-face))
973 (set (make-local-variable 'hl-line-range-function)
974 'hexl-highlight-line-range)
975 (set (make-local-variable 'hl-line-face)
976 'highlight)
9fd76d04
MY
977 (hl-line-mode 1))
978
979(defun hexl-highlight-line-range ()
2d77d354 980 "Return the range of address region for the point.
5232b4cd 981This function is assumed to be used as callback function for `hl-line-mode'."
9fd76d04
MY
982 (cons
983 (line-beginning-position)
984 ;; 9 stands for (length "87654321:")
985 (+ (line-beginning-position) 9)))
986
db6c5b92
SE
987(defun hexl-follow-ascii-find ()
988 "Find and highlight the ASCII element corresponding to current point."
d565f6aa 989 (let ((pos (+ 51
db6c5b92
SE
990 (- (point) (current-column))
991 (mod (hexl-current-address) 16))))
992 (move-overlay hexl-ascii-overlay pos (1+ pos))
993 ))
994
9fd76d04
MY
995(defun hexl-mode-ruler ()
996 "Return a string ruler for hexl mode."
997 (let* ((highlight (mod (hexl-current-address) 16))
4c4ac516
KS
998 (s " 87654321 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789abcdef")
999 (pos 0))
9fd76d04
MY
1000 (set-text-properties 0 (length s) nil s)
1001 ;; Turn spaces in the header into stretch specs so they work
1002 ;; regardless of the header-line face.
1003 (while (string-match "[ \t]+" s pos)
1004 (setq pos (match-end 0))
1005 (put-text-property (match-beginning 0) pos 'display
1006 ;; Assume fixed-size chars
4c4ac516 1007 `(space :align-to ,(1- pos))
9fd76d04
MY
1008 s))
1009 ;; Highlight the current column.
4c4ac516
KS
1010 (put-text-property (+ 11 (/ (* 5 highlight) 2))
1011 (+ 13 (/ (* 5 highlight) 2))
9fd76d04
MY
1012 'face 'highlight s)
1013 ;; Highlight the current ascii column
4c4ac516 1014 (put-text-property (+ 13 39 highlight) (+ 13 40 highlight)
9fd76d04 1015 'face 'highlight s)
4c4ac516 1016 s))
9fd76d04 1017
a2535589
JA
1018;; startup stuff.
1019
1020(if hexl-mode-map
1021 nil
4b7dd7e2 1022 (setq hexl-mode-map (make-keymap))
02aec07b
EZ
1023 ;; Make all self-inserting keys go through hexl-self-insert-command,
1024 ;; because we need to convert them to unibyte characters before
1025 ;; inserting them into the buffer.
340c4d85 1026 (define-key hexl-mode-map [remap self-insert-command] 'hexl-self-insert-command)
ae2d451b 1027
d9c8518d 1028 (define-key hexl-mode-map "\C-m" 'hexl-self-insert-command)
ae2d451b
RS
1029 (define-key hexl-mode-map [left] 'hexl-backward-char)
1030 (define-key hexl-mode-map [right] 'hexl-forward-char)
1031 (define-key hexl-mode-map [up] 'hexl-previous-line)
1032 (define-key hexl-mode-map [down] 'hexl-next-line)
1033 (define-key hexl-mode-map [M-left] 'hexl-backward-short)
480c8cd3 1034 (define-key hexl-mode-map [?\e left] 'hexl-backward-short)
ae2d451b 1035 (define-key hexl-mode-map [M-right] 'hexl-forward-short)
480c8cd3 1036 (define-key hexl-mode-map [?\e right] 'hexl-forward-short)
ae2d451b
RS
1037 (define-key hexl-mode-map [next] 'hexl-scroll-up)
1038 (define-key hexl-mode-map [prior] 'hexl-scroll-down)
d565f6aa
EZ
1039 (define-key hexl-mode-map [home] 'hexl-beginning-of-line)
1040 (define-key hexl-mode-map [end] 'hexl-end-of-line)
1041 (define-key hexl-mode-map [C-home] 'hexl-beginning-of-buffer)
1042 (define-key hexl-mode-map [C-end] 'hexl-end-of-buffer)
ae2d451b
RS
1043 (define-key hexl-mode-map [deletechar] 'undefined)
1044 (define-key hexl-mode-map [deleteline] 'undefined)
1045 (define-key hexl-mode-map [insertline] 'undefined)
1046 (define-key hexl-mode-map [S-delete] 'undefined)
1047 (define-key hexl-mode-map "\177" 'undefined)
1048
1049 (define-key hexl-mode-map "\C-a" 'hexl-beginning-of-line)
1050 (define-key hexl-mode-map "\C-b" 'hexl-backward-char)
1051 (define-key hexl-mode-map "\C-d" 'undefined)
1052 (define-key hexl-mode-map "\C-e" 'hexl-end-of-line)
1053 (define-key hexl-mode-map "\C-f" 'hexl-forward-char)
1054
625c1523
JB
1055 (if (not (memq (key-binding (char-to-string help-char))
1056 '(help-command ehelp-command)))
ae2d451b
RS
1057 (define-key hexl-mode-map (char-to-string help-char) 'undefined))
1058
ae2d451b 1059 (define-key hexl-mode-map "\C-k" 'undefined)
ae2d451b
RS
1060 (define-key hexl-mode-map "\C-n" 'hexl-next-line)
1061 (define-key hexl-mode-map "\C-o" 'undefined)
1062 (define-key hexl-mode-map "\C-p" 'hexl-previous-line)
1063 (define-key hexl-mode-map "\C-q" 'hexl-quoted-insert)
1064 (define-key hexl-mode-map "\C-t" 'undefined)
1065 (define-key hexl-mode-map "\C-v" 'hexl-scroll-up)
1066 (define-key hexl-mode-map "\C-w" 'undefined)
1067 (define-key hexl-mode-map "\C-y" 'undefined)
1068
02aec07b
EZ
1069 (fset 'hexl-ESC-prefix (copy-keymap 'ESC-prefix))
1070 (define-key hexl-mode-map "\e" 'hexl-ESC-prefix)
ae2d451b
RS
1071 (define-key hexl-mode-map "\e\C-a" 'hexl-beginning-of-512b-page)
1072 (define-key hexl-mode-map "\e\C-b" 'hexl-backward-short)
ae2d451b
RS
1073 (define-key hexl-mode-map "\e\C-d" 'hexl-insert-decimal-char)
1074 (define-key hexl-mode-map "\e\C-e" 'hexl-end-of-512b-page)
1075 (define-key hexl-mode-map "\e\C-f" 'hexl-forward-short)
ae2d451b
RS
1076 (define-key hexl-mode-map "\e\C-i" 'undefined)
1077 (define-key hexl-mode-map "\e\C-j" 'undefined)
1078 (define-key hexl-mode-map "\e\C-k" 'undefined)
ae2d451b 1079 (define-key hexl-mode-map "\e\C-o" 'hexl-insert-octal-char)
ae2d451b 1080 (define-key hexl-mode-map "\e\C-q" 'undefined)
ae2d451b 1081 (define-key hexl-mode-map "\e\C-t" 'undefined)
ae2d451b 1082 (define-key hexl-mode-map "\e\C-x" 'hexl-insert-hex-char)
ae2d451b
RS
1083 (define-key hexl-mode-map "\eb" 'hexl-backward-word)
1084 (define-key hexl-mode-map "\ec" 'undefined)
1085 (define-key hexl-mode-map "\ed" 'undefined)
ae2d451b
RS
1086 (define-key hexl-mode-map "\ef" 'hexl-forward-word)
1087 (define-key hexl-mode-map "\eg" 'hexl-goto-hex-address)
ae2d451b
RS
1088 (define-key hexl-mode-map "\ei" 'undefined)
1089 (define-key hexl-mode-map "\ej" 'hexl-goto-address)
1090 (define-key hexl-mode-map "\ek" 'undefined)
1091 (define-key hexl-mode-map "\el" 'undefined)
ae2d451b 1092 (define-key hexl-mode-map "\eq" 'undefined)
ae2d451b
RS
1093 (define-key hexl-mode-map "\es" 'undefined)
1094 (define-key hexl-mode-map "\et" 'undefined)
1095 (define-key hexl-mode-map "\eu" 'undefined)
1096 (define-key hexl-mode-map "\ev" 'hexl-scroll-down)
1097 (define-key hexl-mode-map "\ey" 'undefined)
1098 (define-key hexl-mode-map "\ez" 'undefined)
1099 (define-key hexl-mode-map "\e<" 'hexl-beginning-of-buffer)
1100 (define-key hexl-mode-map "\e>" 'hexl-end-of-buffer)
1101
02aec07b
EZ
1102 (fset 'hexl-C-c-prefix (copy-keymap mode-specific-map))
1103 (define-key hexl-mode-map "\C-c" 'hexl-C-c-prefix)
ae2d451b
RS
1104 (define-key hexl-mode-map "\C-c\C-c" 'hexl-mode-exit)
1105
02aec07b
EZ
1106 (fset 'hexl-C-x-prefix (copy-keymap 'Control-X-prefix))
1107 (define-key hexl-mode-map "\C-x" 'hexl-C-x-prefix)
ae2d451b
RS
1108 (define-key hexl-mode-map "\C-x[" 'hexl-beginning-of-1k-page)
1109 (define-key hexl-mode-map "\C-x]" 'hexl-end-of-1k-page)
1110 (define-key hexl-mode-map "\C-x\C-p" 'undefined)
1111 (define-key hexl-mode-map "\C-x\C-s" 'hexl-save-buffer)
1112 (define-key hexl-mode-map "\C-x\C-t" 'undefined))
a2535589 1113
61dd70aa
DN
1114(easy-menu-define hexl-menu hexl-mode-map "Hexl Mode menu"
1115 `("Hexl"
1116 :help "Hexl-specific Features"
1117
1118 ["Backward short" hexl-backward-short
1119 :help "Move to left a short"]
1120 ["Forward short" hexl-forward-short
1121 :help "Move to right a short"]
1122 ["Backward word" hexl-backward-short
1123 :help "Move to left a word"]
1124 ["Forward word" hexl-forward-short
1125 :help "Move to right a word"]
1126 "-"
1127 ["Beginning of 512b page" hexl-beginning-of-512b-page
1128 :help "Go to beginning of 512 byte boundary"]
1129 ["End of 512b page" hexl-end-of-512b-page
1130 :help "Go to end of 512 byte boundary"]
1131 ["Beginning of 1K page" hexl-beginning-of-1k-page
1132 :help "Go to beginning of 1KB boundary"]
1133 ["End of 1K page" hexl-end-of-1k-page
1134 :help "Go to end of 1KB boundary"]
1135 "-"
1136 ["Go to address" hexl-goto-address
1137 :help "Go to hexl-mode (decimal) address"]
1138 ["Go to address" hexl-goto-hex-address
1139 :help "Go to hexl-mode (hex string) address"]
1140 "-"
1141 ["Insert decimal char" hexl-insert-decimal-char
1142 :help "Insert a character given by its decimal code"]
1143 ["Insert hex char" hexl-insert-hex-char
1144 :help "Insert a character given by its hexadecimal code"]
1145 ["Insert octal char" hexl-insert-octal-char
1146 :help "Insert a character given by its octal code"]
1147 "-"
1148 ["Exit hexl mode" hexl-mode-exit
1149 :help "Exit hexl mode returning to previous mode"]))
1150
19e31f7c
RS
1151(provide 'hexl)
1152
37dc4767 1153;; arch-tag: d5a7aa8a-9bce-480b-bcff-6c4c7ca5ea4a
1a06eabd 1154;;; hexl.el ends here