Compare commits

..

1 Enmetoj

Author SHA1 Message Date
Jaidyn Ann 00adb56e40 Update source URL & e-mail address 2024-01-29 14:37:54 -06:00
5 changed files with 167 additions and 213 deletions

View File

@ -1,20 +0,0 @@
LISP ?= sbcl
all: clean build
clean:
-rm eksd
quicklisp:
curl "https://beta.quicklisp.org/quicklisp.lisp" -o /tmp/ql.lisp
$(LISP) --load /tmp/ql.lisp \
--eval '(quicklisp-quickstart:install :path "~/.local/lib/quicklisp/")' \
--eval '(ql:add-to-init-file)' \
--eval '(quit)'
build:
$(LISP) --load eksd.asd \
--eval '(ql:quickload :eksd)' \
--eval '(ql:quickload :eksd.unix)' \
--eval '(asdf:make :eksd.unix)' \
--eval '(quit)'

View File

@ -1,9 +1,9 @@
# EKSD # EKSD
[xxd](https://hg.256bit.org/vim/file/tip/src/xxd) is a very good hexdump program that makes editing files on UNIX very easy. xxd is a very good hexdump program that makes editing files on UNIX very easy.
It also doesn't support text-tables. Which sucks. It also doesn't support text-tables. Which sucks.
[eksd](https://hak.xwx.moe/jadedctrl/eksd) is a clone of a good hexdump program (even matching several arguments eksd is a clone of a good hexdump program (even matching several arguments
exactly)… except it supports text-tables. exactly)… except it supports text-tables.
## Usage ## Usage
@ -23,7 +23,7 @@ $ eksd -t $TABLE_FILE $FILE > $HEXDUMP_FILE
``` ```
Text-tables are in a simple format— one hexcode per line, followed by its Text-tables are in a simple format— one hexcode per line, followed by its
character. See [./text_tables/*](text_tables/) for examples. character. See ./text-tables/* for examples.
By default, eksd uses a built-in *fancy* text-table— it's basic ASCII, By default, eksd uses a built-in *fancy* text-table— it's basic ASCII,
except it'll print nice pictographics for newline characters, etc. These except it'll print nice pictographics for newline characters, etc. These
@ -42,7 +42,7 @@ $ eksd -t castle-table.txt castlevania.nes | grep -A4 "18e80"
00018eb0: 5454 5454 5454 6668 6086 6e54 5454 5454 ......DEATH..... 00018eb0: 5454 5454 5454 6668 6086 6e54 5454 5454 ......DEATH.....
00018ec0: 5454 5462 6876 7c54 7688 6c7c 8470 5454 ...BELO.LUGOSI.. 00018ec0: 5454 5462 6876 7c54 7688 6c7c 8470 5454 ...BELO.LUGOSI..
``` ```
And here's that same file in [Vims](https://www.vim.org) xxd (just because I feel like showing off): And here's that same file in xxd (just because I feel like showing off):
``` ```
$ xxd castlevania.nes | grep -A4 "18e80" $ xxd castlevania.nes | grep -A4 "18e80"
00018e80: 5454 5454 866e 6854 6460 8486 5454 5454 TTTT.nhTd`..TTTT 00018e80: 5454 5454 866e 6854 6460 8486 5454 5454 TTTT.nhTd`..TTTT
@ -54,19 +54,17 @@ $ xxd castlevania.nes | grep -A4 "18e80"
## Installation ## Installation
Making a binary requires [an implementation](https://common-lisp.net/implementations) of Common Lisp installed: [Steel Bank Common Lisp](https://sbcl.org/) is our implementation-of-choice. Its available on most operating systems under the package name `sbcl`. Making a binary requires a Lisp (I recommend SBCL) and Quicklisp
(https://quicklisp.org).
You also need the library-manager [Quicklisp](https://quicklisp.org), which can [be installed](https://www.quicklisp.org/beta/#installation) quite easily, including via our [Makefile](Makefile).
To install quicklisp, build a binary, and install it, simply:
Put this repository into your `quicklisp/local-projects/`, then run, in your
lisp interpreter:
``` ```
$ make quicklisp # (ql:quickload '(eksd eksd-unix))
$ make build # (save-lisp-and-die "eksd" :toplevel #'eksd-unix:invoke :executable t)
$ sudo cp eksd /usr/local/bin/eksd
``` ```
Bam, you've made and installed a binary! Cool! And bam, you've made a binary. Cool.
## Misc ## Misc

View File

@ -1,29 +1,21 @@
;;;; eksd.unix: UNIX-style cli interface for the xxd-clone eksd. ;; This file is free software: you can redistribute it and/or modify
;; it under the terms of version 3 of the GNU General Public License
;; Copyright © 20192024 Jaidyn Ann <jadedctrl@posteo.at> ;; as published by the Free Software Foundation.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of
;; the License, or (at your option) any later version.
;; ;;
;; This program is distributed in the hope that it will be useful, ;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details. ;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(defpackage :eksd.unix (defpackage :eksd-unix
(:use :cl :eksd) (:use :cl :eksd)
(:export :main (:export :invoke
*text-table*)) *text-table*))
(in-package :eksd.unix) (in-package :eksd-unix)
;; —————————————————————————————————————
;;; —————————————————————————————————————
(opts:define-opts (opts:define-opts
(:name :help (:name :help
:description "print this help text." :description "print this help text."
@ -59,25 +51,25 @@
:meta-var "TABLE")) :meta-var "TABLE"))
;; —————————————————————————————————————
;;; Macros ;; MACROS
;;; —————————————————————————————————————
;; list symbol form ;; LIST SYMBOL FORM
(defmacro when-opt (opts option body) (defmacro when-opt (opts option body)
`(when (getf ,opts ,option) `(when (getf ,opts ,option)
,body)) ,body))
;; list symbol form form ;; LIST SYMBOL FORM FORM
(defmacro if-opt (opts option if-form &optional else-form) (defmacro if-opt (opts option if-form &optional else-form)
`(if (getf ,opts ,option) `(if (getf ,opts ,option)
,if-form ,else-form)) ,if-form ,else-form))
;; —————————————————————————————————————
;;; Main - Invocation ;; MAIN - INVOCATION
;;; —————————————————————————————————————
;; nil → nil ;; NIL → NIL
(defun main () (defun invoke ()
"Actual invocation of the program. This is what you should set as :toplevel." "Actual invocation of the program. This is what you should set as :toplevel."
(multiple-value-bind (opts free) (opts:get-opts) (multiple-value-bind (opts free) (opts:get-opts)
(when-opt opts :help (help)) (when-opt opts :help (help))
@ -93,14 +85,17 @@
(close input-stream)))) (close input-stream))))
;; number stream → nil
;; NUMBER STREAM → NIL
(defun help (&optional (exit-code 0) (stream *standard-output*)) (defun help (&optional (exit-code 0) (stream *standard-output*))
"Prints help message and dies." "Prints help message and dies."
(unix-opts:describe :prefix "usage: eksd [-hr] [-t table-file] file" (unix-opts:describe :prefix "usage: eksd [-hr] [-t table-file] file"
:stream stream) :stream stream)
(unix-opts:exit exit-code)) (unix-opts:exit exit-code))
; list stream → nil ;; —————————————————
;; LIST STREAM → NIL
(defun reverse-or-dump (opts input-stream) (defun reverse-or-dump (opts input-stream)
"Determine if a hexdump or reversal's necessary— and execute it." "Determine if a hexdump or reversal's necessary— and execute it."
(if-opt opts :reverse (if-opt opts :reverse
@ -108,21 +103,21 @@
(apply #'print-stream (choose-pstream-args opts input-stream)))) (apply #'print-stream (choose-pstream-args opts input-stream))))
;; —————————————————————————————————————
;;; Input ;; INPUT
;;; —————————————————————————————————————
;; list → stream ;; LIST → STREAM
(defun choose-input-stream (free-args opts) (defun choose-input-stream (free-args opts)
"Select an input stream, between a file passed in free-args or stdin." "Select an input stream, between a file passed in free-args or stdin."
(let* ((input-file (car free-args)) (let* ((input-file (car free-args))
(input-file-p (ignore-errors (probe-file input-file))) (input-file-p (ignore-errors (probe-file input-file)))
(stdin-p (listen *standard-input*))) (stdin-p (listen *standard-input*)))
(cond ((and (getf opts :reverse) input-file-p (cond ((and (getf opts :reverse) input-file-p)
(open input-file :direction :input :element-type 'character))) (open input-file :direction :input :element-type 'character))
(input-file-p (open-byte input-file)) (input-file-p (open-byte input-file))
(stdin-p *standard-input*)))) (stdin-p *standard-input*))))
;; list → nil ;; LIST → NIL
(defun choose-text-table (opts) (defun choose-text-table (opts)
"Choose the appropriate text-table— user-given or otherwise." "Choose the appropriate text-table— user-given or otherwise."
(if-opt opts :text-table (if-opt opts :text-table
@ -131,13 +126,13 @@
(setq *text-table* eksd:*ascii-text-table*) (setq *text-table* eksd:*ascii-text-table*)
(setq *text-table* eksd:*fancy-text-table*)))) (setq *text-table* eksd:*fancy-text-table*))))
;; list stream → nil ;; LIST STREAM → NIL
(defun choose-stream-position (opts stream) (defun choose-stream-position (opts stream)
"Choose the correct stream position— if seek arg used, etc." "Choose the correct stream position— if seek arg used, etc."
(when (not (eq stream *standard-input*)) (when (not (eq stream *standard-input*))
(if-opt opts :seek (file-position stream (getf opts :seek))))) (if-opt opts :seek (file-position stream (getf opts :seek)))))
;; list stream → list ;; LIST STREAM → LIST
(defun choose-pstream-args (opts input-stream) (defun choose-pstream-args (opts input-stream)
"Take all options, and return the appropriate arguments to #'print-stream." "Take all options, and return the appropriate arguments to #'print-stream."
(let ((args (list input-stream))) (let ((args (list input-stream)))
@ -146,10 +141,9 @@
(when-opt opts :group (nconc args `(:group ,(getf opts :group)))) (when-opt opts :group (nconc args `(:group ,(getf opts :group))))
args)) args))
;; —————————————————
;;; —————————————————
;; stream number number → list number ;; STREAM NUMBER NUMBER → LIST NUMBER
(defun get-line-hex (stream index width) (defun get-line-hex (stream index width)
"Return a line's worth of octets; and a new octet-index." "Return a line's worth of octets; and a new octet-index."
(values (values
@ -158,10 +152,10 @@
index)) index))
;; Output
;; ————————————————————————————————————— ;; —————————————————————————————————————
;; stream number number stream ;; OUTPUT
;; STREAM NUMBER NUMBER STREAM
(defun print-stream (stream &key (width 16) (group 2) (upcase nil) (out 't)) (defun print-stream (stream &key (width 16) (group 2) (upcase nil) (out 't))
"Print an entire stream in hex, xxd-style." "Print an entire stream in hex, xxd-style."
(let ((index 0)) (let ((index 0))
@ -170,7 +164,8 @@
:group group :width width :group group :width width
:upcase upcase))))) :upcase upcase)))))
;; stream stream number number number → number
;; STREAM STREAM NUMBER NUMBER NUMBER → NUMBER
(defun print-line (stream &key (out 't) (index 0) (width 16) (group 2) (defun print-line (stream &key (out 't) (index 0) (width 16) (group 2)
(upcase nil)) (upcase nil))
"Print a given line of xxd-style output index, bytes, preview and all. "Print a given line of xxd-style output index, bytes, preview and all.
@ -182,29 +177,29 @@
(format t "~%") (format t "~%")
new-index)) new-index))
;; number stream → nil ;; NUMBER STREAM → NIL
(defun print-index (index &optional (out 't)) (defun print-index (index &optional (out 't))
"Print the current index, padded to 8 char-length and in hexadecimal." "Print the current index, padded to 8 char-length and in hexadecimal."
(format out "~8,,,'0@A: " (string-downcase (eksd:integer-to-hex index)))) (format out "~8,,,'0@A: " (string-downcase (eksd:integer-to-hex index))))
;; list-of-strings number stream → nil ;; LIST_OF_STRINGS NUMBER STREAM → NIL
(defun print-bytes (hexes group-size upcase &optional (out 't)) (defun print-bytes (hexes group-size upcase &optional (out 't))
"Print the given list of bytes on a line in specified-sized groupings." "Print the given list of bytes on a line in specified-sized groupings."
(mapcar (lambda (group) (mapcar (lambda (group)
(format out (if upcase "~{~@:(~a~)~} " "~{~(~a~)~} ") group)) (format out (if upcase "~{~@:(~a~)~} " "~{~(~a~)~} ") group))
(pairs hexes group-size))) (pairs hexes group-size)))
;; list-of-strings stream → nil ;; LIST_OF_STRINGS STREAM → NIL
(defun print-preview (hexes &optional (out 't)) (defun print-preview (hexes &optional (out 't))
"Print a given list of bytes' preview, as per ASCII table." "Print a given list of bytes' preview, as per ASCII table."
(format out " ~{~A~}" (format out " ~{~A~}"
(mapcar (lambda (hex) (hex-to-char hex *text-table*)) hexes))) (mapcar (lambda (hex) (hex-to-char hex *text-table*)) hexes)))
;; —————————————————————————————————————
;;; Reversal ;; REVERSAL
;;; —————————————————————————————————————
;; stream stream → nil ;; STREAM STREAM → NIL
(defun reverse-stream (stream &optional (out *standard-output*)) (defun reverse-stream (stream &optional (out *standard-output*))
"Take a stream of xxd-style/eksd-output hexcode and convert back into binary." "Take a stream of xxd-style/eksd-output hexcode and convert back into binary."
(loop :while (listen stream) (loop :while (listen stream)
@ -212,7 +207,7 @@
(write-byte (eksd:hex-to-integer byte) out)) (write-byte (eksd:hex-to-integer byte) out))
(line-to-hexes (read-line stream))))) (line-to-hexes (read-line stream)))))
;; string → list ;; STRING → LIST
(defun line-to-hexes (line) (defun line-to-hexes (line)
"Convert an xxd-style/eksd-output hexcode line into a list of hexcodes." "Convert an xxd-style/eksd-output hexcode line into a list of hexcodes."
(mapcar (lambda (pair) (format nil "~{~A~}" pair)) (mapcar (lambda (pair) (format nil "~{~A~}" pair))
@ -221,17 +216,17 @@
(left-clip-string line ": ")" ")))))) (left-clip-string line ": ")" "))))))
;; —————————————————————————————————————
;;; Text-tables ;; TEXT-TABLES
;;; —————————————————————————————————————
;; string → list ;; STRING → LIST
(defun parse-table-line (string) (defun parse-table-line (string)
"Parse a text-table line into a pair of hex-code and preview character." "Parse a text-table line into a pair of hex-code and preview character."
(let ((chars (char-list string))) (let ((chars (char-list string)))
(list (format nil "~{~a~}" (list (car chars) (cadr chars))) (list (format nil "~{~a~}" (list (car chars) (cadr chars)))
(tail chars)))) (tail chars))))
;; pathname → list ;; PATHNAME → LIST
(defun parse-table-file (pathname) (defun parse-table-file (pathname)
"Parse a text-table file (hexcode followed by preview character) into a list "Parse a text-table file (hexcode followed by preview character) into a list
of lists '(hexcode character)." of lists '(hexcode character)."
@ -240,17 +235,17 @@
:collect (parse-table-line (read-line istream))))) :collect (parse-table-line (read-line istream)))))
;; —————————————————————————————————————
;;; Misc ;; MISC
;;; —————————————————————————————————————
;; list number varying → list ;; LIST NUMBER VARYING → LIST
(defun list-pad (list target-length &optional (padding nil)) (defun list-pad (list target-length &optional (padding nil))
"Pad a list out to length, by appending padding as necessary." "Pad a list out to length, by appending padding as necessary."
(if (not (eq target-length (length list))) (if (not (eq target-length (length list)))
(list-pad (append list (list padding)) target-length padding) (list-pad (append list (list padding)) target-length padding)
list)) list))
;; list number → list ;; LIST NUMBER → LIST
(defun pairs (list width &optional pairs) (defun pairs (list width &optional pairs)
"Split a list into pairs (sublist) of a given width." "Split a list into pairs (sublist) of a given width."
(cond ((not list) pairs) (cond ((not list) pairs)
@ -260,29 +255,24 @@
(pairs (cdr list) width (pairs (cdr list) width
(nconc (de-tail pairs) `(,(nconc (tail pairs) `(,(car list))))))))) (nconc (de-tail pairs) `(,(nconc (tail pairs) `(,(car list)))))))))
;; string character → string ;; STRING CHARACTER → STRING
(defun left-clip-string (string &optional (seperator #\space)) (defun left-clip-string (string &optional (seperator #\space))
"Clip a string up to the first instance of the seperator." "Clip a string up to the first instance of the seperator."
(reduce (lambda (a b) (format nil "~A~A~A" a seperator b)) (reduce (lambda (a b) (format nil "~A~A~A" a seperator b))
(cdr (cl-strings:split string seperator)))) (cdr (cl-strings:split string seperator))))
;; string number → list ;; STRING NUMBER → LIST
(defun string-pairs (string &optional (pair-length 2)) (defun string-pairs (string &optional (pair-length 2))
"Return a list of characters from a string in pairs of given length." "Return a list of characters from a string in pairs of given length."
(pairs (char-list string) pair-length)) (pairs (char-list string) pair-length))
;; pathname → stream ;; PATHNAME → STREAM
(defun open-byte (pathname) (defun open-byte (pathname)
"Open an input file as a byte-stream." "Open an input file as a byte-stream."
(open pathname :direction :input :element-type '(unsigned-byte 8))) (open pathname :direction :input :element-type '(unsigned-byte 8)))
;; string → list ;; —————————————————
(defun char-list (string)
"Convert a string into a list of characters."
(loop :for char :across string :collect char))
;; list → list
(defun de-tail (list)
"Remove the last element from a list."
(reverse (cdr (reverse list))))
(defun char-list (string) (loop :for char :across string :collect char))
(defun de-tail (list) (reverse (cdr (reverse list))))
(defun tail (list) (car (last list)))

22
eksd.asd Normal file → Executable file
View File

@ -1,23 +1,15 @@
(require "asdf") (defsystem "eksd"
:version "0.1"
(asdf:defsystem "eksd"
:version "0.11"
:license "GPLv3" :license "GPLv3"
:author "Jaidyn Ann <jadedctrl@posteo.at>" :author "Jaidyn Ann <jadedctrl@posteo.at>"
:homepage "https://hak.xwx.moe/jadedctrl/eksd"
:description "For reading files into hex— `xxd`-like with text-tables." :description "For reading files into hex— `xxd`-like with text-tables."
:depends-on () :depends-on ()
:components ((:file "src/eksd"))) :components ((:file "eksd")))
(asdf:defsystem "eksd.unix" (defsystem "eksd-unix"
:version "0.11" :version "0.1"
:license "GPLv3" :license "GPLv3"
:author "Jaidyn Ann <jadedctrl@posteo.at>" :author "Jaidyn Ann <jadedctrl@posteo.at>"
:homepage "https://hak.xwx.moe/jadedctrl/eksd"
:description "UNIX terminal front-tend to eksd. `xxd` twin." :description "UNIX terminal front-tend to eksd. `xxd` twin."
:class asdf:program-system :depends-on (:eksd :unix-opts :cl-strings)
:build-operation "program-op" :components ((:file "eksd-unix")))
:build-pathname "eksd"
:entry-point "eksd.unix:main"
:depends-on (:cl-strings :eksd :unix-opts)
:components ((:file "src/unix")))

View File

@ -1,19 +1,11 @@
;;;; eksd: Backend to the xxd-clone hex-dump program eksd. ;; This file is free software: you can redistribute it and/or modify
;; it under the terms of version 3 of the GNU General Public License
;; Copyright © 20192024 Jaidyn Ann <jadedctrl@posteo.at> ;; as published by the Free Software Foundation.
;;
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of
;; the License, or (at your option) any later version.
;; ;;
;; This program is distributed in the hope that it will be useful, ;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details. ;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(defpackage :eksd (defpackage :eksd
(:use :cl) (:use :cl)
@ -30,9 +22,8 @@
(in-package :eksd) (in-package :eksd)
;; —————————————————————————————————————
;;; Constants
;;; —————————————————————————————————————
(defparameter *ascii-text-table* (defparameter *ascii-text-table*
'(("20" #\space)("21" #\!)("22" #\")("23" #\#)("24" #\$) ("25" #\%) '(("20" #\space)("21" #\!)("22" #\")("23" #\#)("24" #\$) ("25" #\%)
("26" #\&) ("27" #\') ("28" #\() ("29" #\)) ("2A" #\*) ("2B" #\+) ("26" #\&) ("27" #\') ("28" #\() ("29" #\)) ("2A" #\*) ("2B" #\+)
@ -56,16 +47,16 @@
(defparameter *fancy-text-table* (append *ascii-text-table* *fancy-text-bits*)) (defparameter *fancy-text-table* (append *ascii-text-table* *fancy-text-bits*))
;; —————————————————————————————————————
;;; X → Hex ;; X → HEX
;;; —————————————————————————————————————
;; stream → list-of-strings ;; STREAM → LIST_OF_STRINGS
(defun stream-to-hex (stream) (defun stream-to-hex (stream)
"Return a stream's data as a list of hexadecimal strings." "Return a stream's data as a list of hexadecimal strings."
(loop :while (listen stream) (loop :while (listen stream)
:collect (read-hex stream))) :collect (read-hex stream)))
;; pathname → list-of-strings ;; PATHNAME → LIST_OF_STRINGS
(defun file-to-hex (pathname) (defun file-to-hex (pathname)
"Return a list of a file's octets represented in hexadecimal strings." "Return a list of a file's octets represented in hexadecimal strings."
(with-open-file (fstream pathname (with-open-file (fstream pathname
@ -73,16 +64,17 @@
(stream-to-hex fstream))) (stream-to-hex fstream)))
;;; Hex → X ;; —————————————————————————————————————
;;; ————————————————————————————————————— ;; HEX → X
;; list-of-strings stream → nil
;; LIST_OF_STRINGS STREAM → NIL
(defun hex-to-stream (hexes stream) (defun hex-to-stream (hexes stream)
"Write a list of bytes (in hex-string format) to a stream." "Write a list of bytes (in hex-string format) to a stream."
(loop :for hex :in hexes (loop :for hex :in hexes
:do (write-hex hex stream))) :do (write-hex hex stream)))
;; list-of-strings pathname → nil ;; LIST_OF_STRINGS PATHNAME → NIL
(defun hex-to-file (hexes pathname) (defun hex-to-file (hexes pathname)
"Write a list of bytes (in hex-string format) to a file." "Write a list of bytes (in hex-string format) to a file."
(with-open-file (fstream pathname (with-open-file (fstream pathname
@ -90,60 +82,62 @@
(hex-to-stream hexes fstream))) (hex-to-stream hexes fstream)))
;; Text-table fun
;; ————————————————————————————————————— ;; —————————————————————————————————————
;; TEXT-TABLE FUN
(defgeneric hex-to-char (hex/es &optional text-table) (defgeneric hex-to-char (hex/es &optional text-table)
(:documentation "Return a hexadecimal's respective character (as string) (:documentation "Return a hexadecimal's respective character (as string)
according to the given text-table.")) according to the given text-table."))
;; string list → string ;; STRING LIST → STRING
(defmethod hex-to-char ((hex string) &optional (text-table *ascii-text-table*)) (defmethod hex-to-char ((hex string) &optional (text-table *ascii-text-table*))
(or (cadr (assoc hex text-table :test #'equal)) #\.)) (or (cadr (assoc hex text-table :test #'equal)) #\.))
;; list-of-strings list → list-of-strings ;; LIST_OF_STRINGS LIST → LIST_OF_STRINGS
(defmethod hex-to-char ((hexes list) &optional (text-table *ascii-text-table*)) (defmethod hex-to-char ((hexes list) &optional (text-table *ascii-text-table*))
(mapcar (lambda (hex) (hex-to-char hex text-table)) hexes)) (mapcar (lambda (hex) (hex-to-char hex text-table)) hexes))
;; pathname list → list_of_strings ;; PATHNAME LIST → LIST_OF_STRINGS
(defun file-to-char (pathname &optional (text-table *ascii-text-table*)) (defun file-to-char (pathname &optional (text-table *ascii-text-table*))
"Print character representation of a file, as per the given character table." "Print character representation of a file, as per the given character table."
(hex-to-char (file-to-hex pathname) text-table)) (hex-to-char (file-to-hex pathname) text-table))
;; character list → string
;; CHARACTER LIST → STRING
(defun char-hex (char &optional text-table) (defun char-hex (char &optional text-table)
"Return a character's hex, given a text-table." "Return a character's hex, given a text-table."
(if (not text-table) (if (not text-table)
(integer-to-hex (char-code char)) (integer-to-hex (char-code char))
(cadr (assoc char (mapcar #'reverse text-table))))) (cadr (assoc char (mapcar #'reverse text-table)))))
;; string list → list
(defun string-hex (string &optional text-table) (defun string-hex (string &optional text-table)
"Given a string and text-table, return a list of its characters hex-codes."
(loop :for char :across string (loop :for char :across string
:collect (char-hex char text-table))) :collect (char-hex char text-table)))
;;; Misc ;; —————————————————————————————————————
;;; ————————————————————————————————————— ;; MISC
;; stream → string
;; STREAM → STRING
(defun read-hex (stream) (defun read-hex (stream)
"Read a byte from a stream as a hexcode." "Read a byte from a stream as a hexcode."
(integer-to-hex (read-byte stream))) (integer-to-hex (read-byte stream)))
;; stream → string ;; STREAM → STRING
(defun write-hex (hex stream) (defun write-hex (hex stream)
"Read a byte from a stream as a hexcode." "Read a byte from a stream as a hexcode."
(write-byte (hex-to-integer hex) stream)) (write-byte (hex-to-integer hex) stream))
;; number → string
;; NUMBER → STRING
(defun integer-to-hex (number) (defun integer-to-hex (number)
"Return the base-16 of a number." "Return the base-16 of a number."
(format nil "~2,'0x" number)) (format nil "~2,'0x" number))
;; string → number ;; STRING → NUMBER
(defun hex-to-integer (hex) (defun hex-to-integer (hex)
"Convert hex to a base-10 integer." "Convert hex to a base-10 integer."
(parse-integer hex :radix 16)) (parse-integer hex :radix 16))