]> code.delx.au - gnu-emacs/blobdiff - lispref/processes.texi
(Searching and Matching): Move node.
[gnu-emacs] / lispref / processes.texi
index 07a728863554b289e6535e1bf9e67b28ebf1542f..afdeaa1d2a071c3260561d01f184ba684a1829b8 100644 (file)
@@ -1,7 +1,7 @@
 @c -*-texinfo-*-
 @c This is part of the GNU Emacs Lisp Reference Manual.
 @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
 @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.
 * 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
 @end menu
 
 @node Subprocess Creation
@@ -168,7 +170,7 @@ function.
 (shell-quote-argument "foo > bar")
      @result{} "foo\\ \\>\\ bar"
 
 (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
 (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
 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
 
   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
 @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
 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
@@ -1559,7 +1561,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
 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
 
   You can distinguish process objects representing network connections
 and servers from those representing subprocesses with the
@@ -1574,7 +1576,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
 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
 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 +1717,20 @@ sets its remote peer address to @var{address}.
 @node Low-Level Network
 @section Low-Level Network Access
 
 @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.
    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 +1839,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}
 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}.
 
 @item :filter @var{filter}
 Initialize the process filter to @var{filter}.
@@ -1850,14 +1867,21 @@ happened.
 Initialize the process plist to @var{plist}.
 @end table
 
 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
+
+  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
+  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
 @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}
 
 @table @asis
 @item :bindtodevice @var{device-name}
@@ -1912,13 +1936,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.
 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
 
 @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
 @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 +1947,64 @@ The current setting of an option is available via the
 @code{process-contact} function.
 @end defun
 
 @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
 @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 +2015,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
 
 @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
 
 @table @var
 @item addr
@@ -1966,56 +2044,411 @@ If @var{omit-port} is non-@code{nil}, the value does not include
 the port number.
 @end defun
 
 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
 
 @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
 
 @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
 
 @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
 
 @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
 @ignore
    arch-tag: ba9da253-e65f-4e7f-b727-08fba0a1df7a
 @end ignore
-