(Minor Mode Conventions): Use custom-set-minor-mode.
[bpt/emacs.git] / lispref / processes.texi
index 07a7288..d63ddc4 100644 (file)
@@ -1,7 +1,7 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Emacs Lisp Reference Manual.
-@c Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2005
-@c   Free Software Foundation, Inc.
+@c Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2002, 2003,
+@c   2004, 2005 Free Software Foundation, Inc.
 @c See the file elisp.texi for copying conditions.
 @setfilename ../info/processes
 @node Processes, Display, Abbrevs, Top
@@ -52,6 +52,8 @@ This function returns @code{t} if @var{object} is a process,
 * Datagrams::                UDP network connections.
 * Low-Level Network::        Lower-level but more general function
                                to create connections and servers.
+* Misc Network::             Additional relevant functions for network connections.
+* Byte Packing::             Using bindat to pack and unpack binary data.
 @end menu
 
 @node Subprocess Creation
@@ -168,7 +170,7 @@ function.
 (shell-quote-argument "foo > bar")
      @result{} "foo\\ \\>\\ bar"
 
-;; @r{This example shows the behavior on MS-DOS and MS-Windows systems.}
+;; @r{This example shows the behavior on MS-DOS and MS-Windows.}
 (shell-quote-argument "foo > bar")
      @result{} "\"foo > bar\""
 @end example
@@ -766,9 +768,9 @@ specify the process to send input to, and the input data to send.  The
 data appears on the ``standard input'' of the subprocess.
 
   Some operating systems have limited space for buffered input in a
-@acronym{PTY}.  On these systems, Emacs sends an @acronym{EOF} periodically amidst
-the other characters, to force them through.  For most programs,
-these @acronym{EOF}s do no harm.
+@acronym{PTY}.  On these systems, Emacs sends an @acronym{EOF}
+periodically amidst the other characters, to force them through.  For
+most programs, these @acronym{EOF}s do no harm.
 
   Subprocess input is normally encoded using a coding system before the
 subprocess receives it, much like text written into a file.  You can use
@@ -972,7 +974,7 @@ primitive that waits.
 @defvar process-adaptive-read-buffering
 On some systems, when Emacs reads the output from a subprocess, the
 output data is read in very small blocks, potentially resulting in
-very poor performance.  This behaviour can be remedied to some extent
+very poor performance.  This behavior can be remedied to some extent
 by setting the variable @var{process-adaptive-read-buffering} to a
 non-@code{nil} value (the default), as it will automatically delay reading
 from such processes, thus allowing them to produce more output before
@@ -1094,9 +1096,10 @@ then free to do whatever it chooses with the output.
 
   Quitting is normally inhibited within a filter function---otherwise,
 the effect of typing @kbd{C-g} at command level or to quit a user
-command would be unpredictable.  If you want to permit quitting inside a
-filter function, bind @code{inhibit-quit} to @code{nil}.
-@xref{Quitting}.
+command would be unpredictable.  If you want to permit quitting inside
+a filter function, bind @code{inhibit-quit} to @code{nil}.  In most
+cases, the right way to do this is with the macro
+@code{with-local-quit}.  @xref{Quitting}.
 
   If an error happens during execution of a filter function, it is
 caught automatically, so that it doesn't stop the execution of whatever
@@ -1373,16 +1376,22 @@ quick succession, can call the sentinel just once.  However, process
 termination will always run the sentinel exactly once.  This is
 because the process status can't change again after termination.
 
-  Quitting is normally inhibited within a sentinel---otherwise, the
-effect of typing @kbd{C-g} at command level or to quit a user command
-would be unpredictable.  If you want to permit quitting inside a
-sentinel, bind @code{inhibit-quit} to @code{nil}.  @xref{Quitting}.
+  Emacs explicitly checks for output from the process before running
+the process sentinel.  Once the sentinel runs due to process
+termination, no further output can arrive from the process.
 
   A sentinel that writes the output into the buffer of the process
 should check whether the buffer is still alive.  If it tries to insert
 into a dead buffer, it will get an error.  If the buffer is dead,
 @code{(buffer-name (process-buffer @var{process}))} returns @code{nil}.
 
