* Byte swapping and bindat [not found] <87pmjglllc.fsf.ref@yahoo.com> @ 2022-06-10 13:00 ` Po Lu 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor 0 siblings, 1 reply; 10+ messages in thread From: Po Lu @ 2022-06-10 13:00 UTC (permalink / raw) To: help-gnu-emacs I was looking into replacing some of the very complicated Motif binary message parsing code in x-dnd.el with bindat, but there doesn't seem to be a way to make bindat do byte-swapping automatically, which makes it a lot less attractive. Is there a way to specify a bindat type with fields whose endianess depends on an external parameter (or another field of the type?) Defining each type twice for both byte orders seems very ugly. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 13:00 ` Byte swapping and bindat Po Lu @ 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-10 15:53 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Stefan Monnier via Users list for the GNU Emacs text editor @ 2022-06-10 13:32 UTC (permalink / raw) To: help-gnu-emacs > Is there a way to specify a bindat type with fields whose endianess > depends on an external parameter (or another field of the type?) I'm so glad you asked: (let* ((threshold 32) (type (bindat-type (kind uint 8) (length sint 32 (> kind threshold))))) (list (bindat-unpack type "\x10\x00\x00\x01\x01") (bindat-unpack type "\x80\x00\x00\x01\x01"))) => (((kind . 16) (length . 257)) ((kind . 128) (length . 16842752))) That's one of the benefits of the new Bindat :-) Stefan ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor @ 2022-06-10 15:53 ` Eli Zaretskii 2022-06-10 21:42 ` Stefan Monnier 2022-06-10 17:03 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-11 0:54 ` Po Lu 2 siblings, 1 reply; 10+ messages in thread From: Eli Zaretskii @ 2022-06-10 15:53 UTC (permalink / raw) To: help-gnu-emacs > Date: Fri, 10 Jun 2022 09:32:31 -0400 > From: Stefan Monnier via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> > > (let* ((threshold 32) > (type (bindat-type (kind uint 8) > (length sint 32 (> kind threshold))))) > (list (bindat-unpack type "\x10\x00\x00\x01\x01") > (bindat-unpack type "\x80\x00\x00\x01\x01"))) > => > (((kind . 16) (length . 257)) > ((kind . 128) (length . 16842752))) It would be nice to have sint documented in the ELisp manual... ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 15:53 ` Eli Zaretskii @ 2022-06-10 21:42 ` Stefan Monnier 2022-06-11 0:55 ` Po Lu 2022-06-11 5:45 ` Eli Zaretskii 0 siblings, 2 replies; 10+ messages in thread From: Stefan Monnier @ 2022-06-10 21:42 UTC (permalink / raw) To: Eli Zaretskii; +Cc: EMACS development team Eli Zaretskii [2022-06-10 18:53:32] wrote: >> Date: Fri, 10 Jun 2022 09:32:31 -0400 >> From: Stefan Monnier via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> >> >> (let* ((threshold 32) >> (type (bindat-type (kind uint 8) >> (length sint 32 (> kind threshold))))) >> (list (bindat-unpack type "\x10\x00\x00\x01\x01") >> (bindat-unpack type "\x80\x00\x00\x01\x01"))) >> => >> (((kind . 16) (length . 257)) >> ((kind . 128) (length . 16842752))) > > It would be nice to have sint documented in the ELisp manual... Good point. I think it would also be nice to unify `uint` and `uintr`. What about the patch below? Stefan diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 55fb93ec5a8..63570d2117f 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -3470,13 +3470,15 @@ Bindat Types @itemx byte Unsigned byte, with length 1. -@item uint @var{bitlen} -Unsigned integer in network byte order, with @var{bitlen} bits. +@item uint @var{bitlen} &optional @var{le} +Unsigned integer in network byte order (big-endian), with @var{bitlen} bits. @var{bitlen} has to be a multiple of 8. +If @var{le} is non-@code{nil}, then use little-endian. -@item uintr @var{bitlen} -Unsigned integer in little endian order, with @var{bitlen} bits. +@item sint @var{bitlen} @var{le} +Signed integer in network byte order (big-endian), with @var{bitlen} bits. @var{bitlen} has to be a multiple of 8. +If @var{le} is non-@code{nil}, then use little-endian. @item str @var{len} Unibyte string (@pxref{Text Representations}) of length @var{len} bytes. diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el index 5f3c772983a..48ae7c8545b 100644 --- a/lisp/emacs-lisp/bindat.el +++ b/lisp/emacs-lisp/bindat.el @@ -77,7 +77,7 @@ ;; (bindat-type ;; (type u8) ;; (opcode u8) -;; (length uintr 32) ;; little endian order +;; (length uint 32 t) ;; little endian order ;; (id strz 8) ;; (data vec length) ;; (_ align 4))) @@ -663,14 +663,17 @@ bindat--type (`(length . ,_) `(cl-incf bindat-idx 1)) (`(pack . ,args) `(bindat--pack-u8 . ,args)))) -(cl-defmethod bindat--type (op (_ (eql 'uint)) n) +(cl-defmethod bindat--type (op (_ (eql 'uint)) n &optional le) (if (eq n 8) (bindat--type op 'byte) (bindat--pcase op - ('unpack `(bindat--unpack-uint ,n)) + ('unpack + `(if ,le (bindat--unpack-uintr ,n) (bindat--unpack-uint ,n))) (`(length . ,_) `(cl-incf bindat-idx (/ ,n 8))) - (`(pack . ,args) `(bindat--pack-uint ,n . ,args))))) + (`(pack . ,args) + `(if ,le (bindat--pack-uintr ,n . ,args) + (bindat--pack-uint ,n . ,args)))))) -(cl-defmethod bindat--type (op (_ (eql 'uintr)) n) +(cl-defmethod bindat--type (op (_ (eql 'uintr)) n) ;Obsolete since Emacs-29. (if (eq n 8) (bindat--type op 'byte) (bindat--pcase op ('unpack `(bindat--unpack-uintr ,n)) @@ -849,8 +852,7 @@ bindat-type "Return the Bindat type value to pack&unpack TYPE. TYPE is a Bindat type expression. It can take the following forms: - uint BITLEN - Big-endian unsigned integer - uintr BITLEN - Little-endian unsigned integer + uint BITLEN [LE] - unsigned integer (big-endian if LE is nil) str LEN - Byte string strz [LEN] - Zero-terminated byte-string bits LEN - Bit vector (LEN is counted in bytes) @@ -935,9 +937,9 @@ bindat--make-docstring (if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc))))) (bindat-defmacro u8 () "Unsigned 8bit integer." '(byte)) -(bindat-defmacro sint (bitlen r) +(bindat-defmacro sint (bitlen le) "Signed integer of size BITLEN. -Bigendian if R is nil and little endian if not." +Big-endian if LE is nil and little-endian if not." (let ((bl (make-symbol "bitlen")) (max (make-symbol "max")) (wrap (make-symbol "wrap"))) @@ -945,7 +947,7 @@ sint (,max (ash 1 (1- ,bl))) (,wrap (+ ,max ,max))) (struct :pack-var v - (n if ,r (uintr ,bl) (uint ,bl) + (n uint ,bl ,le :pack-val (if (< v 0) (+ v ,wrap) v)) :unpack-val (if (>= n ,max) (- n ,wrap) n))))) diff --git a/test/lisp/emacs-lisp/bindat-tests.el b/test/lisp/emacs-lisp/bindat-tests.el index 48170727525..1ce402977f5 100644 --- a/test/lisp/emacs-lisp/bindat-tests.el +++ b/test/lisp/emacs-lisp/bindat-tests.el @@ -36,7 +36,7 @@ data-bindat-spec (bindat-type (type u8) (opcode u8) - (length uintr 16) ;; little endian order + (length uint 16 'le) ;; little endian order (id strz 8) (data vec length) (_ align 4))) @@ -128,18 +128,17 @@ bindat-test--sint (r (zerop (% kind 2)))) (dotimes (_ 100) (let* ((n (random (ash 1 bitlen))) - (i (- n (ash 1 (1- bitlen))))) + (i (- n (ash 1 (1- bitlen)))) + (stype (bindat-type sint bitlen r)) + (utype (bindat-type if r (uintr bitlen) (uint bitlen)))) (should (equal (bindat-unpack - (bindat-type sint bitlen r) - (bindat-pack (bindat-type sint bitlen r) i)) + stype + (bindat-pack stype i)) i)) (when (>= i 0) - (should (equal (bindat-pack - (bindat-type if r (uintr bitlen) (uint bitlen)) i) - (bindat-pack (bindat-type sint bitlen r) i))) - (should (equal (bindat-unpack - (bindat-type if r (uintr bitlen) (uint bitlen)) - (bindat-pack (bindat-type sint bitlen r) i)) + (should (equal (bindat-pack utype i) + (bindat-pack stype i))) + (should (equal (bindat-unpack utype (bindat-pack stype i)) i)))))))) (defconst bindat-test--LEB128 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 21:42 ` Stefan Monnier @ 2022-06-11 0:55 ` Po Lu 2022-06-11 5:45 ` Eli Zaretskii 1 sibling, 0 replies; 10+ messages in thread From: Po Lu @ 2022-06-11 0:55 UTC (permalink / raw) To: Stefan Monnier; +Cc: Eli Zaretskii, EMACS development team Stefan Monnier <monnier@iro.umontreal.ca> writes: > Good point. I think it would also be nice to unify `uint` and `uintr`. > > What about the patch below? I can't speak as to the code, but the idea and the doc looks great. Thanks! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 21:42 ` Stefan Monnier 2022-06-11 0:55 ` Po Lu @ 2022-06-11 5:45 ` Eli Zaretskii 1 sibling, 0 replies; 10+ messages in thread From: Eli Zaretskii @ 2022-06-11 5:45 UTC (permalink / raw) To: Stefan Monnier; +Cc: emacs-devel > From: Stefan Monnier <monnier@iro.umontreal.ca> > Cc: EMACS development team <emacs-devel@gnu.org> > Date: Fri, 10 Jun 2022 17:42:41 -0400 > > > It would be nice to have sint documented in the ELisp manual... > > Good point. I think it would also be nice to unify `uint` and `uintr`. > > What about the patch below? Thanks. > -@item uint @var{bitlen} > -Unsigned integer in network byte order, with @var{bitlen} bits. > +@item uint @var{bitlen} &optional @var{le} > +Unsigned integer in network byte order (big-endian), with @var{bitlen} bits. > @var{bitlen} has to be a multiple of 8. > +If @var{le} is non-@code{nil}, then use little-endian. ^^^^^^^^^^^^^^^^^ "use little-endian byte order" is more clear. > -@item uintr @var{bitlen} > -Unsigned integer in little endian order, with @var{bitlen} bits. > +@item sint @var{bitlen} @var{le} > +Signed integer in network byte order (big-endian), with @var{bitlen} bits. > @var{bitlen} has to be a multiple of 8. > +If @var{le} is non-@code{nil}, then use little-endian. Same here. > @@ -849,8 +852,7 @@ bindat-type > "Return the Bindat type value to pack&unpack TYPE. > TYPE is a Bindat type expression. It can take the following forms: > > - uint BITLEN - Big-endian unsigned integer > - uintr BITLEN - Little-endian unsigned integer > + uint BITLEN [LE] - unsigned integer (big-endian if LE is nil) > str LEN - Byte string > strz [LEN] - Zero-terminated byte-string > bits LEN - Bit vector (LEN is counted in bytes) Do we want to say in the doc string that uintr is supported for backward compatibility? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-10 15:53 ` Eli Zaretskii @ 2022-06-10 17:03 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-11 0:54 ` Po Lu 2 siblings, 0 replies; 10+ messages in thread From: Stefan Monnier via Users list for the GNU Emacs text editor @ 2022-06-10 17:03 UTC (permalink / raw) To: help-gnu-emacs Stefan Monnier via Users list for the GNU Emacs text editor [2022-06-10 09:32:31] wrote: >> Is there a way to specify a bindat type with fields whose endianess >> depends on an external parameter (or another field of the type?) > > I'm so glad you asked: > > (let* ((threshold 32) > (type (bindat-type (kind uint 8) > (length sint 32 (> kind threshold))))) > (list (bindat-unpack type "\x10\x00\x00\x01\x01") > (bindat-unpack type "\x80\x00\x00\x01\x01"))) > => > (((kind . 16) (length . 257)) > ((kind . 128) (length . 16842752))) > > That's one of the benefits of the new Bindat :-) Oh, and if you want to do that for `uint` (which currently doesn't take a "reverse" argument (patch welcome)), you can do: (let* ((threshold 32) (type (bindat-type (kind uint 8) (length if (> kind threshold) (uintr 32) (uint 32))))) (list (bindat-unpack type "\x10\x00\x00\x01\x01") (bindat-unpack type "\x80\x00\x00\x01\x01"))) => (((kind . 16) (length . 257)) ((kind . 128) (length . 16842752))) -- Stefan ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-10 15:53 ` Eli Zaretskii 2022-06-10 17:03 ` Stefan Monnier via Users list for the GNU Emacs text editor @ 2022-06-11 0:54 ` Po Lu 2022-06-11 1:08 ` Stefan Monnier 2 siblings, 1 reply; 10+ messages in thread From: Po Lu @ 2022-06-11 0:54 UTC (permalink / raw) To: Stefan Monnier via Users list for the GNU Emacs text editor Cc: Stefan Monnier Stefan Monnier via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> writes: >> Is there a way to specify a bindat type with fields whose endianess >> depends on an external parameter (or another field of the type?) > > I'm so glad you asked: > > (let* ((threshold 32) > (type (bindat-type (kind uint 8) > (length sint 32 (> kind threshold))))) > (list (bindat-unpack type "\x10\x00\x00\x01\x01") > (bindat-unpack type "\x80\x00\x00\x01\x01"))) > => > (((kind . 16) (length . 257)) > ((kind . 128) (length . 16842752))) > > That's one of the benefits of the new Bindat :-) Thanks. Where is that documented? (And what about an unsigned integer? Is it just `uint', which according to the doc is a big-endian number?) ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-11 0:54 ` Po Lu @ 2022-06-11 1:08 ` Stefan Monnier 2022-06-11 1:15 ` Po Lu 0 siblings, 1 reply; 10+ messages in thread From: Stefan Monnier @ 2022-06-11 1:08 UTC (permalink / raw) To: Po Lu; +Cc: Stefan Monnier via Users list for the GNU Emacs text editor >> That's one of the benefits of the new Bindat :-) > Thanks. Where is that documented? Not sure what "that" refers to. If you mean "sint" it's documented in `C-h f bindate-type RET`. If you mean the fact that the `r` argument can be an arbitrary ELisp expression, it's not explicitly documented, because it holds for basically every part of `bindate-type` specs. > (And what about an unsigned integer? Is it just `uint', which according > to the doc is a big-endian number?) I assume you've now seen my other post which answers this question. Stefan ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Byte swapping and bindat 2022-06-11 1:08 ` Stefan Monnier @ 2022-06-11 1:15 ` Po Lu 0 siblings, 0 replies; 10+ messages in thread From: Po Lu @ 2022-06-11 1:15 UTC (permalink / raw) To: Stefan Monnier Cc: Stefan Monnier via Users list for the GNU Emacs text editor Stefan Monnier <monnier@iro.umontreal.ca> writes: > Not sure what "that" refers to. > If you mean "sint" it's documented in `C-h f bindate-type RET`. Hmm, I must've missed that. > I assume you've now seen my other post which answers this question. Yes, thanks. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2022-06-11 5:45 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <87pmjglllc.fsf.ref@yahoo.com> 2022-06-10 13:00 ` Byte swapping and bindat Po Lu 2022-06-10 13:32 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-10 15:53 ` Eli Zaretskii 2022-06-10 21:42 ` Stefan Monnier 2022-06-11 0:55 ` Po Lu 2022-06-11 5:45 ` Eli Zaretskii 2022-06-10 17:03 ` Stefan Monnier via Users list for the GNU Emacs text editor 2022-06-11 0:54 ` Po Lu 2022-06-11 1:08 ` Stefan Monnier 2022-06-11 1:15 ` Po Lu
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.