+  Quitting is normally inhibited within a sentinel---otherwise, the
+effect of typing @kbd{C-g} at command level or to quit a user command
+would be unpredictable.  If you want to permit quitting inside a
+sentinel, bind @code{inhibit-quit} to @code{nil}.  In most cases, the
+right way to do this is with the macro @code{with-local-quit}.
+@xref{Quitting}.
+
   If an error happens during execution of a sentinel, it is caught
 automatically, so that it doesn't stop the execution of whatever
 programs was running when the sentinel was started.  However, if
@@ -1559,7 +1568,7 @@ back to listening for more connection requests.
 keyword/argument pairs, for example @code{:server t} to create a
 server process, or @code{:type 'datagram} to create a datagram
 connection.  @xref{Low-Level Network}, for details.  You can also use
-the @code{open-network-stream} function descibed below.
+the @code{open-network-stream} function described below.
 
   You can distinguish process objects representing network connections
 and servers from those representing subprocesses with the
@@ -1574,7 +1583,7 @@ subprocess.  @xref{Process Information}.
 process, being stopped means not accepting new connections.  (Up to 5
 connection requests will be queued for when you resume the server; you
 can increase this limit, unless it is imposed by the operating
-systems.)  For a network stream connection, being stopped means not
+system.)  For a network stream connection, being stopped means not
 processing input (any arriving input waits until you resume the
 connection).  For a datagram connection, some number of packets may be
 queued but input may be lost.  You can use the function
@@ -1715,6 +1724,20 @@ sets its remote peer address to @var{address}.
 @node Low-Level Network
 @section Low-Level Network Access
 
+  You can also create network connections by operating at a lower
+level that that of @code{open-network-stream}, using
+@code{make-network-process}.
+
+@menu
+* Make Network::             Using @code{make-network-process}.
+* Network Options::          Further control over network connections.
+* Network Feature Testing::  Determining which network features work on
+                               the machine you are using.
+@end menu
+
+@node Make Network
+@subsection @code{make-network-process}
+
    The basic function for creating network connections and network
 servers is @code{make-network-process}.  It can do either of those
 jobs, depending on the arguments you give it.
@@ -1823,7 +1846,8 @@ If you don't specify this keyword at all, the default
 is to determine the coding systems from the data.
 
 @item :noquery @var{query-flag}
-Initialize the process query flag to @var{query-flag}.  @xref{Query Before Exit}.
+Initialize the process query flag to @var{query-flag}.
+@xref{Query Before Exit}.
 
 @item :filter @var{filter}
 Initialize the process filter to @var{filter}.
@@ -1850,14 +1874,21 @@ happened.
 Initialize the process plist to @var{plist}.
 @end table
 
-The following network options can be specified for the network
-process.  Except for @code{:reuseaddr}, you can set or modify these
-options later using @code{set-network-process-option}.
+The original argument list, modified with the actual connection
+information, is available via the @code{process-contact} function.
+@end defun
+
+@node Network Options
+@subsection Network Options
 
-For a server process, the options specified with
+  The following network options can be specified when you create a
+network process.  Except for @code{:reuseaddr}, you can also set or
+modify these options later, using @code{set-network-process-option}.
+
+  For a server process, the options specified with
 @code{make-network-process} are not inherited by the client
 connections, so you will need to set the necessary options for each
-child connection as they are created.
+child connection as it is created.
 
 @table @asis
 @item :bindtodevice @var{device-name}
@@ -1912,13 +1943,8 @@ listening on that port.  If @var{reuseaddr-flag} is @code{nil}, there
 may be a period of time after the last use of that port (by any
 process on the host), where it is not possible to make a new server on
 that port.
-
 @end table
 
-The original argument list, modified with the actual connection
-information, is available via the @code{process-contact} function.
-@end defun
-
 @defun set-network-process-option process option value
 This function sets or modifies a network option for network process
 @var{process}.  See @code{make-network-process} for details of options
@@ -1928,6 +1954,64 @@ The current setting of an option is available via the
 @code{process-contact} function.
 @end defun
 
+@node Network Feature Testing
+@subsection Testing Availability of Network Features
+
+  To test for the availability of a given network feature, use
+@code{featurep} like this:
+
+@example
+(featurep 'make-network-process '(@var{keyword} @var{value}))
+@end example
+
+@noindent
+The result of the first form is @code{t} if it works to specify
+@var{keyword} with value @var{value} in @code{make-network-process}.
+The result of the second form is @code{t} if @var{keyword} is
+supported by @code{make-network-process}.  Here are some of the
+@var{keyword}---@var{value} pairs you can test in
+this way.
+
+@table @code
+@item (:nowait t)
+Non-@code{nil} if non-blocking connect is supported.
+@item (:type datagram)
+Non-@code{nil} if datagrams are supported.
+@item (:family local)
+Non-@code{nil} if local (aka ``UNIX domain'') sockets are supported.
+@item (:service t)
+Non-@code{nil} if the system can select the port for a server.
+@end table
+
+  To test for the availability of a given network option, use
+@code{featurep} like this:
+
+@example
+(featurep 'make-network-process '@var{keyword})
+@end example
+
+@noindent
+Here are some of the options you can test in this way.
+
+@table @code
+@item :bindtodevice
+@itemx :broadcast
+@itemx :dontroute
+@itemx :keepalive
+@itemx :linger
+@itemx :oobinline
+@itemx :priority
+@itemx :reuseaddr
+That particular network option is supported by
+@code{make-network-process} and @code{set-network-process-option}.
+@end table
+
+@node Misc Network
+@section Misc Network Facilities
+
+  These additional functions are useful for creating and operating
+on network connections.
+
 @defun network-interface-list
 This function returns a list describing the network interfaces
 of the machine you are using.  The value is an alist whose
@@ -1938,7 +2022,8 @@ and @var{remote-address} arguments to @code{make-network-process}.
 
 @defun network-interface-info ifname
 This function returns information about the network interface named
-@var{ifname}.  The value is a list of the form @code{(@var{addr} @var{bcast} @var{netmask} @var{hwaddr} @var{flags})}.
+@var{ifname}.  The value is a list of the form
+@code{(@var{addr} @var{bcast} @var{netmask} @var{hwaddr} @var{flags})}.
 
 @table @var
 @item addr
@@ -1966,56 +2051,411 @@ If @var{omit-port} is non-@code{nil}, the value does not include
 the port number.
 @end defun
 
-  To test for the availability of a given network feature, use
-@code{featurep} like this:
+@node Byte Packing
+@section Packing and Unpacking Byte Arrays
 
-@example
-(featurep 'make-network-process '(@var{keyword} @var{value}))
-@end example
+  This section describes how to pack and unpack arrays of bytes,
+usually for binary network protocols.  These functions convert byte arrays
+to alists, and vice versa.  The byte array can be represented as a
+unibyte string or as a vector of integers, while the alist associates
+symbols either with fixed-size objects or with recursive sub-alists.
 
-@noindent
-The result of the first form is @code{t} if it works to specify
-@var{keyword} with value @var{value} in @code{make-network-process}.
-The result of the second form is @code{t} if @var{keyword} is
-supported by @code{make-network-process}.  Here are some of the
-@var{keyword}---@var{value} pairs you can test in
-this way.
+@cindex serializing
+@cindex deserializing
+@cindex packing
+@cindex unpacking
+  Conversion from byte arrays to nested alists is also known as
+@dfn{deserializing} or @dfn{unpacking}, while going in the opposite
+direction is also known as @dfn{serializing} or @dfn{packing}.
+
+@menu
+* Bindat Spec::         Describing data layout.
+* Bindat Functions::    Doing the unpacking and packing.
+* Bindat Examples::     Samples of what bindat.el can do for you!
+@end menu
+
+@node Bindat Spec
+@subsection Describing Data Layout
+
+  To control unpacking and packing, you write a @dfn{data layout
+specification}, a special nested list describing named and typed
+@dfn{fields}.  This specification controls length of each field to be
+processed, and how to pack or unpack it.
+
+@cindex endianness
+@cindex big endian
+@cindex little endian
+@cindex network byte ordering
+  A field's @dfn{type} describes the size (in bytes) of the object
+that the field represents and, in the case of multibyte fields, how
+the bytes are ordered within the field.  The two possible orderings
+are ``big endian'' (also known as ``network byte ordering'') and
+``little endian''.  For instance, the number @code{#x23cd} (decimal
+9165) in big endian would be the two bytes @code{#x23} @code{#xcd};
+and in little endian, @code{#xcd} @code{#x23}.  Here are the possible
+type values:
 
 @table @code
-@item (:nowait t)
-Non-@code{nil} if non-blocking connect is supported.
-@item (:type datagram)
-Non-@code{nil} if datagrams are supported.
-@item (:family local)
-Non-@code{nil} if local (aka ``UNIX domain'') sockets are supported.
-@item (:service t)
-Non-@code{nil} if the system can select the port for a server.
+@item u8
+@itemx byte
+Unsigned byte, with length 1.
+
+@item u16
+@itemx word
+@itemx short
+Unsigned integer in network byte order, with length 2.
+
+@item u24
+Unsigned integer in network byte order, with length 3.
+
+@item u32
+@itemx dword
+@itemx long
+Unsigned integer in network byte order, with length 4.
+Note: These values may be limited by Emacs' integer implementation limits.
+
+@item u16r
+@itemx u24r
+@itemx u32r
+Unsigned integer in little endian order, with length 2, 3 and 4, respectively.
+
+@item str @var{len}
+String of length @var{len}.
+
+@item strz @var{len}
+Zero-terminated string of length @var{len}.
+
+@item vec @var{len}
+Vector of @var{len} bytes.
+
+@item ip
+Four-byte vector representing an Internet address.  For example:
+@code{[127 0 0 1]} for localhost.
+
+@item bits @var{len}
+List of set bits in @var{len} bytes.  The bytes are taken in big
+endian order and the bits are numbered starting with @code{8 *
+@var{len} @minus{} 1} and ending with zero.  For example: @code{bits
+2} unpacks @code{#x28} @code{#x1c} to @code{(2 3 4 11 13)} and
+@code{#x1c} @code{#x28} to @code{(3 5 10 11 12)}.
+
+@item (eval @var{form})
+@var{form} is a Lisp expression evaluated at the moment the field is
+unpacked or packed.  The result of the evaluation should be one of the
+above-listed type specifications.
 @end table
 
-  To test for the availability of a given network option, use
-@code{featurep} like this:
+A field specification generally has the form @code{([@var{name}]
+@var{handler})}.  The square braces indicate that @var{name} is
+optional.  (Don't use names that are symbols meaningful as type
+specifications (above) or handler specifications (below), since that
+would be ambiguous.)  @var{name} can be a symbol or the expression
+@code{(eval @var{form})}, in which case @var{form} should evaluate to
+a symbol.
 
-@example
-(featurep 'make-network-process '@var{keyword})
-@end example
+@var{handler} describes how to unpack or pack the field and can be one
+of the following:
 
-Here are some of the option @var{keyword}s you can test in
-this way.
+@table @code
+@item @var{type}
+Unpack/pack this field according to the type specification @var{type}.
+
+@item eval @var{form}
+Evaluate @var{form}, a Lisp expression, for side-effect only.  If the
+field name is specified, the value is bound to that field name.
+@var{form} can access and update these dynamically bound variables:
 
 @table @code
-@item :bindtodevice
-@itemx :broadcast
-@itemx :dontroute
-@itemx :keepalive
-@itemx :linger
-@itemx :oobinline
-@itemx :priority
-@itemx :reuseaddr
-That particular network option is supported by
-@code{make-network-process} and @code{set-network-process-option}.
+@item raw-data
+The data as a byte array.
+
+@item pos
+Current position of the unpacking or packing operation.
+
+@item struct
+Alist.
+
+@item last
+Value of the last field processed.
 @end table
 
+@item fill @var{len}
+Skip @var{len} bytes.  In packing, this leaves them unchanged,
+which normally means they remain zero.  In unpacking, this means
+they are ignored.
+
+@item align @var{len}
+Skip to the next multiple of @var{len} bytes.
+
+@item struct @var{spec-name}
+Process @var{spec-name} as a sub-specification.  This describes a
+structure nested within another structure.
+
+@item union @var{form} (@var{tag} @var{spec})@dots{}
+@c ??? I don't see how one would actually  use this.
+@c ??? what kind of expression would be useful for @var{form}?
+Evaluate @var{form}, a Lisp expression, find the first @var{tag}
+that matches it, and process its associated data layout specification
+@var{spec}.  Matching can occur in one of three ways:
+
+@itemize
+@item
+If a @var{tag} has the form @code{(eval @var{expr})}, evaluate
+@var{expr} with the variable @code{tag} dynamically bound to the value
+of @var{form}.  A non-@code{nil} result indicates a match.
+
+@item
+@var{tag} matches if it is @code{equal} to the value of @var{form}.
+
+@item
+@var{tag} matches unconditionally if it is @code{t}.
+@end itemize
+
+@item repeat @var{count} @var{field-spec}@dots{}
+@var{count} may be an integer, or a list of one element naming a
+previous field.  For correct operation, each @var{field-spec} must
+include a name.
+@c ??? What does it MEAN?
+@end table
+
+@node Bindat Functions
+@subsection Functions to Unpack and Pack Bytes
+
+  In the following documentation, @var{spec} refers to a data layout
+specification, @code{raw-data} to a byte array, and @var{struct} to an
+alist representing unpacked field data.
+
+@defun bindat-unpack spec raw-data &optional pos
+This function unpacks data from the byte array @code{raw-data}
+according to @var{spec}.  Normally this starts unpacking at the
+beginning of the byte array, but if @var{pos} is non-@code{nil}, it
+specifies a zero-based starting position to use instead.
+
+The value is an alist or nested alist in which each element describes
+one unpacked field.
+@end defun
+
+@defun bindat-get-field struct &rest name
+This function selects a field's data from the nested alist
+@var{struct}.  Usually @var{struct} was returned by
+@code{bindat-unpack}.  If @var{name} corresponds to just one argument,
+that means to extract a top-level field value.  Multiple @var{name}
+arguments specify repeated lookup of sub-structures.  An integer name
+acts as an array index.
+
+For example, if @var{name} is @code{(a b 2 c)}, that means to find
+field @code{c} in the second element of subfield @code{b} of field
+@code{a}.  (This corresponds to @code{struct.a.b[2].c} in C.)
+@end defun
+
+@defun bindat-length spec struct
+@c ??? I don't understand this at all -- rms
+This function returns the length in bytes of @var{struct}, according
+to @var{spec}.
+@end defun
+
+@defun bindat-pack spec struct &optional raw-data pos
+This function returns a byte array packed according to @var{spec} from
+the data in the alist @var{struct}.  Normally it creates and fills a
+new byte array starting at the beginning.  However, if @var{raw-data}
+is non-@code{nil}, it specifies a pre-allocated string or vector to
+pack into.  If @var{pos} is non-@code{nil}, it specifies the starting
+offset for packing into @code{raw-data}.
+
+@c ??? Isn't this a bug?  Shouldn't it always be unibyte?
+Note: The result is a multibyte string; use @code{string-make-unibyte}
+on it to make it unibyte if necessary.
+@end defun
+
+@defun bindat-ip-to-string ip
+Convert the Internet address vector @var{ip} to a string in the usual
+dotted notation.
+
+@example
+(bindat-ip-to-string [127 0 0 1])
+     @result{} "127.0.0.1"
+@end example
+@end defun
+
+@node Bindat Examples
+@subsection Examples of Byte Unpacking and Packing
+
+  Here is a complete example of byte unpacking and packing:
+
+@lisp
+(defvar fcookie-index-spec
+  '((:version  u32)
+    (:count    u32)
+    (:longest  u32)
+    (:shortest u32)
+    (:flags    u32)
+    (:delim    u8)
+    (:ignored  fill 3)
+    (:offset   repeat (:count)
+               (:foo u32)))
+  "Description of a fortune cookie index file's contents.")
+
+(defun fcookie (cookies &optional index)
+  "Display a random fortune cookie from file COOKIES.
+Optional second arg INDEX specifies the associated index
+filename, which is by default constructed by appending
+\".dat\" to COOKIES.  Display cookie text in possibly
+new buffer \"*Fortune Cookie: BASENAME*\" where BASENAME
+is COOKIES without the directory part."
+  (interactive "fCookies file: ")
+  (let* ((info (with-temp-buffer
+                 (insert-file-contents-literally
+                  (or index (concat cookies ".dat")))
+                 (bindat-unpack fcookie-index-spec
+                                (buffer-string))))
+         (sel (random (bindat-get-field info :count)))
+         (beg (cdar (bindat-get-field info :offset sel)))
+         (end (or (cdar (bindat-get-field info
+                                          :offset (1+ sel)))
+                  (nth 7 (file-attributes cookies)))))
+    (switch-to-buffer
+     (get-buffer-create
+      (format "*Fortune Cookie: %s*"
+              (file-name-nondirectory cookies))))
+    (erase-buffer)
+    (insert-file-contents-literally
+     cookies nil beg (- end 3))))
+
+(defun fcookie-create-index (cookies &optional index delim)
+  "Scan file COOKIES, and write out its index file.
+Optional second arg INDEX specifies the index filename,
+which is by default constructed by appending \".dat\" to
+COOKIES.  Optional third arg DELIM specifies the unibyte
+character which, when found on a line of its own in
+COOKIES, indicates the border between entries."
+  (interactive "fCookies file: ")
+  (setq delim (or delim ?%))
+  (let ((delim-line (format "\n%c\n" delim))
+        (count 0)
+        (max 0)
+        min p q len offsets)
+    (unless (= 3 (string-bytes delim-line))
+      (error "Delimiter cannot be represented in one byte"))
+    (with-temp-buffer
+      (insert-file-contents-literally cookies)
+      (while (and (setq p (point))
+                  (search-forward delim-line (point-max) t)
+                  (setq len (- (point) 3 p)))
+        (setq count (1+ count)
+              max (max max len)
+              min (min (or min max) len)
+              offsets (cons (1- p) offsets))))
+    (with-temp-buffer
+      (set-buffer-multibyte nil)
+      (insert
+       (string-make-unibyte
+        (bindat-pack
+         fcookie-index-spec
+         `((:version . 2)
+           (:count . ,count)
+           (:longest . ,max)
+           (:shortest . ,min)
+           (:flags . 0)
+           (:delim . ,delim)
+           (:offset . ,(mapcar (lambda (o)
+                                 (list (cons :foo o)))
+                               (nreverse offsets)))))))
+      (let ((coding-system-for-write 'raw-text-unix))
+        (write-file (or index (concat cookies ".dat")))))))
+@end lisp
+
+Following is an example of defining and unpacking a complex structure.
+Consider the following C structures:
+
+@example
+struct header @{
+    unsigned long    dest_ip;
+    unsigned long    src_ip;
+    unsigned short   dest_port;
+    unsigned short   src_port;
+@};
+
+struct data @{
+    unsigned char    type;
+    unsigned char    opcode;
+    unsigned long    length;  /* In little endian order */
+    unsigned char    id[8];   /* null-terminated string  */
+    unsigned char    data[/* (length + 3) & ~3 */];
+@};
+
+struct packet @{
+    struct header    header;
+    unsigned char    items;
+    unsigned char    filler[3];
+    struct data      item[/* items */];
+
+@};
+@end example
+
+The corresponding data layout specification:
+
+@lisp
+(setq header-spec
+      '((dest-ip   ip)
+        (src-ip    ip)
+        (dest-port u16)
+        (src-port  u16)))
+
+(setq data-spec
+      '((type      u8)
+        (opcode    u8)
+        (length    u16r) ;; little endian order
+        (id        strz 8)
+        (data      vec (length))
+        (align     4)))
+
+(setq packet-spec
+      '((header    struct header-spec)
+        (items     u8)
+        (fill      3)
+        (item      repeat (items)
+                   (struct data-spec))))
+@end lisp
+
+A binary data representation:
+
+@lisp
+(setq binary-data
+      [ 192 168 1 100 192 168 1 101 01 28 21 32 2 0 0 0
+        2 3 5 0 ?A ?B ?C ?D ?E ?F 0 0 1 2 3 4 5 0 0 0
+        1 4 7 0 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ])
+@end lisp
+
+The corresponding decoded structure:
+
+@lisp
+(setq decoded (bindat-unpack packet-spec binary-data))
+     @result{}
+((header
+  (dest-ip   . [192 168 1 100])
+  (src-ip    . [192 168 1 101])
+  (dest-port . 284)
+  (src-port  . 5408))
+ (items . 2)
+ (item ((data . [1 2 3 4 5])
+        (id . "ABCDEF")
+        (length . 5)
+        (opcode . 3)
+        (type . 2))
+       ((data . [6 7 8 9 10 11 12])
+        (id . "BCDEFG")
+        (length . 7)
+        (opcode . 4)
+        (type . 1))))
+@end lisp
+
+Fetching data from this structure:
+
+@lisp
+(bindat-get-field decoded 'item 1 'id)
+     @result{} "BCDEFG"
+@end lisp
+
 @ignore
    arch-tag: ba9da253-e65f-4e7f-b727-08fba0a1df7a
 @end ignore
-