This is poke.info, produced by makeinfo version 6.7 from poke.texi.

This manual describes GNU poke (version 3.3, 20 August 2023).

   Copyright (C) 2019, 2020, 2021, 2022, 2023 The poke authors.

     You can redistribute it and/or modify this manual 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.
INFO-DIR-SECTION Editors
START-INFO-DIR-ENTRY
* poke: (poke). Interactive editor for binary files.
END-INFO-DIR-ENTRY


File: poke.info,  Node: Top,  Next: Introduction,  Up: (dir)

GNU poke Manual
***************

This manual describes GNU poke (version 3.3, 20 August 2023).

   Copyright (C) 2019, 2020, 2021, 2022, 2023 The poke authors.

     You can redistribute it and/or modify this manual 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.

   GNU poke is an interactive, extensible editor for binary data.  Not
limited to editing basic entities such as bits and bytes, it provides a
full-fledged procedural, interactive programming language designed to
describe data structures and to operate on them.

   This manual describes the 'poke' binary data editor as well as the
Poke language.

* Menu:

Getting Started
* Introduction::		Introducing GNU poke.
* Setting Up::                  Preparing to use GNU poke.

Using poke
* Basic Editing::		Poking bits, bytes and simple data.
* Structuring Data::		Poking your own abstractions.
* Maps and Map-files::          Working with views of data.
* Writing Pickles::		Sharing your abstractions the sane way.
* Writing Binary Utilities::    Standalone Poke programs.
* Configuration::		Tailoring the tool to your needs.

Pickles
* IOS::                         Functions to work with IO spaces.
* Time::			Handling time.
* Colors::			Editing colors.
* Audio::			Poking audio files.
* Object Formats::		Editing executables and libraries.
* Programs::			Facilities to write binary utilities.

poked
* poked::                       The poke daemon.

poke and Emacs
* Programming Emacs Modes::     Modes to write Poke and RAS programs.

poke and Vim
* Vim Syntax Highlighting::     Poke Syntax Highlighting in Vim.

Reference Material
* Dot-Commands::                Commanding the tool.
* Commands::			Commands for editing data.
* The Poke Language::		Poke reference manual.
* The Standard Library::	Standard goodies for Poke programs.

Internals
* The Poke Virtual Machine::	The PVM and its mysteries.

Appendices
* Table of ASCII Codes::	   The ASCII character set.
* GNU Free Documentation License:: Distribution terms for this document.
* Indices::			   List of indices in this document.

-- The Detailed Node Listing --

Here are some other nodes which are really subnodes of the ones
already listed, mentioned here so you can get to them in one step:

Introduction
* Motivation::			Why a binary editor?
* Nomenclature::		poke, Poke and pickles.
* Invoking poke::		command line options.
* Commanding poke::		Interactive and non-interactive usage.

Setting Up
* Setting up Hyperlinks::       GNU poke uses terminal hyperlinks.
* Simple Init File::            A simple initial ~/.pokerc.

Basic Editing
* Binary Files::		Text vs. binary.
* Files as IO Spaces::		Poking files.
* Dumping File Contents::	A first look at a file's bytes.
* Poking Bytes::		Reading, manipulating and writing bytes.
* Values and Variables::        Values can be stored in variables.
* From Bytes to Integers::	Building numbers with bytes.
* Big and Little Endians::	Pick your egg.
* Negative Integers::		Going behind zero.
* Weird Integers::		Incomplete bytes in numbers.
* Unaligned Integers::		IO spaces are bit-oriented.
* Integers of Different Sizes:: Promotion of integers in expressions.
* Offsets and Sizes::           United values.
* Buffers as IO Spaces::	Poking memory buffers.
* Copying Bytes::		Moving data between IO spaces.
* Saving Buffers in Files::	From memory to files.
* Character Sets::		ASCII, Unicode, ...
* From Bytes to Characters::	Working with ASCII codes
* ASCII Strings::		NULL-terminated strings.
* From Strings to Characters::	Indexing strings.

Structuring Data
* The SBM Format::		The Stupid BitMap Format
* Poking a SBM Image::		A need for abstraction.
* Modifying SBM Images::	Modifying existing data.
* Defining Types::		Abstracting data structures.
* Pickles::			Pickling useful abstractions.
* Poking Structs::		Abstracting heterogeneous data.
* How Structs are Built::	How poke builds struct values.
* Variables in Structs::
* Functions in Structs::
* Struct Methods::		Operations provided by built structs.
* Padding and Alignment::       Reserved fields, payloads and more.
* Dealing with Alternatives::   Conditional decoding.
* Structured Integers::         Structs that are stored like integers.
* Working with Incorrect Data:: Non-strict mapping to the rescue.

Maps and Map-files
* Editing using Variables::     Data is usually edited mapping variables.
* poke Maps::                   Maps and map-files.
* Loading Maps::                Using maps defined in files.
* Multiple Maps::               Multiple perspectives of the same data.
* Auto-map::                    Loading maps automagically.
* Constructing Maps::           Creating and managing maps on the fly.
* Predefined Maps::             Collection of already-written maps.

Writing Pickles
* Pretty-printers::		Conventions for pretty-printed output.
* Setters and Getters::		Anatomy getters and setters.

Writing Binary Utilities
* Poke Scripts::                Using poke as an interpreter.
* Command-Line Arguments::      Handling command-line arguments.
* Exiting from Scripts::        Exit with an error status.
* Loading pickles as Modules::  Importing pickles in programs.
* elfextractor::                An example Poke binary utility.
* Filters::                     Writing filters for binary data.

Configuration
* pokerc::			User's initialization file.
* Load Path::			Determining location of modules.
* Styling::			Changing the appearance of poke's output.

Time
* POSIX Time::			Encoding POSIX dates.

Colors
* The Color Registry::		The 'color' pickle.
* RGB24 Encoding::		Encoding colors with three bytes.

Audio
* MP3::				Editing MP3 files.

Programming Emacs Modes
* poke-mode::                   Major mode for writing Poke programs.
* poke-map-mode::               Major mode for writing map-files.
* poke-ras-mode::               Major mode for writing RAS programs.

Vim Syntax Highlighting
* poke.vim::    Poke syntax highlighter

Dot-Commands
* load command::		Loading pickles.
* source command::              Executing commands in files.
* file command::		Opening and selecting file IO spaces.
* mem command::			Opening and selecting memory IO spaces.
* nbd command::			Opening and selecting NBD IO spaces.
* proc command::                Opening and selecting process IO spaces.
* ios command::			Switching between IO spaces.
* close command::		Closing IO spaces.
* doc command::                 Online manual.
* editor command::		Using an external editor for input.
* info command::		Getting information about open files, etc.
* set command::			Querying and setting global options.
* vm command::			Poke Virtual Machine services.
* exit command::		Exiting poke :(
* quit command::		Likewise.

Commands
* dump::			Binary dumps.
* copy::			Copying data around.
* save::			Save data into a file.
* sdiff::                       Comparing mapped values byte by byte.
* extract::			Extract contents of values to buffers.
* scrabble::			Scrabble memory chunks based on patterns.

The Poke Language
* Integers::			Whole numbers.
* Offsets::			Memory sizes and offsets.
* Strings::			NULL-terminated strings.
* Arrays::			Homogeneous collections.
* Structs::			Heterogeneous collections.
* Types::			Declaring types.
* Assignments::			Changing the value of variables.
* Compound Statements::		Sequences of statements.
* Conditionals::		Conditional statements and expressions.
* Loops::			Statements to iterate on conditions.
* Expression Statements::	Using expressions for their side-effects.
* Functions::			Procedural abstraction.
* Assembler::                   Assembler instructions with Poke operands.
* Endianness::			Byte ordering.
* Mapping::			Accessing IO spaces.
* Exception Handling::		Dealing with exceptional conditions.
* Terminal::	                Dealing with the terminal.
* Printing::			Output in Poke programs.
* Comments::			Documenting Poke programs.
* Modules::			Loading pickles from Poke programs.
* System::			Accessing the system from within Poke.
* VM::                          Tweaking the PVM in Poke programs.
* Debugging::                   Debugging Poke programs.

The Standard Library
* Standard Integral Types::	int, long and the like.
* Standard Offset Types::	off64 and the like.
* Standard Units::		b, B, Kb and the like.
* Conversion Functions::	catos, atoi, etc.
* Array Functions::             Functions which deal with arrays.
* String Functions::		Functions which deal with strings.
* Character Functions::         Functions which deal with characters.
* Values Functions::            Functions which deal with values in general.
* Sorting Functions::		qsort.
* CRC Functions::               Cyclic Redundancy Checksums.
* Dates and Times::             Processing and displaying dates and times.
* Offset Functions::            Useful functions that operate on offsets.
* Other Functions::             Miscellany.


The Poke Virtual Machine
* PVM Instructions::		Virtual Machine instructions.


File: poke.info,  Node: Introduction,  Next: Setting Up,  Prev: Top,  Up: Top

1 Introduction
**************

* Menu:

* Motivation::			Why a binary editor?
* Nomenclature::		poke, Poke and pickles.
* Invoking poke::		command line options.
* Commanding poke::		Interactive and non-interactive usage.


File: poke.info,  Node: Motivation,  Next: Nomenclature,  Up: Introduction

1.1 Motivation
==============

The main purpose of GNU poke is to manipulate structured binary data in
terms of abstractions provided by the user.  The Poke type definitions
can be seen as a sort of declarative specifications for decoding and
encoding procedures.  The user specifies the structure of the data to be
manipulated, and poke uses that information to automagically decode and
encode the data.  Under this perspective, struct types correspond to
sequences of instructions, array types to repetitions or loops, union
types to alternatives or conditionals, and so on.

* Menu:

* Decode-Compute-Encode:: Encoded data and conventional languages.
* Describe-Compute::      The poke approach.


File: poke.info,  Node: Decode-Compute-Encode,  Next: Describe-Compute,  Up: Motivation

1.1.1 Decode-Compute-Encode
---------------------------

Computing with data whose form is not the most convenient way to be
manipulated, like is often the case in unstructured binary data,
requires performing a preliminary step that transforms the data into a
more convenient representation, usually featuring a higher level of
abstraction.  This step is known in computer jargon as "unmarshalling",
when the data is fetch from some storage or transmission media or, more
generally, "decoding".

   Once the computation has been performed, the result should be
transformed back to the low-level representation to be stored or
transmitted.  This is performed in a closing step known as "marshalling"
or, more generally, "encoding".

   Consider the following C program whose purpose is to read a 32-bit
signed integer from a byte-oriented storage media at a given offset,
multiply it by two, and store the result at the same offset.

     void double_number (int fd, off_t offset, int endian)
     {
        int number, i;
        unsigned char b[4];

        /* Decode.  */
        lseek (fd, offset, SEEK_SET);
        for (i = 0; i < 4; ++i)
           read (fd, &b[i], 1);

        if (endian == BIG)
          number = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
        else
          number = b[3] << 24 | b[2] << 16 | b[1] << 8 | b[0];

        /* Compute.  */
        number = number * 2;

        /* Encode.  */
        if (endian == BIG)
        {
          b[0] = (number >> 24) & 0xff;
          b[1] = (number >> 16) & 0xff;
          b[2] = (number >> 8) & 0xff;
          b[3] = number & 0xff;
        }
        else
        {
          b[3] = (number >> 24) & 0xff;
          b[2] = (number >> 16) & 0xff;
          b[1] = (number >> 8) & 0xff;
          b[0] = number & 0xff;
        }

        lseek (fd, offset, SEEK_SET);
        for (i = 0; i < 4; ++i)
           write (fd, &b[i], 1);
     }

   As we can see, decoding takes care of fetching the data from the
storage in simple units, bytes.  Then it mounts the more abstract entity
on which the computation will be performed, in this case a signed 32-bit
integer.  Considerations like endianness, negative encoding (which is
assumed to be two's complement in this example and handled automatically
by C) and error conditions (omitted in this example for clarity) should
be handled properly.

   Conversely, encoding turns the signed 32-bit integer into a sequence
of bytes and then writes them out to the storage at the desired offset.
Again, this requires taking endianness into account and handling error
conditions.

   This example may look simplistic and artificial, and it is, but too
often the computation proper (like multiplying the integer by two) is
way more straightforward than the decoding and encoding of the data used
for the computation.

   Generally speaking, decoding and encoding binary data is laborious
and error prone.  Think about sequences of elements, variable-length and
clever compact encodings, elements not aligned to byte boundaries, the
always bug-prone endianness, and a long etc.  Dirty business, sometimes
risky, and always _boring_.


File: poke.info,  Node: Describe-Compute,  Prev: Decode-Compute-Encode,  Up: Motivation

1.1.2 Describe-Compute
----------------------

This is where poke comes into play.  Basically, it allows you to
describe the characteristics of the data you want to compute on, and
then decodes and encodes it for you, taking care of the gory details.
That way you can concentrate your energy on the _fun_ part: computing on
the data at your pleasure.

   Of course, you are still required to provide a description of the
data.  In the Poke language, these descriptions take the form of "type
definitions", which are "declarative": you specify _what_ you want, and
poke extracts the _how_ from that.

   For example, consider the following Poke type definition:

     type Packet =
       struct
       {
         uint<16> magic == 0xef;
         uint<32> size;
         byte[size] data @ 8#B;
       };

   This tells poke that, in order to decode a 'Packet', it should
perform the following procedure (a similar procedure is implied for
encoding):

   - Read two bytes from the IO space, mount them into an unsigned
     16-bit integer using whatever current endianness, and put it in
     'magic'.  If this unsigned 16-bit integer doesn't equal to '0xef',
     then stop and emit a "data integrity" error.
   - Read four bytes, mount them into an unsigned 32-bit integer using
     the same endianness, and put it in 'size'.
   - Seek the IO space to advance 16 bits.
   - Do 'size' times:

        - Read one byte and mount it into an unsigned 8-bit integer.
        - Put the integer in the proper place in the 'data' array.

   If during this procedure an end of file is encountered, or some other
erroneous condition happens, an appropriate error is raised.

   In the procedure sketched above we find a sequence of operations,
implied by the struct type, and a loop, implied by the array type.  As
we shall see later in this book, it is also possible to decode
conditionally.  Union types are used for that purpose.


File: poke.info,  Node: Nomenclature,  Next: Invoking poke,  Prev: Motivation,  Up: Introduction

1.2 Nomenclature
================

GNU poke is a new program and it introduces many new concepts.  It is a
good idea to clarify how we call things in the poke community.  Unless
everyone uses the same nomenclature to refer to pokish thingies, it is
gonna get very confusing very soon!

   First of all we have 'poke', the program.  Since "poke" is a very
common English word, when the context is not clear we either use the
full denomination 'GNU poke', or quote the word using some other
notation.

   Then we have "Poke", with upper case P, which is the name of the
domain-specific programming language implemented by 'poke', the program.

   This distinction is important.  For example, when people talk about
"poke programmers" they refer to the group of people hacking GNU poke.
When they talk about "Poke programmers" they refer to the people who
write programs using the Poke programming language.

   Finally, a "pickle" is a Poke source file containing definitions of
types, variables, functions, etc, that conceptually apply to some
definite domain.  For example, 'elf.pk' is a pickle that provides
facilities to poke ELF object files.  Pickles are not necessarily
related to file formats: a set of functions to work with bit patterns,
for example, could be implemented in a pickle named 'bitpatterns.pk'.

   We hope this helps to clarify things.


File: poke.info,  Node: Invoking poke,  Next: Commanding poke,  Prev: Nomenclature,  Up: Introduction

1.3 Invoking poke
=================

Synopsis:

     poke [OPTION...] [FILE]

The following options are available.

'-l'
'--load=FILE'
     Load the given file as a Poke program.  Any number of '-l' options
     can be specified, and they are loaded in the given order.

'-L FILE'
     Load the given file as a Poke program and exit.  The rest of the
     command-line is not processed by poke, and is available to the Poke
     script in the 'argv' variable.  This is commonly used along with a
     shebang (*note Scripts::) to implement Poke scripts.

Commanding poke from the command line:

'-c'
'--command=CMD'
     Execute the given command.  Any number of '-c' options can be
     specified, and they are executed in the given order.

'-s'
'--source=FILE'
     Load FILE as a command file.  Any number of '-s' options may be
     specified, and they are loaded in the given order.  *Note Command
     Files::.

Styling text output:

'--color=HOW'
     Whether to use styled output, and how.  Valid options for HOW are
     'yes', 'no', 'auto', 'html' and 'test'.

'--style-dark'
     Use the default style that works better for dark backgrounds.  This
     is the default.

'--style-bright'
     Use the default style that works better for bright backgrounds.

'--style=FILE'
     Use FILE as the CSS to use for styling poke, instead of the default
     style.

Other options:

'-q'
'--no-init-file'
     Do not load the '~/.pokerc' init file.

'--no-auto-map'
     Do not load map-files automatically when poke opens IO spaces.

'--no-hserver'
     Do not run the terminal hyperlinks server.

'--quiet'
     Be as terse as possible.

'--help'
     Print a help message and exit.

'--version'
     Show version and exit.


File: poke.info,  Node: Commanding poke,  Prev: Invoking poke,  Up: Introduction

1.4 Commanding poke
===================

GNU poke is primarily an interactive editor that works in the command
line.  However, it is also possible to use it in a non-interactive way.
This chapter documents both possibilities.

* Menu:

* The REPL::                  Using poke interactively.
* Evaluation::		      Evaluating Poke.
* Commands and Dot-Commands:: Two kinds of commands.
* Command Files::	      Loading commands from files.
* Scripts::		      Executing Poke programs in the command line.


File: poke.info,  Node: The REPL,  Next: Evaluation,  Up: Commanding poke

1.4.1 The REPL
--------------

If poke is invoked with an interactive TTY connected to the standard
input, it greets you with a welcome message, licensing information and
such, and finally a prompt that looks like:

     (poke)

   At this point, the program is ready to be commanded.  You are
expected to introduce a line and press <enter>.  At that point poke will
examine the command, notify you if there is some error condition,
process the line and maybe displaying something in the terminal.

   Repeatedly typing complex commands can be tiresome.  To help you,
poke uses the readline library *Note (rluserman)Top::.  This provides
shortcuts and simple keystrokes to repeat previous commands with or
without modification, fast selection of file names and entries from
other multiple choice contexts, and navigation within a command and
among previous commands.  When the REPL starts, the history of your
previous sessions are loaded from the file '.poke_history' located in
your home directory (if it exists).

   There are several kinds of lines that can be provided in the REPL:

   * A "dot-command" invocation, that starts with a dot character ('.').
   * A command invocation.
   * A Poke statement.
   * A Poke expression.

   These are explained in the following sections.


File: poke.info,  Node: Evaluation,  Next: Commands and Dot-Commands,  Prev: The REPL,  Up: Commanding poke

1.4.2 Evaluation
----------------

You can evaluate a Poke statement by typing it at the REPL's prompt.
Only a single statement, including expression statements (*note
Expression Statements::) and compound statements (*note Compound
Statements::), can be evaluated this way.  It needs not be terminated by
a semicolon.

   When an expression is evaluated, the result of the evaluation is
printed back to you.  For example:

     (poke) 23
     23
     (poke) [1,2,3]
     [1,2,3]
     (poke) Packet @ 0#B
     Packet {i=1179403647,j=65794L}

   When a statement other than an expression statement is executed in
the REPL no result is printed, but of course the statement can print on
its own:

     (poke) fun do_foo = void: {}
     (poke) do_foo
     (poke) for (i in [1,2,3]) printf "elem %i32d\n", i;
     elem 1
     elem 2
     elem 3

   If there is an error compiling the line, you are notified with a nice
error message, showing the location of the error.  For example:

     (poke) [1,2,3 + "foo"]
     <stdin>:1:6: error: invalid operands in expression
     [1,2,3 + "foo"];
          ^~~~~~~~~


File: poke.info,  Node: Commands and Dot-Commands,  Next: Command Files,  Prev: Evaluation,  Up: Commanding poke

1.4.3 Commands and Dot-Commands
-------------------------------

There are two kinds of commands in poke: the "dot-commands", which are
written in C and have their own conventions for handling sub-commands
and passing arguments and flags, and normal commands, which are written
in Poke.

1.4.3.1 Dot-Commands
....................

Dot-commands are so called because their names start with the dot
character ('.').  They can feature subcommands.  Example:

     (poke) .vm disassemble expression int[] @ 0#B
     (poke) .vm disassemble function (dump)

   When there is no ambiguity, the command name and the subcommands can
be shortened to prefixes.  The commands above can also be written as:

     (poke) .vm dis e int[] @ 0#B
     (poke) .vm dis f (dump)

   Some commands also get flags, which are one-letter indicators that
can be appended to the command name (including subcommands) after a
slash character ('/').  For example, the '.vm' disassembler commands
accept a 'n' flag to indicate we want a native disassemble.  We can pass
it as follows:

     (poke) .vm disassemble expression/n int[] @ 0#B
     (poke) .vm disassemble function/n (dump)

   If a dot-command accepts more than one argument, they are separated
using comma characters (',').  Spaces are generally ignored.

1.4.3.2 Commands
................

Regular poke commands are written in Poke and use different conventions.
The name of commands follow the same rules as normal Poke identifiers,
and do not start with a dot character.

   An example is the 'dump' command:

     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 f700 0100 0000 0000 0000 0000 0000  ................
     00000020: 0000 0000 0000 0000 8001 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ....@.....@.....
     00000040: 1800 0000 0000 0000 0000 0000 0000 0000  ................
     00000050: 7900 0000 0000 0000 b701 0000 9a02 0000  y...............
     00000060: 7b10 0000 0000 0000 1800 0000 0000 0000  {...............
     00000070: 0000 0000 0000 0000 7900 0000 0000 0000  ........y.......

   After the name of the command, arguments can be specified by name,
like this:

     (poke) dump :from 0#B :size 8#B
     (poke) dump :from 0#B :size 8#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100                      .ELF....

   The 'dump' command is discussed in greater detail below (*note
dump::).  The order of arguments is irrelevant in principle:

     (poke) dump :from 0#B :size 8#B :ascii 0 :ruler 0
     00000000: 7f45 4c46 0201 0100
     (poke) dump :ruler 0 :from 0#B :size 8#B :ascii 0
     00000000: 7f45 4c46 0201 0100

   However, beware side effects while computing the values you pass as
the arguments!  The expressions themselves are evaluated from left to
right (according to the order of declaration in the signature).

   Which arguments are accepted, and their kind, depend on the specific
command.

   Note that the idea is to restrict the number of dot-commands to the
absolutely minimum.  Most of the command-like functionality provided in
poke shall be implemented as regular commands.


File: poke.info,  Node: Command Files,  Next: Scripts,  Prev: Commands and Dot-Commands,  Up: Commanding poke

1.4.4 Command Files
-------------------

Command files contain poke commands.  A poke command may be a dot
command, a Poke statement or a Poke expression.  Lines starting with '#'
are comments will be ignored.  However a comment must start at the
beginning of a line.  Here is an example of a script:

     # The following two lines are dot commands
     .load my-pickle.pk
     .set obase 16

     # The following line is a Poke statement
     dump :size 0x100#B :from 0x10#B

     # The following line is a Poke expression statement without any side effect.
     # Consequently it is valid, but rather useless.
     4 == 4

   A command file contains commands, not Poke code.  This means it gets
read line by line and commands cannot occupy more than one line.  Hence
the following is a valid command file:

     type foo = struct {int this; int that;}

but this is not valid as a command file (although it is a valid Poke
statement) and will provoke an error:

     type foo = struct
     {
      int this;
      int that;
     }

   Command files can be loaded at startup using the '-s' command line
option (*note Invoking poke::).  The '~/.pokerc' startup file is also an
example of a poke command file (*note pokerc::).


File: poke.info,  Node: Scripts,  Prev: Command Files,  Up: Commanding poke

1.4.5 Scripts
-------------

Following the example of Guile Scheme, the Poke syntax includes support
for multi-line comments using the '#!' and '!#' delimiters.  This, along
with the '-L' command line option, allows to write Poke scripts and
execute them in the command line like if they were normal programs.
Example of a script:

     #!/usr/bin/poke -L
     !#

     print "Hello world!\n";

   The resulting script can process command-line options by accessing
the 'argv' array.  The following Poke script prints its arguments:

     #!/usr/bin/poke -L
     !#

     for (arg in argv)
       printf ("Argument: %s\n", arg);

   If you want to pass additional flags to the poke command, you need to
use a slightly different kind of shebang:

     #!/usr/bin/env sh
     exec poke -L "$0" "$@"
     !#

     load elf;
     open (argv[0]);
     printf ("%v\n", Elf64_Ehdr @ 0#B);


File: poke.info,  Node: Setting Up,  Next: Basic Editing,  Prev: Introduction,  Up: Top

2 Setting Up
************

* Menu:

* Setting up Hyperlinks::       GNU poke uses terminal hyperlinks.
* Simple Init File::            A simple initial ~/.pokerc.


File: poke.info,  Node: Setting up Hyperlinks,  Next: Simple Init File,  Up: Setting Up

2.1 Setting up Hyperlinks
=========================

GNU poke uses "terminal hyperlinks" in order to improve the interactive
usage of the tool: clicking on terminal hyperlinks requests poke to
execute certain actions.  This is used to implement buttons and other
interactive goodies.

   Many terminal emulators support terminal hyperlinks.  However, we are
using a very simple protocol called 'app://' that is not supported (yet)
on GNU/Linux distros.  Fortunately, it is very easy to set your system
to use this protocol, and this chapter shows you how.

2.1.1 Make sure your poke speaks hyperlinks
-------------------------------------------

The first step in having an hyperlinks-capable poke is to make sure to
have a recent enough version of libtextstyle when building poke.  If
your poke can emit hyperlinks you will see a message like this when
running it on the terminal:

     hserver listening in port 43713.

2.1.2 Use a terminal emulator that supports hyperlinks
------------------------------------------------------

Gnome Terminal has support for displaying hyperlinks as do many other
emulators that rely on VTE. Check the list at
<https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#supporting-apps>
for a mostly up-to-date, non-exhaustive list of emulators that support
printing hyperlinks.

2.1.3 Get and install the app-client utility
--------------------------------------------

Since 'app://' is a new URI protocol that we designed, common terminal
emulators don't know what to do when they encounter such a URI. To work
around this problem we use the XDG Desktop Specification and a little C
utility called 'app-client', which can be found at
<https://gitlab.com/darnir/hyperlink-app-client>.

   By setting 'app-client' as the default handler for 'app://' URIs, the
terminal emulator does not need to understand the syntax or semantics of
the 'app://' protocol.  It offloads the handling of the URI entirely to
'app-client'.  In order to use this, first download and install
'app-client':

     $ git clone https://gitlab.com/darnir/hyperlink-app-client
     $ cd hyperlink-app-client
     $ make
     $ sudo make install

   This is enough for any utility (like terminals) that use 'xdg-open'
to do the right thing with hyperlinks.  However, certain terminals
require additional setup.  See below if that is your case.

2.1.4 GNOME Terminal
--------------------

Gnome Terminal doesn't use 'xdg-open' to start the applications.
Instead, it parses the 'mimeapps.list' file manually to find the right
application.

   Edit your 'mimeapps.list', it is usually located at
'$HOME/.local/share/applications/mimeapps.list', but it might also be at
'$XDG_CONFIG_DIR/mimeapps.list', and add the following line to it:

     x-scheme-handler/app=app-client.desktop

   This let's Gnome Terminal know how to open 'app://' links.


File: poke.info,  Node: Simple Init File,  Prev: Setting up Hyperlinks,  Up: Setting Up

2.2 Simple Init File
====================

GNU poke is a spartan program that tries to be as simple as possible by
default, without fancy displays.  Therefore, before exploring poke you
may want to configure it minimally.  This section contains a few
recommendations in that respect.

   First we must say that poke reads a per-user configuration from the
'~/.pokerc' file.  *Note pokerc::.

   We recommend new users to set the following options:

     .set endian little
     .set omode tree
     .set oacutoff 5
     .set pretty-print yes
     .set pager yes

'.set endian little' will make poke to use little-endian by default when
accessing IO spaces, such as files or memory buffers.  *Note Big and
Little Endians::.

   '.set omode tree' will make poke to format composite data structures,
such as arrays and struct, in several lines in a nice tree-like format.
By default the program will format these values in a single line (what
we call the "plain" output mode) which can be difficult to read.

   '.set oacutoff 5' will make poke to output at most five elements in
array values, followed by a dieresis '...'.

   '.set pretty-print yes' will make poke to use pretty-printers when
printing out values of struct types that have a pretty-printer defined
for them.  You can recognize pretty-printed values because, by
convention, they are emitted between '#<' and '>' markers, like for
example '#<leb128:1234>'.  If you see a pretty-printed value and you
need to look at its internal structure, you can disable pretty-printing
using a '.set pretty-print no' dot-command at any time.  *Note
Pretty-printers::.

   '.set pager yes' will make poke to page the output of commands that
emit output larger than the visible terminal.  This of course only has
an effect when running poke interactively.

   These options are fully explained later in this manual.  *Note set
command::.


File: poke.info,  Node: Basic Editing,  Next: Structuring Data,  Prev: Setting Up,  Up: Top

3 Basic Editing
***************

In this chapter you will learn how to shuffle binary data around with
poke, in terms of fundamental predefined entities: bits, bytes,
integers, and the like.

* Menu:

* Binary Files::		Text vs. binary.
* Files as IO Spaces::		Poking files.
* Dumping File Contents::	A first look at a file's bytes.
* Poking Bytes::		Reading, manipulating and writing bytes.
* Values and Variables::        Values can be stored in variables.
* From Bytes to Integers::	Building numbers with bytes.
* Big and Little Endians::	Pick your egg.
* Negative Integers::		Going behind 0.
* Weird Integers::		Incomplete bytes in numbers.
* Unaligned Integers::		IO spaces are bit-oriented.
* Integers of Different Sizes:: Promotion of integers in expressions.
* Offsets and Sizes::           United values.
* Buffers as IO Spaces::	Poking memory buffers.
* Copying Bytes::		Moving data between IO spaces.
* Saving Buffers in Files::	From memory to files.
* Character Sets::		ASCII, Unicode, ...
* From Bytes to Characters::	Working with ASCII codes
* ASCII Strings::		NULL-terminated strings.
* From Strings to Characters::	Indexing strings.
* Strings are not Arrays::      Converting between strings and arrays.


File: poke.info,  Node: Binary Files,  Next: Files as IO Spaces,  Up: Basic Editing

3.1 Binary Files
================

GNU poke is an editor for "binary files".  Right, so what is a binary
file?  Strictly speaking, every file in a computer's file system is
binary.  This is because, in a very fundamental level, files are just
sequences of bytes.

   Colloquially, however, it is very common to talk about "binary files"
as opposed to "text files".  In this informal meaning, a text file is
basically a file composed, mostly, of bytes (and byte sequences) that
can be translated into printable characters in some character set, such
as ASCII, EBCDIC or Unicode.  It follows that binary files would then be
files composed, mostly, of bytes not intended to be interpreted as
encoded characters.

   Some text files contain non-printable characters, such as form feed
characters, and many binary files contain printable strings, such as a
string table in an ELF object file.  That is why we used the word
"mostly" in the definitions above.  In practice, however, the
distinction is almost always clear and there is common consensus on
whether a given file format can be considered as a binary format, or
not.

   GNU poke can edit any file, and as we shall see, it provides some
nice features to manipulate sequences of bytes interpreted as character
strings.  However, it is called a "binary editor" because it is
especially designed to be particularly useful editing binary files, in
the sense of the term defined above.

   In this chapter, we will be using ELF object files as the experiment
subject in most of the examples.  ELF files are good for this purpose,
because they are eminently binary, highly structured, and still strings
play a role in them, encoding names of entities like sections and
symbols.  You don't need to have a perfect knowledge of the ELF format
in order to follow the examples, but being familiarized with the concept
of object file formats should surely help.

   Obtaining a simple ELF object file is easy, if you have a C compiler
installed:

     $ echo 'int foo () { return 0; }' | gcc -c -xc -o foo.o -

   The command above compiles a very simple ELF object file that
contains the compiled form of a little dummy function.  This object file
will be our companion for a while, and will be the subject of much
analysis and abuse, as we poke it.


File: poke.info,  Node: Files as IO Spaces,  Next: Dumping File Contents,  Prev: Binary Files,  Up: Basic Editing

3.2 Files as IO Spaces
======================

Now that we have a binary file ('foo.o') it is time to open it with
poke.  There are two ways to do that.

   One way is to pass the name of the file in the poke invocation.  The
program will start, open the file, and present you with the REPL, like
in:

     $ poke foo.o
     [...]
     (poke)

   The other way is to fire up poke without arguments, and then use the
'.file' dot-command to open the file:

     $ poke
     [...]
     (poke) .file foo.o
     The current IOS is now `./foo.o'.
     (poke)

Note how poke replies to the dot-command, stating that the "current IOS"
is now the file we opened.

   You may be wondering, what is this IOS thing?  It is an acronym for
Input/Output Space, often written IO Space.  This is the denomination
used to refer to the entities being edited with poke.  In this case the
IO space being edited is a file, but we will see that is not always the
case: poke can also edit other entities such as memory buffers and
remote block-oriented devices over the network.  For now, let's keep in
mind that IOS, or IO space, refers to the file being edited.

   And why "current"?  GNU poke is capable of editing several files
(more generally, several IO spaces) simultaneously.  At any time, one of
these files is the "current one".  In our case, the current IO space is
the file 'foo.o', since it is the only file poke knows about:

     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #0	FILE	rw	0x00000000#B	0x00000398#B	./foo.o

   The command '.info ios' gives us information about all the IO spaces
that are currently open.  The first column tells us a "tag" that
identifies the IOS. In this example, the tag corresponding to 'foo.o' is
'#0'.  The second column tells us the type of IO space.  The third
column tells us that 'foo.o' allows both reading and writing.  The
fourth column tells us the size of the file, in hexadecimal.

   You may wonder what is that weird suffix '#B'.  It is a unit, and
tells us that the size '0x398' is measured in bytes, i.e.  the size of
'foo.o' is '0x398' bytes (or, in decimal, '920' bytes.)

   Finally, the asterisk character at the left of the entry for 'foo.o'
identifies it as the current IO space.  To see this more clearly, let's
open another file:

     (poke) .file bar.o
     The current IOS is now `./bar.o'.
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #1	FILE	rw	0x00000000#B	0x00000398#B	./bar.o
       #0	FILE	rw	0x00000000#B	0x00000398#B	./foo.o

   Ah, there we have both 'foo.o' and 'bar.o'.  Now the current IO space
(the entry featuring the asterisk at the left) is the file that we just
opened, 'bar.o'.  This is because poke always sets the most recently
open file as the current one.  We can switch back to 'foo.o' using yet
another dot-command, '.ios', which gets an IO space tag as an argument:

     (poke) .ios #0
     The current IOS is now `./foo.o'.
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
       #1	FILE	rw	0x00000000#B	0x00000398#B	./bar.o
     * #0	FILE	rw	0x00000000#B	0x00000398#B	./foo.o

We are back to 'foo.o'.  Since we are not really interested in 'bar.o',
let's close it:

     (poke) .close #1
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #0	FILE	rw	0x00000000#B	0x00000398#B	./foo.o

Awesome.  Now we can focus on 'foo.o''s contents...


File: poke.info,  Node: Dumping File Contents,  Next: Poking Bytes,  Prev: Files as IO Spaces,  Up: Basic Editing

3.3 Dumping File Contents
=========================

Data stored in modern computers, in both volatile memory and persistent
files, is fundamentally a sequence of entities called "bytes".  The
bytes can be addressed by its position in the sequence, starting with
zero:

     +--------+--------+--------+ ... +--------+
     | byte 0 | byte 1 | byte 2 |     | byte N |
     +--------+--------+--------+ ... +--------+

Each byte has capacity to store a little unsigned integer in the range
'0..255'.  Therefore, the IO spaces that we edit with poke (like the
file 'foo.o') can be seen as a sequence of little numbers, like depicted
in the figure above.

   GNU poke provides a command whose purpose is to display the values of
these bytes: 'dump'(1) .  It is called like that because it dumps ranges
of bytes to the terminal, allowing the user to inspect them.

   So let's use our first poke command!  Fire up poke, open the file
'foo.o' as explained above, and execute the 'dump' command:

     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
     00000020: 0102 0000 0000 0000 9801 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............
     00000040: 2564 0a00 0000 0000 0000 0000 0000 0000  %d..............
     00000050: b702 0000 0100 0000 1801 0000 0000 0000  ................
     00000060: 0000 0000 0000 0000 8510 0000 ffff ffff  ................
     00000070: b700 0000 0000 0000 9500 0000 0000 0000  ................
     (poke)

What are we looking at?

   The first line of the output, starting with '76543210', is a "ruler".
It is there to help us to visually determine the location (or offset) of
the data.

   The rest of the lines show the values of the bytes that are stored in
the file, 16 bytes per line.  The first column in these data lines shows
the offset, in hexadecimal and measured in number of bytes, from which
the row of data starts.  For example, the offset of the first byte shown
in the third data line has offset 0x20 in the file, the second byte has
offset 0x21, and so on.  Note how the data rows show the values of the
individual bytes, in hexadecimal.  Generally speaking, when dealing with
bytes (and binary data in general) it is useful to manipulate magnitudes
in hexadecimal, or octal.  This is because it is easy to group digits in
these bases to little groups of bits (four and three respectively) in
the equivalent binary representation.  In this case, each couple of
hexadecimal digits denote the value of a single byte(2).  For example,
the value of the first byte in the third data row is 0x01, the value of
the second byte 0x02, and so on.

   Using the ruler and the column of offsets, locating bytes in the data
is very easy.  Let's say for example we are interested in the byte at
offset 0x68: we use the first column to quickly find the row starting at
0x60, and the ruler to find the column marked with '88'.  Cross column
and row and... voila!  The byte in question has the value 0x85.  The
reverse process is just as easy.  What is the offset of the first 0x40
in the file?  Try it!

   The section at the right of the output is the ASCII output.  It shows
the row of bytes at the left interpreted as ASCII characters.
Non-printable characters are shown as '.' to avoid scrambling the
terminal, and yes, there is actually way to customize what character to
use, so they are not confused from real ASCII dot characters ('0x2e') :P
In this particular dump we can see that near the beginning of the file
there are three bytes whose value, if interpreted as ASCII characters,
conform the string "ELF". As we shall see, this is part of the ELF magic
number.  Again, the ruler is very useful to locate the byte
corresponding to some character in the ASCII section, or the other way
around.  What is the value of the byte corresponding to the 'F' in
'ELF'?  Try it!

   Something to notice in the 'dump' output above is that these are not,
by any mean, the complete contents of the file 'foo.o'.  The '.info ios'
dot-command informed us in the last section that 'foo.o' contains 920
bytes, of which the 'dump' command only showed us... '0x80' bytes, or
'128' bytes in decimal.

   'dump' is certainly capable of showing more (and less) than '128'
bytes.  We can ask 'dump' to display some given amount of data by
specifying its size using a "command argument".  For example:

     (poke) dump :size 64#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
     00000020: 0102 0000 0000 0000 9801 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............

   The command above asks poke to "dump 64 bytes".  In this example
':size' is the name of the argument, and '64#B' is the argument's value.
Again, the suffix '#B' tells poke we want to dump 64 bytes, not 64
kilobits nor 64 potatoes.

   Another interesting aspect of our first dump (ahem) is that the
dumped bytes start from the beginning of the file, i.e.  the offset of
the first byte is 0x0.  Certainly there should be other areas of the
file with interesting contents for us to inspect.  To that purpose, we
can use yet another option, ':from':

     (poke) dump :size 64#B :from 128#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000080: 1400 0000 0000 0000 0000 0000 0000 0000  ................
     00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     000000a0: 0000 0000 0300 0100 0000 0000 0000 0000  ................
     000000b0: 0000 0000 0000 0000 0000 0000 0300 0300  ................

   The command above asks poke to "dump 64 bytes starting at 128 bytes
from the beginning of the file".  Note how the first row of bytes start
at offset '0x80', i.e.  '128' in decimal.

   Passing options to commands is easy and natural, but we may find
ourselves passing the same values again and again to certain command
options.  For example, if the default size of 'dump' of 128 bytes is not
what you prefer, because you have a particularly tall monitor, or you
are one of these people using sub-atomic sized fonts, it can be tiresome
and error-prone to pass ':size' to 'dump' every time you use it.
Fortunately, the default size can be customized by setting a "global
variable":

     (poke) pk_dump_size = 160#B

This tells poke to set '160' bytes as the new value for the
'pk_dump_size' variable.  This is a global variable that the 'dump'
command uses to determine how much data to show if the user doesn't
specify an explicit value with the ':size' option.  Many other commands
use the same strategy in order to alter their default behavior, not just
'dump'.

   And now that we are talking about that, it is also cumbersome to have
to set the default size used by 'dump' every time we run poke.  But no
problem, just set the variable in a file called '.pokerc' in your home
directory, like this:

     pk_dump_size = 160#B

Every time poke starts, it reads '~/.pokerc' and executes the commands
contained in it.  See *note pokerc::.

   The 'dump' command is very flexible, and accepts a lot of options and
customization variables that we won't be covering in this chapter.  For
a complete description of the command, see *note dump::.

   ---------- Footnotes ----------

   (1) Note that this is not a dot-command like '.file', '.ios' or
'.close': 'dump' does not start with a dot!  We will see later how
dot-commands differ from "normal commands" like 'dump', but for now,
let's ignore the distinction.

   (2) Do not be fooled by the fact 'dump' shows the hexadecimal digits
in groups of four: this is just a visual aid and, as we shall see, it is
possible to change the grouping by passing arguments to 'dump'.


File: poke.info,  Node: Poking Bytes,  Next: Values and Variables,  Prev: Dumping File Contents,  Up: Basic Editing

3.4 Poking Bytes
================

Let's look again at the first bytes of the file 'foo.o':

     (poke) dump :size 64#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
     00000020: 0102 0000 0000 0000 9801 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............

   At this point we know how to use the ruler to localize specific bytes
just by looking at the displayed data.  If we wanted to operate on the
values of some given bytes, we could look at the dump and type the
values in the REPL. For example, if we wanted to add the values of the
bytes at offsets 0x2 and 0x4, we could look at the dump and then type:

     (poke) 0x4c + 0x02
     0x4e

   GNU poke supports many operators that take integers as arguments, to
perform arithmetic, relational, logical and bit-wise operations on them
(*note Integers::).  Since bytes are no more (and no less) than little
unsigned integers, we can use these operators to perform calculations on
bytes.

   For example, this is how we would calculate whether the highest bit
in the second byte in 'foo.o' is set:

     (poke) 0x45 & 0x80
     0

Note how booleans are encoded in Poke as integers, 0 meaning false, any
other value meaning true.

   Looking at the output of 'dump' and writing the desired byte value in
the prompt is cumbersome.  Fortunately, there is a much more convenient
way to access the value of a byte, given its offset in the file: it is
called "mapping" a byte value.  This operation is implemented by a
binary operator, called the map operator.

   This is how it works.  Assuming we were interested in the byte at
'64' bytes from the beginning of the file, this is how we would refer to
it (or "map" it):

     (poke) byte @ 64#B
     37UB

This application of the map operator tells poke to map a byte at the
offset 64 bytes.  It can be read as "byte at 64 bytes".  Note how poke
replies with the value 37UB. The suffix 'UB' means "unsigned byte", and
is an indication for the user about the nature of the preceding number:
it is unsigned, and it occupies a byte when stored.

   As we can see in this example, poke uses decimal by default when
showing values in the REPL. We already noted how it is usually better to
work in hexadecimal when dealing with byte values.  Fortunately, we can
change the numeration base used by poke when printing numbers, using the
'.set obase' ("set output base") dot-command as this:

     (poke) .set obase 16

After this, we can map the byte again, this time getting the result
expressed in hexadecimal:

     (poke) byte @ 64#B
     0x25UB

Again, you may find it useful to add the '.set obase 16' command to your
'.pokerc' file, if you want the customization to be persistent between
poke invocations.

   Going back to the example of calculating whether the highest bit in
the second byte in 'foo.o' is set, this is how we would do it with a
map:

     (poke) (byte @ 2#B) & 0x80
     0

Turns out the answer is no.

   The map operator can also be used at the left side of an assignment
operator:

     (poke) byte @ 0x28#B = 0xff

Which reads "assign 0xff to the byte at offset 0x4a bytes".  Dumping
again, we can verify that the byte actually changed:

     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
     00000020: 0102 0000 0000 0000 ff01 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............

Does this mean that 'foo.o' changed accordingly, in disk?  The answer is
yes.  poke always commits changes immediately to the file being edited.
This, that is an useful feature, can also be a bit tricky if you forget
about it, leading to data corruption, so please be careful.

   Incidentally, altering the byte at offset 0x28 most probably have
caused 'foo.o' to stop being a valid ELF file, but since we are just
editing bytes (and not ELF structures) we actually don't care much.


File: poke.info,  Node: Values and Variables,  Next: From Bytes to Integers,  Prev: Poking Bytes,  Up: Basic Editing

3.5 Values and Variables
========================

Up to now we have worked with byte values, either writing them in the
REPL or mapping them at the current IO space.  Often it is useful to
save values under meaningful names, and access to them by name.  In poke
we do that by storing the values in "variables".

   Before being used, variables shall be defined using the 'var'
construction.  Let's get the byte at offset '64' bytes and save it in a
variable called 'foo':

     (poke) var foo = byte @ 64#B

This defines a new variable ('foo') and initializes it to the value of
the byte at offset 64 bytes.  This results on 'foo' to hold the value
37.

   Once defined, we can get the value of a variable by just giving its
name to poke:

     (poke) foo
     37UB

Several variables can be defined in a single 'var' declaration.  Each
definition is separated by a comma.  This is equivalent of issuing
several 'var's:

     (poke) var a = 10, b = 20

In general, a variable containing a byte value can be used in any
context where the contained value would be expected.  If we wanted to
check the highest bit in the byte value stored in 'foo' we would do:

     (poke) foo & 0x80
     0x0

   Assigning a value to a variable makes the value the new contents of
the variable.  For example, we can increase the value of 'foo' by one
like this:

     (poke) foo = foo + 1

   At this point, an important question is: when we change the value of
the variable 'foo', are we also changing the value of the byte stored in
'foo.o' at offset 64 bytes?  The answer is no.  This is because when we
do the mapping:

     (poke) var foo = byte @ 64#B

The value stored in 'foo' is a _copy_ of the value returned by the map
operator '@'.  You can imagine the variable as a storage cell located
somewhere in poke's memory.  After the assignment above is executed
there are two copies of the byte value 0x25: one in 'foo.o' at offset 64
bytes, and the other in the variable 'foo'.

   It follows that if we wanted to increase the byte in the file, we
would need to do something like:

     (poke) var foo = byte @ 64#B
     (poke) foo = foo + 1
     (poke) byte @ 64#B = foo

Or, more succinctly, omitting the usage of a variable:

     (poke) byte @ 64#B = (byte @ 64#B) + 1

Or, even _more_ succinctly:

     (poke) (byte @ 64#B) += 1

Note how we have to use parenthesis around the map at the right hand
side, because the map operator '@' has less precedence than the plus
operator '+'.


File: poke.info,  Node: From Bytes to Integers,  Next: Big and Little Endians,  Prev: Values and Variables,  Up: Basic Editing

3.6 From Bytes to Integers
==========================

The bytes we have been working with are unsigned whole numbers (or
integers) in the range '0..255'.  We saw how poke sees the contents of
the files as a sequence of bytes, and how each byte can be addressed
using an offset.  Mapping bytes using the map operator '@' gives us
these values, which are denoted in poke with literals like '10UB' or
'0x0aUB'.

   This very limited range of values have consequences when it comes to
do arithmetic with bytes.  Suppose for example we wanted to calculate
the average of the first three byte values stored in 'foo.o'.  We could
do something like:

     (poke) a0 = byte @ 0#B
     (poke) a1 = byte @ 1#B
     (poke) a2 = byte @ 2#B
     (poke) a0
     0x7fUB
     (poke) a1
     0x45UB
     (poke) a2
     0x4cUB
     (poke) (a0 + a1 + a2) / 3UB
     5UB

That is obviously the wrong answer.  What happened?  Let's do it step by
step.  First, we add the first two bytes:

     (poke) a0 + a1
     0xc4UB

Which is all right.  0xc4 is 0x7f plus 0x45.  But, let's add now the
third byte:

     (poke) a0 + a1 + a2
     0x10UB

That's no good.  Adding the value of the third byte (0x4c) we overflow
the range of valid values for a byte value.  The calculation went banana
at this point.

   Another obvious problem is that we surely will want to store integers
bigger than 255 in our files.  Clearly we need a way to encode them
somehow, and since all we have in a file are bytes, the integers will
have to be composed of them.

   Integers bigger than 255 can be encoded by interpreting consecutive
byte values in a certain way.  First, let's consider a single byte.  If
we print a byte value using binary rather than decimal or hexadecimal,
we will observe that eight bits are what it takes to encode the numbers
between 0 and 0xff (255) using a "natural binary encoding":

     (poke) .set obase 2
     (poke) 0UB
     0b00000000UB
     (poke) 0xFFUB
     0b11111111UB

   This is the reason why people say bytes are "composed" of eight bits,
or that the width of a byte is eight bits.  But this way of talking
doesn't really reflect the view that the operating system has of devices
like files or memory buffers: both disk and memory controllers provide
and consume bytes, i.e.  little unsigned numbers in the range '0..255'.
At that level, bytes are indivisible.  We will see later that poke
provides ways to work on the "sub-byte" level, but that is just really
an artifact to make our life easier: underneath, all that goes in and
out are bytes.

   Anyhow, if we were to "concatenate" the binary representation of two
consecutive bytes, we would end with a much bigger range of possible
numbers, in the range '0b00000000_00000000..0b11111111_11111111'(1), or
'0x0000..0xffff' in hexadecimal.  poke provides a bit-concatenation
operator ':::' that does exactly that:

     (poke) 0x1UB
     0b00000001UB
     (poke) 0x1UB ::: 0x1UB
     0b0000000100000001UH

Note how the suffix of the resulting number is now 'UH'.  This indicates
that the number is no longer a byte value: it is too big for that.  The
'H' in this new suffix means "half", and it is a traditional way to call
an integer that is encoded using two bytes, or 16 bits.

   So, using our method of encoding bigger numbers concatenating bytes,
what would be the "half" integer composed of two bytes at the beginning
of 'foo.o'?

     (poke) .set obase 16
     (poke) (byte @ 0#B):::(byte @ 1#B)
     0x7f45UH

   Now, let's go back to the syntax we used to map a byte value.  In the
invocation of the map operator 'byte @ 0#B' the operand at the left (in
this case 'byte') tells the operator what kind of value to map.  This is
called a "type specifier"; 'byte' is the type specifier for a single
byte value, and 'byte[3]' is the type specifier for a group of three
byte values arranged in an array.

   As it happens, 'byte' is a synonym for another slightly more
interesting type specifier: 'uint<8>'.  You can probably infer the
meaning already: a byte is an unsigned integer which is 8 bits big.  We
can of course use this alternate specifier in a mapping operation,
achieving exactly the same result than if we were using 'byte':

     (poke) uint<8> @ 0#B
     0x7fUB

   You may be wondering: is it possible to use a similar type specifier
for mapping bigger integers, like these "halves" that are composed of
two bytes?  Yeah, it is indeed possible:

     (poke) uint<16> @ 0#B
     0x7f45UH

Mapping an unsigned integer of 16-bits at the offset 0 gives us an
unsigned "half" value, as expected.

   You can easily build bigger and bigger numbers concatenating more and
more bytes.  Three bytes?  sure:

     (poke) uint<24> @ 0#B
     (uint<24>) 0x7f454c

Note that in this case poke uses a prefix instead of a suffix to
indicate that the given value is 24-bits long.  This is because only a
limited number of suffixes (which are more concise and more readable
than the prefix form) are available, corresponding to common or typical
widths.

   Four bytes?

     (poke) uint<32> @ 0#B
     0x7f454c46U

   Certain integer widths are so often used that easier-to-type synonyms
for their type specifiers are provided.  We already know 'byte' for
'uint<8>'.  Similarly, 'ushort' is a synonym for 'uint<16>', 'uint' is a
synonym for 'uint<32>' and 'ulong' is a synonym for 'uint<64>'.  Try
them!

   GNU poke supports integers up to eight bytes, i.e.  up to 64-bits.
This may change in the future, as we are planning to support arbitrarily
large integers.

   ---------- Footnotes ----------

   (1) poke allows to insert underscore characters '_' anywhere in
number literals.  The only purpose of these characters is to improve
readability, and they are totally ignored by poke, i.e.  they do not
alter the value of the number.


File: poke.info,  Node: Big and Little Endians,  Next: Negative Integers,  Prev: From Bytes to Integers,  Up: Basic Editing

3.7 Big and Little Endians
==========================

When talking about whole numbers (integers) we should distinguish
between their value (such as 123) and their "written form" that we would
use when writing the number on a piece of paper, such as '123'.

   The written form of a number is composed of digits, arranged in
certain order.  We all know that the ordering of the digits in the
written form of a number is important: if we write '123' we are
referring to a different value than if we write '321'.  The mathematical
reason for this is that depending on the position they occupy in the
written form, each digit contributes with a different "weight" to the
total value of the number.  This is always the case, regardless of the
numerical base used to denote the number.

   For example, the value of the number 123 (whose written form is
'123') is calculated as '1*10^2+2*10^1+3*10^0'.  If we swap the last two
digits in the written form of the number, '132', we have
'1*10^2+3*10^1+2*10^0', which results in a different value: 132.  When
we consider other numerical bases, the bases in the polynomial change
accordingly, but the correspondence between written form and value
stands: for example, the value of 0x123 is calculated as
'1*16^2+2*16^1+3*16^0'.

   The "higher" a digit is in the polynomial, the "more significant" it
is, i.e.  the more weight it has on the value of the number where it
appears.  In the written number '123', for example, the digit 1 is the
"most significant" digit of the number, and the digit 3 is the "least
significant" digit.

   This distinction between the written form of a number and its value
is very important.  Just like in certain languages letters are read
right-to-left (Arabic) or even down-to-up (Japanese) we could certainly
conceive a language in which the digits of numbers were arranged from
right-to-left instead of left-to-right.  In such a language the written
representation of 123 would be '321', not '123'.  In other words: the
least significant digit would come first, not last, in the written form
of the number.

   Now when it comes to store numbers in computers, rather than writing
them on a paper, the role of the paper is played by the computer's
memory, be it ephemeral (like RAM) or persistent (like a spinning hard
disk or a Flash memory), which is organized as a sequence of bytes.
Since we are composing numbers with bytes, it makes sense to have each
byte to play the role of a digit in the written form of the bigger
number.  Since bytes can have values from 0 to 255, the base is 256.
But what is the "written form" for our byte-composed numbers?

   In the last section we tried to compose bigger integers by
concatenating bytes together and interpreting the result.  In doing so,
we assumed (quite naturally) that in the written form of the resulting
integer the bytes are ordered in the same order than they appear in the
file, i.e.  we assume that the written form of the number
'b1*256^2+b2*256^1+b3*256^0' would be 'b1b2b3', where 'b1', 'b2' and
'b3' are bytes.  In other words, given a written form 'b1b2b3', 'b1'
would be the most significant byte (digit) and 'b3' would be the least
significant byte (digit).  In our world of IO spaces, the "written form"
is the disposition of the bytes in the IO space (file, memory buffer,
etc) being edited.

   That interpretation of the written form is exactly what the
bit-concatenation operator implements:

     (poke) dump :from 0#B :size 3#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c                                  .EL
     (poke) var b1 = byte @ 0#B
     (poke) var b2 = byte @ 1#B
     (poke) var b3 = byte @ 2#B
     (poke) b1:::b2:::b3
     (uint<24>) 0x7f454c

   However, much like in certain human languages the written form is
read from right to left, some computers also read numbers from right to
left in their "written form".  Actually, turns out that _most_ modern
computers do it like that.  This means that, in these computers, given
the written form 'b1b2b3' (i.e.  given a file where 'b1' comes first,
followed by 'b2' and then 'b3') the most significant byte is 'b3' and
the least significant byte is 'b1'.  Therefore, the value of the number
would be 'b3*256^2+b2*256^1+b3*256^0'.

   So, given the written form of a bigger number 'b1b2b3' (i.e.  some
ordering of bytes implied by the file they are stored in) there are at
least two ways to interpret them to calculate the value of the number.
When the written form is read from left to right, we talk about a "big
endian" interpretation.  When the written form is read from right to
left, we talk about a "little endian" interpretation.

   Given the first three bytes in 'foo.o', we can determine the value of
the integer composed of these three bytes in both interpretations:

     (poke) b1:::b2:::b3
     (uint<24>) 0x7f454c
     (poke) b3:::b2:::b1
     (uint<24>) 0x4c457f

   Remember how the type specifier 'byte' is just a synonym of
'uint<8>', and how we can use type specifiers like 'uint<24>' and
'uint<32>' to map bigger integers?  When we do that, like in:

     (poke) uint<24> @ 0#B
     (uint<24>) 0x7f454c

Poke should somehow decide what kind of interpretation to use, i.e.  how
to read the "written form" of the number.  As you can see from the
example, poke uses the left-to-right interpretation, or big-endian, by
default.  But you can change it using a new dot-command: '.set endian':

     (poke) .set endian little
     (poke) uint<24> @ 0#B
     (uint<24>) 0x4c457f

   The currently used interpretation (also called "endianness") is shown
if you invoke the dot-command without an argument(1):

     (poke) .set endian
     little

   Different systems use different endianness.  Into a given system, it
is to be expected that most files will be encoded following the same
conventions.  Therefore poke provides you a way to set the endianness to
whatever endianness is in the system.  You do it this way:

     (poke) .set endian host

   ---------- Footnotes ----------

   (1) This also applies to the other '.set' commands


File: poke.info,  Node: Negative Integers,  Next: Weird Integers,  Prev: Big and Little Endians,  Up: Basic Editing

3.8 Negative Integers
=====================

3.8.1 Negative Encodings
------------------------

Up to this point we have worked with unsigned integers, i.e.  whole
numbers which are zero or bigger than zero.  Much like it happened with
endianness, the interpretation of the value of several bytes as a
negative number depends on the specific interpretation.

   In computing there are two main ways to interpret the values of a
group of bytes as a negative number: "one's complement" and "two's
complement".

   At the moment GNU poke supports the two complement interpretation,
which is really ubiquitous and is the negative encoding used by the vast
majority of modern computers and operating systems.

   We may consider adding support for one's complement in the future,
but only if there are real needs that would justify the effort (which
wouldn't be a small one ;)).

3.8.2 Signed Integers
---------------------

Unsigned values are never negative.  For example:

     (poke) 0UB - 1UB
     0xffUB

Instead of getting a -1, we get the result of an unsigned underflow,
which is the biggest possible value for an unsigned integer of size 8
bits: 0xff.

   When using type specifiers like 'uint<8>' or 'uint<16>' in a map, we
get unsigned values such as 0UB. We need other type specifiers to map
signed values.  These look like 'int<8>' and 'int<16>'.

   For example, let's map a signed 16-bit value from 'foo.o':

     (poke) .set obase 10
     (poke) int<16> @ 0#B
     28515H

Note how the suffix of the value is now 'H' and not 'UH'.  This means
that the value is signed!  But in this case the mapped integer is still
positive, so let's try to get an actual negative value:

     (poke) var h = int<16> @ 0#B
     (poke) h - h - 1H
     -1H

3.8.3 Mixing Signed and Unsigned Integers
-----------------------------------------

Adding two signed integers gives you a signed integer:

     (poke) 1 + 2
     3

Likewise, adding two unsigned integers results in an unsigned integer:

     (poke) 1U + 2U
     3U

But, what happens if we mix signed and unsigned values in an expression?
Is the result signed, or unsigned?  Let's find out:

     (poke) 1U + 2
     3U

Looks like combining an unsigned value with a signed value gives us an
unsigned value.  This actually applies to all the operators that work on
integer values: multiplication, division, exponentiation, etc.

   What actually happens is that the signed operand is converted to an
unsigned value before executing the expression.  You can also convert
signed values into unsigned values (and vice-versa) using "cast
constructions":

     (poke) 2 as uint<32>
     2U

Therefore, the expression '1U + 2' is equivalent to '1U + 2 as
uint<32>':

     (poke) 1U + 2 as uint<32>
     3U

   You may be wondering: why not doing it the other way around?  Why not
converting the unsigned operand into a signed value and then operate?
The reason is that, given an integer of some particular size, the
positive range that you can store in it is bigger when interpreted as an
unsigned integer than when interpreted as a signed integer.  Therefore,
converting signed into unsigned before operating reduces the risk of
positive overflow, which by the way is not allowed in poke.  This of
course assumes that we, as users, will be working with positive numbers
more often than with negative numbers, but that is a reasonable
assumption to do, as it is often the case!


File: poke.info,  Node: Weird Integers,  Next: Unaligned Integers,  Prev: Negative Integers,  Up: Basic Editing

3.9 Weird Integers
==================

Up to this point we have been playing with integers that are built using
a whole number of bytes.  However, we have seen that the type specifier
for an integer has the form 'int<N>' or 'uint<N>' for signed and
unsigned variants, where 'N' is the width of the integer, in bits.  We
have used bit-sizes that are multiple of 8, which is the size of a byte.
So, why is this so?  Why is 'N' not measured in bytes instead?

   The reason is that poke is not limited to integers composed of a
whole number of bytes.  You can actually have integers composed of _any_
number of bits, between 1 and 64.  So yes, 'int<3>' is a type specifier
for signed 3-bit integers, and 'uint<17>' is a type specifier for
unsigned 17-bit integers.

   We call integers like this "weird integers".

   The vast majority of programming languages do not provide any support
for weird integers.  In the few cases they do, it is often in a very
limited and specific way, like bitmap fields in C structs.  Such
constructions are often vague, obscure, and often their semantics depend
on the specific implementation of the language, and/or the
characteristics of the system where you run your program.

   In poke, on the contrary, weird numbers are first class citizens, and
they don't differ in any way from "normal" integers which are composed
of a whole number of bytes.  Their interpretation is also well defined,
and they keep the same semantics regardless of the characteristics of
the computer on which poke is running.

3.9.1 Incomplete Bytes
----------------------

Let's consider first weird numbers that span for more than one byte.
For example, an unsigned integer of 12 bits.  Let's visualize the
written form of this number, i.e.  the sequence of its constituent bytes
as they appear in the underlying IO space:

       byte 0  |  byte 1
     +---------+----+----+
     |::::::::::::::|    |
     +---------+----+----+
     |   uint<12>   |

All right, the first byte is used in its entirely, but only half of the
second byte is used to conform the value of the number.  The other half
of the second byte has no influence of the value of the 12 bits number.

   Now, we talk about the "second half of the byte", but what do that
means exactly?  We know that bytes in memory and files (bytes in IO
spaces) are indivisible at the system level: bytes are read and written
one at a time, as little integers in the range '0..255'.  However, we
can create the useful fiction that each byte is composed by "bits",
which are the digits in the binary representation of the byte value.

   So, we can look at a byte as composed of a group of eight bits, like
this:

                byte
     +-------------------------+
     | b7 b6 b5 b4 b3 b2 b1 b0 |
     +-------------------------+

Note how we decided to number the bits in descending order from left to
right.  This is because these bits correspond to the base of the
polynomial equivalent to the binary value of the byte, i.e.  the value
of the byte is
'b7*2^7+b6*2^6+b5*2^5+b4*2^4+b3*2^3+b2*2^2+b1*2^1+b0*2^0'.  In other
words: at the bit level poke always uses a big endian interpretation,
and the bit that "comes first" in this imaginary stream of bits is the
most significant bit in the binary representation of the number.  Please
note that this is just a convention imposed by the poke authors: the
opposite could have been chosen, but it would have been a bit confusing,
as we would have to picture binary numbers in reverse order!

   With this new way of looking at bytes, we can now visualize what we
mean exactly with the "first half" and "second half" of the trailing
byte, in our 12 bits unsigned number:

                byte 0         |           byte 1
     +-------------------------+-------------+-------------+
     | a7 a6 a5 a4 a3 a2 a1 a0   b7 b6 b5 b4 :             |
     +-------------------------+-------------+-------------+
     |                uint<12>               |

Thus the first half of 'byte 1' is the sequence of bits 'b7 b6 b5 b4'.
The second half, which is not pictured since it doesn't contribute to
the value of the number, would be 'b3 b2 b1 b0'.

   So what would be the value of the 12-bit integer?  Exactly like with
non-weird numbers, this depends on the current selected endianness,
which determines the ordering of bytes.

   If the current endianness is big, then 'byte 0' provides the most
significant bits of the result number, and the used portion of 'byte 1'
provides the least significant bits of the result number:

     0b a7 a6 a5 a4 a3 a2 a1 a0 b7 b6 b5 b4

However, if the current selected endianness is little, then the used
portion of 'byte 1' provides the most significant bits of the result
number, and 'byte 0' provides the least significant bits of the result
number:

     0b b7 b6 b5 b4 a7 a6 a5 a4 a3 a2 a1 a0

   Let's see this in action.  Let's take a look to the value of the
first two bytes in 'foo.o', in binary:

     (poke) .set obase 2
     (poke) byte @ 0#B
     0b01111111UB
     (poke) byte @ 1#B
     0b01000101UB

Looking at these bytes as sequences of bits, we have:

             byte @ 0#B       |        byte @ 1#B
     +-------------------------+-------------+-------------+
     |  0  1  1  1  1  1  1  1    0  1  0  0 :  0  1  0  1
     +-------------------------+-------------+-------------+
     |                uint<12>               |

Let's map our weird number at offset 0 bytes, using big endian:

     (poke) .set endian big
     (poke) uint<12> @ 0#B
     (uint<12>) 0b011111110100

That matches what we explained before: the most significant bits of the
unsigned 12 bits number come from the byte at offset 0, i.e.
'01111111', whereas the least significant bits come from the byte at
offset 1, i.e.  '0100'.

   Now let's map it using little endian:

     (poke) uint<12> @ 0#B
     (uint<12>) 0b010001111111

This time the most significant bits of the unsigned 12 bits number come
from the byte at offset 1, i.e.  '0100', whereas the least significant
bits come from the byte at offset 0, i.e.  '01111111'.

   An important thing to note is that non-weird numbers, i.e.  numbers
built with a whole number of bytes, are basically a particular case of
weird numbers where the last byte in the written form (in the IO space)
provides all its bits.  The rules are exactly the same in all cases,
which makes it easy to obtain predictable and natural results when
building integers using poke.

3.9.2 Quantum Bytenics
----------------------

The second kind of weird numbers are integers using less than 8 bits.
These "sub-byte" numbers do not use all the bits of their containing
byte.  Consider for example the written form of an unsigned integer of
size 5 bits:

         byte
     +-----+----+
     |:::::|    |
     +-----+----+
     uint<5>

Now let's view the byte as a sequence of bits:

                  byte
     +----------------+----------+
     | b7 b6 b5 b4 b3 |          |
     +----------------+----------+
     |    uint<5>     |

What is the value of this number?  Applying the general rules for
building integers from bytes, we can easily see that regardless of the
current endianness the value, in binary, is:

     0b b7 b6 b5 b4 b3

   Let's see this in poke:

     (poke) .set obase 2
     (poke) .set endian big
     (poke) byte @ 0#B
     0b01111111UB
     (poke) uint<5> @ 0#B
     (uint<5>) 0b01111
     (poke) .set endian little
     (poke) uint<5> @ 0#B
     (uint<5>) 0b01111

3.9.3 Signed Weird Numbers
--------------------------

In the section discussing negative integers, we saw how the difference
between a signed number and an unsigned number is basically a different
interpretation of the most significant bit.  Exactly the same applies to
weird numbers.

   Let's summon our unsigned 12-bit integer at the beginning of the file
'foo.o':

     (poke) .set endian big
     (poke) uint<12> @ 0#B
     (uint<12>) 0b011111110100

The most significant bit of the resulting value (not of its written
form) indicates that this number would be positive if we were mapping
the corresponding signed value.  Let's see:

     (poke) int<12> @ 0#B
     (int<12>) 0b010001111111
     (poke) .set obase 10
     (poke) int<12> @ 0#B
     (int<12>) 1151

   Let's make it a bit more interesting, and change the value of the
first byte in the file so we get a negative number:

     (poke) .set obase 2
     (poke) byte @ 0#B = 0b1111_1111
     (poke) int<12> @ 0#B
     (int<12>) 0b111111110100
     (poke) .set obase 10
     (poke) int<12> @ 0#B
     (int<12>) -12

Now, let's switch to little endian:

     (poke) .set endian little
     (poke) .set obase 2
     (poke) int<12> @ 0#B
     (int<12>) 0b010011111111
     (poke) .set obase 10
     (poke) int<12>  0#B
     (int<12>) 1279


File: poke.info,  Node: Unaligned Integers,  Next: Integers of Different Sizes,  Prev: Weird Integers,  Up: Basic Editing

3.10 Unaligned Integers
=======================

We have mentioned above that the data stored in computers, that we edit
with poke, is arranged as a sequence of bytes.  The entities we edit
with poke (that we call "IO devices") are presented to us as IO spaces.
Up to now, we have accessed this IO space in terms of bytes, in commands
like 'dump :from 32#B' and in expressions like '2UB + byte @ 0#B'.  We
said that mapped integers are built from bytes read from the IO space.

   However, the IO space that poke offers to us is actually a space of
bits, not a space of bytes, and the poke values are mapped on this space
of bits.  The following figure shows this:

     poke values      |        uint<16> @ 2#b        |
     -----------      |                               |
     IO space     |b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|
     -----------  |               |               |               |
     IO device    |     byte0     |     byte1     |     byte2     |

The main consequence of this, that you can see in the figure above, is
that we can use offsets in mapping operations that are not "aligned to
bytes".  You can specify an offset in bits, instead of bytes, using the
'#b' suffix instead of '#B'.  Little 'b' means bits, and big 'B' means
bytes.

   Let's map an unaligned 16 bit unsigned integer in 'foo.o':

     (poke) dump :from 0#B :size 3#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c                                  .EL
     (poke) .set obase 2
     (poke) byte @ 0#B
     0b01111111UB
     (poke) byte @ 1#B
     0b01000101UB
     (poke) byte @ 2#B
     0b01001100UB
     (poke) .set endian big
     (poke) uint<16> @ 2#b
     0b1111110100010101UH

   Graphically:

     poke values      |        uint<16> @ 2#b        |
     -----------      |                               |
     IO space     |0|1|1|1|1|1|1|1|0|1|0|0|0|1|0|1|0|1|0|0|1|1|0|0|
     -----------  |               |               |               |
     IO device    |     0x7f      |      0x45     |      0x4c     |

   These three levels of abstractions make it very easy and natural to
work with unaligned data.  Imagine for example that you are poking
packages in a network protocol that is bit-oriented.  This means that
the packages will generally not be aligned to byte boundaries, but still
the payload stored in the packages contains integers of several sizes.
Other conventional binary editors or programming languages, that are
almost always byte oriented, would require us to "unpack" the network
data to a different, byte oriented, representation before messing with
it.  poke, on the contrary, allows you to directly map these integers as
if they were aligned to byte boundaries, and work with them.

   However, when one tries to determine the correspondence between a
given poke value and the underlying bytes in the IO device, things can
get complicated.  This is particularly true when we map what we called
"weird numbers", i.e.  numbers with partial bytes.  As we saw, the rules
to build these numbers were expressed in terms of bytes.

   In order to ease the visualization of the process used to build
integer values (especially if they are weird numbers, i.e.  integers
with partial bytes) one can imagine an additional layer of "virtual
bytes" above the space of bits provided by the IO space.  Graphically:

     poke values       |        uint<16> @ 2#b        |
     -----------       |                               |
     Virtual bytes     | virt. byte1   |  virt. byte2  |
     -----------       |               |               |
     IO space      |0|1|1|1|1|1|1|1|0|1|0|0|0|1|0|1|0|1|0|0|1|1|0|0|
     -----------   |               |               |               |
     IO device     |     0x7f      |      0x45     |      0x4c     |

   It is very important to understand that the IO space is an
abstraction provided by poke.  The underlying file, or memory buffer, or
whatever, is actually a sequence of bytes; poke translates the
operations on integers, bits, bytes, etc into the corresponding byte
operations, and this translation is far from trivial.  Fortunately, we
can let poke do the dirty job for us, and abstract ourselves from that
complexity.


File: poke.info,  Node: Integers of Different Sizes,  Next: Offsets and Sizes,  Prev: Unaligned Integers,  Up: Basic Editing

3.11 Integers of Different Sizes
================================

When integer values of different sizes are passed to an arithmetic or
relational operator, the "smaller" operand gets converted into the size
of the "bigger" operand.  For example:

     (poke) 1H + 2
     3

The operands are of size 16-bit and 32-bit respectively, and the result
is a 32-bit integer.  This is equivalent to:

     (poke) 1H as int<32> + 2
     3


File: poke.info,  Node: Offsets and Sizes,  Next: Buffers as IO Spaces,  Prev: Integers of Different Sizes,  Up: Basic Editing

3.12 Offsets and Sizes
======================

Early in the design of what is becoming GNU poke I was struck by a
problem that, to my surprise, would prove not easy to fix in a
satisfactory way: would I make a byte-oriented program, or a
bit-oriented program?  Considering that the program in question was
nothing less than an editor for binary data, this was no petty dilemma.

   Since the very beginning I had a pretty clear idea of what I wanted
to achieve: a binary editor that would be capable of editing user
defined data structures, besides mere bytes and bits.  I also knew I
needed some sort of domain specific language to describe these
structures and operate on them.  How that language would look like, and
what kind of abstractions it would provide, however, was not clear to
me.  Not at all.

   So once I sketched an initial language design, barely something very
similar to C structs, I was determined to not continue with the poke
implementation until I had described as many as binary formats in my
language as possible.  That, I reckoned, was the only way to make sure
the implemented language would be expressive, complete and useful enough
to fulfil my requirements.

   The first formats I implemented using my immature little language
included ELF, FLV, MP3, BSON... all of them describing structures based
on whole bytes.  Even when they try to be compact, it is always by
packing bit-fields in elements that are, invariably, sized as a multiple
of bytes.  Consequently, the language I was evolving became byte
oriented as well.  No doubt also influenced by my C inheritance, I would
think of bit-fields either as a sort of second class citizen, or as mere
results of shifting and masking.

   This worked well.  The language evolved to be able to express many
different aspects of these formats in a very nice way, like
variable-length data and holes in structures.

   Consider the following definition, which is *not* valid in today's
Poke:

     type Data =
       struct
       {
         byte magic;
         byte count;
         byte dstart;

         byte[count] data @ dstart;
       };

   The data starts with a byte that is a magic number.  Then the size of
the data stored, in bytes, and then the data itself.  This data,
however, doesn't start right after 'dstart': it starts at 'dstart',
which is expressed as an offset, in bytes, since the beginning of the
Data.  I conceived struct field labels to be any expression evaluating
to an integer, which would be interpreted as a number of bytes,
obviously.

   Then, one day, it was the turn for IETF RFC1951, which is the
specification of the DEFLATE algorithm and associated file format.  Oh
dear.  Near the beginning of the spec document it can be read:

     This document does not address the issue of the order in which bits
     of a byte are transmitted on a bit-sequential medium, since the
     final data format described here is byte- rather than bit-oriented.
     However, we describe the compressed block format in below, as a
     sequence of data elements of various bit lengths, not a sequence of
     bytes.

   Then it goes on describing rules to pack the DEFLATE elements into
bytes.  I was appalled, and certainly sort of deflated as well.  The
purpose of my program was precisely to edit binary in terms of the data
elements described by a format.  And in this case, these data elements
came in all sort of bit lengths and alignments.  This can be seen in the
following RFC1951 excerpt, that describes the header of a compressed
block:

     Each block of compressed data begins with 3 header bits containing
     the following data:
          first bit       BFINAL
          next 2 bits     BTYPE

     Note that the header bits do not necessarily begin on a byte
     boundary, since a block does not necessarily occupy an integral
     number of bytes.

   At this point I understood that my little language on the works would
never be capable to describe the DEFLATE structures naturally: C-like
bit-fields, masking and shifting, all based on byte-oriented containers
and boundaries, would never provide the slickness I wanted for my
editor.  I mean, just use C and get done with it.

   This pissed me off.  Undoubtedly other formats and protocols would be
impacted in a similar way.  Even when most formats are byte oriented,
what am I supposed to tell to the people hacking bit-oriented stuff?
"Sorry pal, this is not supported, this program is not for you"?  No
way, I thought, not on my watch.

   The obvious solution for the problem, is to be general.  In this
case, to express every offset and every memory size in bits instead of
bytes.  While this obviously gives the language maximum expressiveness
power, and is ideal for expressing the few bit-oriented formats, it has
the disadvantage of being very inconvenient for most situations.

   To see how annoying this is, let's revisit the little 'BitData'
structure we saw above.  In a bit-oriented description language, we
would need to write something like:

     type BitData =
       struct
       {
         byte magic;
         byte count;
         byte dstart;

         byte[count] data @ dstart * 8;
       };

   Yeah... exactly.  The <*> and <8> keys in the keyboards of the poke
users would wear out very fast, not to mention their patience as well.
Also, should I provide both 'sizeof' and 'bitsizeof' operators?  Nasty.

   I am very fond of the maxim "Never write a program you would never
use yourself"(1), so I resigned myself to make GNU poke byte oriented,
and to provide as many facilities for operating on bit-fields as
possible.

Fortunately, I have smart friends...

   During one of the Rabbit Herd's Hacking Weekends(2) I shared my
frustration and struggle with the other rabbits, and we came to realize
that offsets and data sizes in Poke should not be pure magnitudes or
mere integer values: they should be united.  They should have units.

   It makes full sense when you come to think about it.  For a program
like poke, it is only natural to talk about different memory units, like
bits, bytes, kilobytes, megabits, and so on.  Bits and bytes are just
two common units.

   The syntax that we eventually used to denote united values is to
specify the "magnitude" part, a dash (''#'' character, and then the
"unit".  For example, the size "three bytes" is expressed as '3#B', and
"three bits" as '3#b'.

   Apart from allowing me to express values in different units, this
approach also has other benefits as we will see shortly.

   I'm really grateful to Bruno Haible, Luca Saiu and Nacho Gonzalez for
putting me on the right track.

   ---------- Footnotes ----------

   (1) Actually it is Lord Vetinari's "Never build a dungeon you can't
get out of."  but the point is the same.

   (2) <http://www.jemarch.net/rhhw>


File: poke.info,  Node: Buffers as IO Spaces,  Next: Copying Bytes,  Prev: Offsets and Sizes,  Up: Basic Editing

3.13 Buffers as IO Spaces
=========================

We have mentioned already that files are not the only entities that can
be edited using poke.  Remember the dot-command '.file' that opened a
file as an IO space?

     (poke) .file foo.o
     The current IOS is now `./foo.o'.
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #0	FILE	rw	0x00000000#B	0x000004c8#B	./foo.o

Memory buffers can be created using a similar dot-command, '.mem':

     (poke) .mem foo
     The current IOS is now `*foo*'.
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #1	MEMORY		0x00000000#B	0x00001000#B    *foo*
       #0	FILE	rw	0x00000000#B	0x000004c8#B    ./foo.o

   Note how the name of the buffer is built by prepending and appending
asterisks.  Therefore, the name of the buffer created by the command
'.mem foo' is '*foo*'.  Note also that the new buffer is created with a
default size of 0x1000 bytes, or 4096 bytes.  The contents of the buffer
are zeroed:

     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

   Memory buffer IO spaces grow automatically when a value is mapped
beyond their current size.  This is very useful when populating newly
created buffers.  However, for security reasons, there is a limit: the
IO spaces are only allow to grow 4096 bytes at a time.

   When it comes to map values, there is absolutely no difference
between an IO space backed by a file and an IO space backed by a memory
buffer.  Exactly the same rules apply in both cases.


File: poke.info,  Node: Copying Bytes,  Next: Saving Buffers in Files,  Prev: Buffers as IO Spaces,  Up: Basic Editing

3.14 Copying Bytes
==================

Memory buffer IO spaces are cheap, and they are often used as "scratch"
areas.

   Suppose for example we want to experiment with the ELF header of
'foo.o'.  We could open it in poke:

     (poke) .file foo.o
     The current IOS is now `./foo.o'.

The header of an ELF file comprises the first 64 bytes in the file:

     (poke) dump :size 64#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 3e00 0100 0000 0000 0000 0000 0000  ..>.............
     00000020: 0000 0000 0000 0000 0802 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0b00 0a00  ..............

   We know that as soon as we poke something on an IO space, the
underlying file is immediately modified.  So if we start playing with
'foo.o''s header, we may corrupt the file.  We could of course make a
copy of 'foo.o' and work on the copy, but it is much better to create a
memory IO space and copy the ELF header there:

     (poke) .mem scratch
     The current IOS is now `*scratch*'.
     (poke) copy :from_ios 0 :from 0#B :size 64#B
     (poke) dump :size 64#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
     00000010: 0100 3e00 0100 0000 0000 0000 0000 0000  ..>.............
     00000020: 0000 0000 0000 0000 0802 0000 0000 0000  ................
     00000030: 0000 0000 4000 0000 0000 4000 0b00 0a00  ..............

The command 'copy' above copies 64 bytes starting at byte 0 from the IO
with id 0 (the file 'foo.o') to the current IO space (the buffer
'*scratch*').

   Once we are done working with the copy of the ELF header, and
satisfied, we can copy it back to the file and close the memory IO
space:

     (poke) copy :from 0#B :size 64#B :to_ios 0
     (poke) .close
     The current IOS is now `./foo.o'.

Note how the command arguments ':from_ios' and ':to_ios' are assumed to
be the current IO space if they are not explicitly specified in the
command invocation.  For detailed information on the 'copy' command, see
*note copy::.


File: poke.info,  Node: Saving Buffers in Files,  Next: Character Sets,  Prev: Copying Bytes,  Up: Basic Editing

3.15 Saving Buffers in Files
============================

Another useful command when working with buffer IO spaces (and in
general, with any IO space) is 'save'.  Let's say we want to save a copy
of the header of an ELF file in another file.  We could do it the
pokeish way:

     $ poke foo.o
     [...]
     (poke) save :from 0#B :size 64#B :file "header.dat"

The command above saves the first 64 bytes in the current IO space
(which is backed by the file 'foo.o') into a new file 'header.dat' in
the current working directory.

   Let's now consider again the scenario where we are using a memory IO
space as a scratch area.  It is late in the night and we are tired, so
we would like to save the contents of the scratch buffer to a file, so
we can continue our work tomorrow.  This is how we would do that:

     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #1	MEMORY		0x00000000#B	0x00001000#B    *scratch*
       #0	FILE	rw	0x00000000#B	0x000f4241#B    ./foo.o
     (poke) save :from 0#B :size iosize (1) :file "scratch.dat"

Here we used the built-in function 'iosize', that given an IO space
identifier returns its size.


File: poke.info,  Node: Character Sets,  Next: From Bytes to Characters,  Prev: Saving Buffers in Files,  Up: Basic Editing

3.16 Character Sets
===================

Computers understand text as a sequence of "codes", which are numbers
identifying some particular "character".  A character can represent
things like letters, digits, ideograms, word separators, religious
symbols, etc.  Collections of character codes are called "character
sets".

   Some character sets try to cover one or a few similar written
languages.  This is the case of ASCII and ISO Latin-1, for example.
These character sets are small, i.e.  just a few hundred codes.

   Other character sets are much more ambitious.  This is the case of
Unicode, that tries to cover the entire totality of human languages in
the globe, including the fictitious ones, like klingon.  Unicode is a
really big character set.

   In order to store character codes in a computer's memory, or a file,
we need to "encode" each character code in one or more bytes.  The
number of bytes needed to encode a given character code depends on the
range of codes in the containing set.

   ASCII, for example, defines 128 character codes: a single byte is
enough to encode every possible ASCII character.  It is very easy to
encode ASCII.

   Unicode, on the contrary, defines many thousand of character codes,
and has room for many more: we would need 31 bits in order to encode any
conceivable Unicode character code.  However, it would be wasteful to
use that many bits per character: most used character codes tend to be
in lower regions of the code space.  For example, the code corresponding
to the Latin letter ''a'' is a fairly small number, whereas the codes
corresponding to the Klingon alphabet are really big numbers.
Consequently, some systems opt to just encode a subset of Unicode, like
the first 16 bits of the Unicode space, which is called the Basic
Multilingual Plane, and contains all the characters that most people
will ever need.  There are also variable-length encodings of Unicode,
that try to use as less bytes as possible to encode any given code.  A
particularly clever encoding of Unicode, designed by Rob Pike, is
backwards compatible with the ASCII encoding, i.e.  it encodes all the
ASCII codes in one byte each, and the values of these byte are the same
than in ASCII. This clever encoding is called UTF-8.


File: poke.info,  Node: From Bytes to Characters,  Next: ASCII Strings,  Prev: Character Sets,  Up: Basic Editing

3.17 From Bytes to Characters
=============================

3.17.1 Character Literals
-------------------------

poke has built-in support for ASCII, and its simple encoding: each ASCII
code is encoded using one byte.  Let's see:

     (poke) 'a'
     0x61UB

We presented poke with the character 'a', and it answered with its
corresponding code in the ASCII character set, which is 0x61.  In fact,
'a' and 0x61UB are just two ways to write exactly the same byte value in
poke:

     (poke) 'a' == 0x61UB
     1
     (poke) 'a' + 1
     0x62U

   In order to make this more explicit, poke provides yet another
synonym for the type specifier 'uint<8>': 'char'.

3.17.2 Classifying Characters
-----------------------------

When working with characters it is very useful to have some acquaintance
of the ASCII character set, which is designed in a very clever way with
the goal of easing certain code calculations.  See *note Table of ASCII
Codes:: for a table of ASCII codes in different numeration bases.

   Consider for example the problem of determining whether a byte we map
from an IO space is a digit.  Looking at the ASCI table, we observe that
digits all have consecutive codes, so we can do:

     (poke) var b = byte @ 23#B
     (poke) b >= '0' && b <= '9'
     1

   Now that we know that 'b' is a digit, how could we calculate its
digit value?  If we look at the ASCII table again, we will find that the
character codes for digits are not only consecutive: they are also
ordered in ascending order '0', '1', ... Therefore, we can do:

     (poke) b
     0x37UB
     (poke) b - '0'
     7UB

'b' contains the ASCII code 0x37UB, which corresponds to the character
'7', which is a digit.

   How would we check whether 'b' is a letter?  Looking at the ASCII
table, we find that lower-case letters are encoded consecutively, and
the same applies to upper-case letters.  This leads to repeat the trick
again:

     (poke) (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')
     0

3.17.3 Non-printable Characters
-------------------------------

Not all ASCII code are printable using the glyph that are usually
supported in terminals.  If you look at the table in *note Table of
ASCII Codes::, you will find codes for characters described as "start of
text", "vertical tab", and so on.

   These character codes, which are commonly known as "non-printable
characters", can be represented in poke using its octal code:

     (poke) '\002'
     0x2UB

This is of course no different than using '2UB' directly, but in some
contexts the "character like" notation may be desirable, to stress the
fact that the byte value is used as an ASCII character.

   Some of the non-printable characters also have alternative notations.
This includes new-line and horizontal tab:

     (poke) '\n'
     0xaUB
     (poke) '\t'
     0x9UB

These '\' constructions in character literals are called "escape
sequences".  See *note Characters:: for a complete list of allowed
escapes in character literals.


File: poke.info,  Node: ASCII Strings,  Next: From Strings to Characters,  Prev: From Bytes to Characters,  Up: Basic Editing

3.18 ASCII Strings
==================

3.18.1 String Values
--------------------

Now that we know how to manipulate ASCII codes in poke, we may wonder
how can we combine them to conform words or, more generally, "strings"
of ASCII characters.

   GNU poke has support for native ASCII string values.  The characters
conforming the string are written between '"' and '"' characters, like
in:

     (poke) "word"
     "word"

Note, and this is important, that string values are as atomic as integer
values: they are not really composite values.  The fact that '"word"'
contains an 'r' at position 3 is like the fact that the value '123'
contains a digit '2' at position 2.

   Like in character literals, poke strings support several escape
sequences that help to denote non-printed characters, such as new lines
and horizontal tabs.  *Note String Literals::.

3.18.2 Poking Strings
---------------------

Let's start with a fresh memory buffer IOS '*scratch*':

     (poke) .mem scratch
     The current IOS is now `*scratch*'.
     (poke) dump :size 48#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................

If we wanted to, somehow, store the word 'word' in this IO space,
encoded in ASCII, we could proceed as:

     (poke) char @ 0x12#B = 'w'
     (poke) char @ 0x13#B = 'o'
     (poke) char @ 0x14#B = 'r'
     (poke) char @ 0x15#B = 'd'
     (poke) dump :size 48#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000010: 0000 776f 7264 0000 0000 0000 0000 0000  ..word..........
     00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................

This worked.  The ASCII part of the 'dump' output, which interprets the
bytes as ASCII, clearly shows the word 'word' at the offset where we
poked the character values.  However, we can do better: string values
can be mapped themselves.

   String values use the type specifier 'string'.  As any other kind of
value in poke, they can be mapped from an IO space:

     (poke) string @ 0x12#B
     "word"

Clearly that is the string resulting from the concatenation of the
character values that we poked before.

   The question now is: how did poke know that the last character of the
string was the 'd' at offset 0x15#B? The fact the character code 0 (also
known as the "NULL character") at offset 0x16#B is non-printable,
doesn't imply it is not part of the ASCII character set.  Clearly, we
have to pick an ASCII code and reserve it to mark the end of strings.
Like the C programming language, and countless formats and systems do,
poke uses the NULL character to delimit strings.

   Now consider this:

     (poke) "word"'length
     4UL
     (poke) "word"'size
     40UL#b

Using the 'length' and 'size' attributes, poke tells us that the length
of the string '"word"' is 4 characters, but the size of the string value
is 40 bits, or 5 bytes.  Why this discrepancy?  The 'size' value
attribute tells how much storage space a given value required once
mapped to an IO space, and in the case of strings it should count the
space occupied by the terminating NULL character.

   Poking string values on the IO space is as straightforward as poking
integers:

     (poke) string @ 0x22#B = "WORD"
     (poke) dump :size 48#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000010: 0000 776f 7264 0000 0000 0000 0000 0000  ..word..........
     00000020: 0000 574f 5244 0000 0000 0000 0000 0000  ..WORD..........

3.18.3 From Characters to Strings
---------------------------------

Strings can be concatenated using the string-concatenation '+'
operators:

     (poke) "foo" + "bar"
     "foobar"

The string resulting from the operation above has length 6 characters,
and size 7 bytes.  The terminating NULL character of '"foo"' is lost in
the operation.  This is easily seen:

     (poke) "foo"'size + "bar"'size
     0x40UL#b
     (poke) ("foo" + "bar")'size
     0x38UL#b

   The string concatenation operator requires two strings.  Therefore,
if we wanted to append a character to a string, we would get an error:

     (poke) "Putin" + 'a'
     <stdin>:1:1: error: invalid operands in expression
     "Putin" + 'a';
     ^~~~~~~~~~~~~

It is possible to transform a character value (i.e.  a byte value) into
a string composed of that character using a cast:

     (poke) 'a' as string
     "a"

Using that cast, we can now append:

     (poke) "Putin" + 'a' as string
     "Putina"


File: poke.info,  Node: From Strings to Characters,  Next: Strings are not Arrays,  Prev: ASCII Strings,  Up: Basic Editing

3.19 From Strings to Characters
===============================

Despite being atomic values, poke strings can be indexed in order to
retrieve individual characters:

     (poke) "word"[2]
     0x72UB

Note how the indexing is zero-based, i.e.  the first position in the
string is referred as '[0]', the second position with '[1]', and so on.

   If you specify a negative index, or an index that is too big, you
will get an error:

     (poke) "word"[-1]
     <stdin>:1:8: error: index is out of bounds of string
     "word"[-1];
            ^
     (poke) "word"[5]
     <stdin>:1:8: error: index is out of bounds of string
     "word"[5];
            ^


File: poke.info,  Node: Strings are not Arrays,  Prev: From Strings to Characters,  Up: Basic Editing

3.20 Strings are not Arrays
===========================

Arrays are collections of homogeneous data organized in a sequence.  We
have already seen (briefly) arrays of bytes, which use the type
specifier 'byte[]'.

   Similarly, it is possible to arrange characters (which are basically
little numbers) in an array, like in:

     (poke) ['a','b','c']
     [0x61UB,0x62UB,0x63UB]

However, the array above is _not_ equivalent to the string '"abc"'.  The
later is a simple value, whereas an array is a composite value, and also
is implicitly terminated with a NULL character, i.e.  a 0 byte.

   The Poke standard library provides a couple of utility functions to
convert between string values and character arrays: 'catos' and 'stoca'.

   'catos' gets an array of characters and returns an equivalent string.
For example:

     (poke) catos (['a','b','c'])
     "abc"

'stoca' gets a string and an array and sets the element of the array to
the characters composing the string.  For example:

     (poke) var a = char[3]()
     (poke) stoca ("abc", a)
     (poke) a
     [0x61UB,0x62UB,0x63UB]


File: poke.info,  Node: Structuring Data,  Next: Maps and Map-files,  Prev: Basic Editing,  Up: Top

4 Structuring Data
******************

In the previous chapter we learned how to manipulate pre-defined
entities like bytes, integers and strings.  One of the big points of
poke, however, is that it allows you to define your own data
abstractions, and to operate in term of them.  This is achieved by
defining data structures.

* Menu:

* The SBM Format::              The Stupid BitMap Format
* Poking a SBM Image::	        A need for abstraction.
* Modifying SBM Images::        Modifying existing data.
* Defining Types::	        Abstracting data structures.
* Pickles::		        Pickling useful abstractions.
* Poking Structs::	        Abstracting heterogeneous data.
* How Structs are Built::       How poke builds struct values.
* Variables in Structs::
* Functions in Structs::
* Struct Methods::              Operations provided by built structs.
* Padding and Alignment::       Reserved fields, payloads and more.
* Dealing with Alternatives::   Conditional decoding.
* Structured Integers::         Structs that are stored like integers.
* Working with Incorrect Data:: Non-strict mapping to the rescue.


File: poke.info,  Node: The SBM Format,  Next: Poking a SBM Image,  Up: Structuring Data

4.1 The SBM Format
==================

4.1.1 Images as Maps of Pixels
------------------------------

There are two main ways to store two-dimensional images in computers.

   One is to explicitly store the different "pixels" that compose the
image.  In these "bitmaps", the pixels are arranged sequentially and
implicitly organized into "lines".  A header typically provides
information to determine how many pixels fit in each line:

      <--- line_width  --->
     | pixel | pixel | ... | pixel | pixel | ... | ...
     |        line 1       |         line 2      |

   Several properties have to be encoded for each pixel, depending on
the sophistication of the image: for monochrome images each pixel can be
just either switched on or off, so a single bit could be used to encode
each pixel (this is the origin of the term "bitmap").  When color is
added, a bit is no longer sufficient: the color of the pixel shall be
encoded in some way, typically using a color schema such as RGB, that
requires triplet of little integers to be encoded.  If transparency is
to be supported, the degree of transparency of the pixel shall also be
encoded somehow.

   The other way to store an image is to store a functional description
of the "painted" parts of the image.  This functional description
usually contains instructions like "paint a line of thickness 1 and
color red from the coordinate 10,20 to coordinate 10,40".  Once executed
with certain parameters (like the desired resolution) the functional
description generates a bitmap.  Image formats using this approach are
commonly known as "vectorial formats".

   When it comes to bitmaps, there are a plethora of different formats
out there (bmp, jpg, png) competing in terms of capabilities such as
higher color depths, better resolution, support for transparency (alpha
channels), higher compression level, and the like.  These capabilities
greatly complicate these formats, but ultimately any bitmap can be
reduced to a sequence of pixels, which can be further structured in
terms of "lines".

   We don't know enough poke yet to handle the complications of these
real-life bitmap formats, so in subsequent sections we introduce a very
simple format for bitmaps, the Stupid BitMap format, or simply SBM, that
we will use for learning purposes.

   But please do not feel disappointed: later in this book, when we
become more proficient pokers, we will be messing with these shiny
complex formats as well :)

4.1.2 SBM header
----------------

A SBM file starts with a header that contains a "magic number" composed
of the three bytes 'S' (0x53UB), 'B' (0x42UB) and 'M' (0x4dUB). The next
two bytes indicate the number of pixels per line, and the number of
lines, respectively.  In summary:

                     SBM header
     +-------+-------+-------+-------+-------+
     |  'S'  |  'B'  |  'M'  |  ppl  | lines |
     +-------+-------+-------+-------+-------+
       byte0   byte1   byte2   byte3   byte4

Here 'ppl' stands for pixels-per-line.  The encoding of these fields
implies that the bigger image that can be encoded in SBM has dimensions
255x255.

4.1.3 SBM data
--------------

Albeit stupid, SBM is a colorful format.  It supports more than a
million colors, encoding each color in what is known as "RGB24".  In
RGB24, each color is encoded using three little integers, specifying the
amount of red, green and blue that, added together, compose the color.

   The name RGB24 comes from the fact that each color is encoded using
three bytes, or 24 bits.  Therefore, each pixel in a SBM image is
encoded using three consecutive bytes:

             SBM pixel
     +-------+-------+-------+
     |  Red  | Green | Blue  |
     +-------+-------+-------+
       byte0   byte1   byte2

Each byte in this encoding determines the amount of the base color (red,
green or blue) that compose the color.  We will talk more about these
components later.


File: poke.info,  Node: Poking a SBM Image,  Next: Modifying SBM Images,  Prev: The SBM Format,  Up: Structuring Data

4.2 Poking a SBM Image
======================

4.2.1 P is for poke
-------------------

Let's compose our first SBM image, using poke.  The image we want to
encode is the very simple rendering of the letter 'P' shown in the
figure below.

       | 0 | 1 | 2 | 3 | 4 |
       +---+---+---+---+---+
     0 |   | * | * |   |   |
     1 |   | * |   | * |   |
     2 |   | * |   | * |   |
     3 |   | * | * |   |   |
     4 |   | * |   |   |   |
     5 |   | * |   |   |   |
     6 |   | * |   |   |   |

The image has seven lines, and there are five pixels per line, i.e.  the
dimension of the image in pixels is 5x7.  Also, the pixels denoted by
asterisks are red, whereas the pixels denoted with empty spaces are
white.  In other words, our image uses a red foreground over a white
background.  The "painted" pixels are called foreground pixels, the non
painted pixels are called background pixels.

4.2.2 Preparing the Canvas
--------------------------

The first thing we need is some suitable IO space where to encode the
image.  Let's fire up poke and create a memory buffer:

     $ poke
     [...]
     (poke) .mem image
     The current IOS is now `*image*'.
     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000040: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
     00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

Freshly created memory IO spaces are 4096 bytes long, and that's big
enough for our little image.  If we wanted to work with more data,
remember that memory IO spaces will grow automagically when poked past
their size.

4.2.3 Poking the Header
-----------------------

The first three bytes of the header of a SBM file contains the magic
number that identifies the file as a SBM bitmap.  We can poke these
bytes very easily:

     (poke) byte @ 0#B = 'S'
     (poke) byte @ 1#B = 'B'
     (poke) byte @ 2#B = 'M'

The next couple of bytes encode the dimensions of the bitmap, in this
case 5x7:

     (poke) byte @ 3#B = 5
     (poke) byte @ 4#B = 7

There is something worth noting in this last mapping.  Even though we
were poking bytes (passing the 'byte' type specifier to the map
operators) we specified the 32-bit signed integers '5' and '7' instead
of '5UB' and '7UB'.  When poke finds a situation like this, where
certain kind of integers are expected but other kind are provided, it
converts the value from the provided type to the expected type.  This
conversion may result in truncation (think about converting, say 0xfff
to an unsigned byte, whose maximum possible value is 0xff) but certainly
not in the case at hands.

   The final header looks like:

     (poke) dump :size 16#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 5342 4d05 0700 0000 0000 0000 0000 0000  SBM.............

4.2.4 Poking the Pixels
-----------------------

Now that we have written a SBM header, we have to encode the sequence of
pixels composing the image.

   Recall that every pixel is encoded using three bytes, that conform a
RGB24 color.  We have two kinds of pixels in our image: white pixels,
and red pixels.  In RGB24 white is encoded as '(255,255,255)'.  Pure red
is encoded as '(255,0,0)', but to make things more interesting we will
be using a nicer tomato-like red '(255,99,71)'.

   Therefore, poking a white pixel at some offset OFFSET would involve
the following operations:

     (poke) byte @ OFFSET = 255
     (poke) byte @ OFFSET+1#B = 255
     (poke) byte @ OFFSET+2#B = 255

Likewise, the operations to poke a tomato pixel would look like:

     (poke) byte @ OFFSET = 255
     (poke) byte @ OFFSET+1#B = 99
     (poke) byte @ OFFSET+2#B = 71

To ease things a bit, we can define variables with the color components
for both foreground and background pixels:

     (poke) var bg1 = 255
     (poke) var bg2 = 255
     (poke) var bg3 = 255
     (poke) var fg1 = 255
     (poke) var fg2 = 99
     (poke) var fg3 = 71

Then to poke a foreground pixel would involve doing:

     (poke) byte @ OFFSET = fg1
     (poke) byte @ OFFSET+1#B = fg2
     (poke) byte @ OFFSET+2#B = fg3

   At this point, you may feel that the perspective of mapping the
pixels of our image is not very appealing, considering we have 5x7 = 35
pixels in our image.  We will need to poke 35 * 3 = 105 bytes.  We may
feel tempted to, somehow, use a bigger integer to "encapsulate" the
bytes.  Using the bit-concatenation operator, we could do something
like:

     (poke) var bg = 255UB::255UB::255UB
     (poke) var fg = 255UB::99UB::71UB
     (poke) bg
     (uint<24>) 0xffffff
     (poke) fg
     (uint<24>) 0xff6347

This encodes each color with a 24-bit unsigned integer.  When looking at
the hexadecimal values of 'bg' and 'fg' above, note that 0xff = 255,
0x63 = 99 and 0x47 = 71.  Each byte seems to be in the right position in
the 24-bit containing number.  Now, poking a pixel at some given offset
should be as easy as issuing just one map operation, right?  Let's see,
using some arbitrary offset 10#B:

     (poke) uint<24> @ 10#B = fg
     (poke) dump :from 10#B :size 4#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     0000000a: 4763 ff00                                Gc..

If your current endianness is little (i.e.  you are running on a x86
system or similar) you will get the dump above.  The bytes are reversed,
and consequently the resulting pixel has the wrong color.  Our little
trick didn't work :(

   So are we doomed to poke three bytes for each pixel we want to poke
in our image?  No, not really.  The Poke language provides a
construction oriented to alleviate cases like this, where several
similar elements are to be "encapsulated" in a container.  These
constructions are called "arrays".

   Using array values, we can define the foreground and background
colors like this:

     (poke) var bga = [255UB, 255UB, 255UB]
     (poke) var fga = [255UB, 99UB, 71UB]

All the elements on an array should be of the same kind, i.e.  of the
same type.  Therefore, this is not allowed:

     (poke) [1,"foo"]
     <stdin>:1:1: error: array initializers should be of the same type
     [1,"foo"];
     ^~~~~~~~~

   Given an array value, it is possible to query for the number of
values contained in it (called "elements") by using the ''length' value
attribute.  For example:

     (poke) bga'length
     3UL

Tells us that the array value stored in the variable 'bga' has three
elements.

   How can we poke an array value?  We know that the map operator
accepts two operands: a type specifier and the value to map.  The type
specifier of an array of three bytes is denoted as 'byte[3]'.
Therefore, we can again try to poke a foreground pixel at offset 10#B,
this time using 'fga':

     (poke) byte[3] @ 10#B = fga
     (poke) dump :from 10#B :size 4#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     0000000a: ff63 4700                                 .cG.

   This time, the bytes were written in the right order.  This is
because array elements are always written using their "written"
ordering, with no mind to endianness.  We can also map a pixel from a
given offset:

     (poke) byte[3] @ 10#B
     [255UB,99UB,71UB]

4.2.5 Poking Lines
------------------

At this point, we could encode the 40 pixels composing the image, by
issuing the same number of pokes of 'byte[3]' arrays.  However, we can
simplify the task even further.

   Our pixels are arrays of bytes, denoted by the type specifier
'byte[3]'.  Similarly, we could conceive arrays of 32-bit signed
integers, denoted by 'int[3]', or arrays of bits, denoted by
'uint<1>[3]'.  But, is it possible to have arrays of other arrays?  Yes,
it is:

     (poke) [[1,2],[3,4]]

The value above is an array of two arrays of two integers each.  If we
wanted to map such an array, what would be the type specifier we would
need to use?  It would be 'int[2][2]', which should be read from
right-to-left as "array of two arrays of two integers".  Let's map one
from an arbitrary offset in our IO space:

     (poke) int[2][2] @ 100#B
     [[0,0],[0,0]]

   Consider again the sequence of pixels composing the image.  Using the
information we have in the SBM header, we can group the pixels in the
sequence into "lines".  In our example image, each line contains 5
pixels.  It would be natural to express each line as a sequence of
pixels.  The first line in our image would be:

     (poke) var l0 = [bga,fga,fga,bga,bga]
     (poke) l0
     [[255UB,255UB,255UB],[255UB,99UB,71UB],...]

Let's complete the image lines:

     (poke) var l0 = [bga,fga,bga,fga,bga]
     (poke) var l1 = [bga,fga,bga,fga,bga]
     (poke) var l2 = [bga,fga,fga,bga,bga]
     (poke) var l3 = [bga,fga,bga,bga,bga]
     (poke) var l4 = l3
     (poke) var l5 = l4

Note how we exploited the fact that the three last lines of our image
are identical, to avoid to write the same array thrice.  Array values
can be assigned, and in general manipulated, like any other kind of
value, such as integers or strings.

   At this point, we could poke the pixels line-by-line.  What would be
the type specifier for a line?  A line is an array of five arrays of 3
bytes each, so the type specifier would be 'byte[3][5]'.  Let's do that:

     (poke) byte[3][5] @ 5#B = l0
     (poke) byte[3][5] @ 10#B = l1
     (poke) byte[3][5] @ 15#B = l2
     (poke) byte[3][5] @ 20#B = l3
     (poke) byte[3][5] @ 25#B = l4
     (poke) byte[3][5] @ 30#B = l5
     (poke) byte[3][5] @ 35#B = l6

Not bad, we went from poking 105 bytes in the IO space to poking six
lines.  But we can still do better...

4.2.6 Poking Images
-------------------

When we poked the lines at the end of the previous section, we had to
increase the offset in every map operation.  This is inconvenient.

   In the same way that a sequence of bytes can be abstracted in a line,
a sequence of lines can be abstracted in an image.  It follows that we
can look at the image data as an array of lines.  But lines are
themselves arrays of arrays... no matter, there is no limit on the
number of arrays-of levels that you can nest.

   So, let's define our image as an array of the lines defined above:

     (poke) var image_data = [l0,l1,l2,l3,l4,l5]
     (poke) image_data
     [[[255UB,255UB,255UB],[255UB,99UB,71UB],[255UB,99UB,71UB]...]...]

What would be the type specifier for an image?  It would be an array of
seven arrays of five arrays of three bytes each, in other words
'byte[3][5][7]'.  Let's poke the pixels:

     (poke) byte[3][5][6] @ 5#B = image_data

   This is an example of how abstraction can simplify the handling of
binary data: we switched from manipulating bytes to manipulate higher
abstractions such as colors, lines and images.  We achieved that by
structuring the data in a way that reflects these abstractions.  That's
the way of the Poker.

4.2.7 Saving the Image
----------------------

Now that we have completed the SBM image in our buffer '*image*', it is
time to save it to disk.  For that, we can use the 'save' command we are
already familiar with.

   We know that the SBM image starts at offset 0#B, but what is the size
of its entire binary representation?  The header is easy: it spans for 5
bytes.  The size of the sequence of pixels can be derived from the
pixels per line byte, and the number of lines byte.  We know that each
pixel occupies 3 bytes, so calculating...

     (poke) var ppl = byte @ 3#B
     (poke) var lines = byte @ 4#B
     (poke) save :from 0#B :size 5#B + ppl#B * lines#B :file "p.sbm"

Note how we expressed "ppl bytes" as 'ppl#B', and "lines bytes" as
'lines#B'.  This is the same than expressing "10 bytes" as '10#B'.  We
will talk more about these united values later.

   There is another way of getting the size of the stream of pixels.
Recall that we have the entire set of pixels, structured as lines,
stored in the variable 'image_data'.  Given an array, it is possible to
query for its size using the ''size' "attribute":

     (poke) .set obase 10
     (poke) [1,2,3]'size
     96UL#b

The above indicates that the size of the array of the three integers 1,
2 and 3 is 96 bits.  Using that attribute, we can also obtain the size
of the pixels in the image:

     (poke) image_data'size
     720UL#b

And we can use it in the save command:

     (poke) save :from 0#B :size 5#B + image_data'size :file "p.sbm"

   Using either strategy, at this point a file named 'p.sbm' should have
been written in the current working directory, containing our "P is for
poke" image.  Keep that file around, because we will be poking it
further!


File: poke.info,  Node: Modifying SBM Images,  Next: Defining Types,  Prev: Poking a SBM Image,  Up: Structuring Data

4.3 Modifying SBM Images
========================

4.3.1 Reading a SBM File
------------------------

Let's open with poke the cute image we created in the last section,
'p.sbm':

     $ poke p.sbm
     [...]
     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 5342 4d05 07ff ffff ff63 47ff 6347 ffff  SBM......cG.cG..
     00000010: ffff ffff ffff ffff 6347 ffff ffff 6347  ........cG....cG
     00000020: ffff ffff ffff ff63 47ff ffff ff63 47ff  .......cG....cG.
     00000030: ffff ffff ffff 6347 ff63 47ff ffff ffff  ......cG.cG.....
     00000040: ffff ffff ff63 47ff ffff ffff ffff ffff  .....cG.........
     00000050: ffff ffff 6347 ffff ffff ffff ffff ffff  ....cG..........
     00000060: ffff ff63 47ff ffff ffff ffff ffff       ...cG.........

You can see the 'P' in the ASCII column, right?  If it wasn't for the
header, it would be pictured almost straight.  This is because dump
shows 16 bytes per row, and our image has lines that are 15 bytes long.
This is a happy coincidence: you definitely shouldn't expect to see
ASCII art in the dump output of SBM files in general!  :)

   Now let's read the image's metadata from the header: pixels per line
and how many lines are contained in the image:

     (poke) var ppl = byte @ 3#B
     (poke) ppl
     5UB
     (poke) var lines = byte @ 4#B
     (poke) lines
     7UB

All right, our image is 7x5.  Knowing that each pixel occupies three
bytes, and that each line contains 'ppl' pixels, and that we have
'lines' lines, we can map the entire image data using an array type
specifier:

     (poke) var image_data = byte[3][ppl][lines] @ 5#B
     (poke) image_data
     [[[255UB,255UB,255UB],[255UB,99UB,71UB], ...]...]

4.3.2 Painting Pixels
---------------------

The "P is for poke" slogan was so successful and widely appraised that
the recutils(1) chaps wanted to do a similar campaign "R is for
recutils".  For that purpose, they asked us for a tomato-colored SBM
image with an 'R' in it.

   Our creative department got at it, and after a lot of work they came
with the following design:

       | 0 | 1 | 2 | 3 | 4 |
       +---+---+---+---+---+
     0 |   | * | * |   |   |
     1 |   | * |   | * |   |
     2 |   | * |   | * |   |
     3 |   | * | * |   |   |
     4 |   | * | * |   |   |
     5 |   | * |   | * |   |
     6 |   | * |   | * |   |

Observe that this design really looks like our 'P' (so much for a
creative department).  The bitmap has exactly the same dimensions, and
difference are just three pixels, that pass from being background pixels
to foreground pixels.

   Therefore, it makes sense to read our 'p.sbm' and use it as a base,
completing the missing pixels.  We saw in the last section how to read a
SBM image.  This time, however, we will copy the image first to a memory
IO space to avoid overwriting 'p.sbm':

     $ poke p.sbm
     [...]
     (poke) .mem scratch
     The current IOS is now `*scratch*'.
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #1	MEMORY		0x00000000#B	0x00001000#B	*scratch*
       #0	FILE	rw	0x00000000#B	0x0000006e#B	./p.sbm
     (poke) copy :from_ios 0 :from 0#B :to 0#B :size iosize (0)
     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 5342 4d05 07ff ffff ff63 47ff 6347 ffff  SBM......cG.cG..
     00000010: ffff ffff ffff ffff 6347 ffff ffff 6347  ........cG....cG
     00000020: ffff ffff ffff ff63 47ff ffff ff63 47ff  .......cG....cG.
     00000030: ffff ffff ffff 6347 ff63 47ff ffff ffff  ......cG.cG.....
     00000040: ffff ffff ff63 47ff ffff ffff ffff ffff  .....cG.........
     00000050: ffff ffff 6347 ffff ffff ffff ffff ffff  ....cG..........
     00000060: ffff ff63 47ff ffff ffff ffff ffff 0000  ...cG...........
     00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

Good.  Now let's map the contents of the image, both header information
and the sequence of pixels:

     (poke) var ppl = byte @ 3#B
     (poke) var lines = byte @ 4#B
     (poke) var image_data = byte[3][ppl][lines] @ 5#B

Let's modify the image.  Since the dimensions of the new image are
exactly the same, the header remains the same.  It is the pixel sequence
that is different.  We basically need to turn the pixels at coordinates
'(4,2)', '(5,3)' and '(6,3)' from background pixels to foreground
pixels.

   Remember how we would change the value of some integer in the IO
space?  First, we would map it into a variable, change the value, and
then poke it back to the IO space.  Something like this:

     (poke) var n = int @ OFFSET
     (poke) n = n + 1
     (poke) int @ OFFSET = n

This three-steps process is necessary because in the 'n = n + 1' above
we are modifying the value of the variable 'n', not the integer actually
stored at offset OFFSET in the current IO space.  Therefore we have to
explicitly poke it back if we want the IO space to be updated as well.

   Array values (and, as we shall see, other "composited" values) are
different: when they are the result of the application of the map
operator, the resulting values are "mapped" themselves.

   When a Poke value is mapped, updating their elements have a side
effect: the area corresponding to the updated element, in whatever IO
space it is mapped on, is updated as well!

   Why is this?  The map operator, regardless of the kind of value it is
mapping, always returns a _copy_ of the value found stored in the IO
space.  We already saw how this worked with integers.  However, in Poke
values are copied around using a mechanism called "shared value".  This
means that when a composite value like an array is copied, its elements
are shared by both the original value and the new value.

   We can depict this graphically for better understanding.  A Poke
array like:

     (poke) var a = [1,2,3]

is stored in memory like this:

        +---+---+---+
      a | 1 | 2 | 3 |
        +---+---+---+

   If we make a copy of the array in another variable 'b':

     (poke) var b = a

we get

        +---+---+---+      +---+---+---+
      a | 1 | 2 | 3 |    b | 1 | 2 | 3 |
        +---+---+---+      +---+---+---+

Note how each of the integer elements has been copied to the new value.
The resulting two arrays can then be modified independently:

     (poke) a[1] = 5

resulting in:

        +---+---+---+      +---+---+---+
      a | 1 | 5 | 3 |    b | 1 | 2 | 3 |
        +---+---+---+      +---+---+---+

   However, consider the following array whose elements are also arrays:

     (poke) var a = [[1,2],[3,4],[5,6]]

This array is stored in memory like this:

        +---+---+---+
      a |   |   |   |
        +---+---+---+
          |   |   |   +---+---+
          |   |   +---| 5 | 6 |
          |   |       +---+---+
          |   |
          |   |       +---+---+
          |   +-------| 3 | 4 |
          |           +---+---+
          |
          |           +---+---+
          +-----------| 1 | 2 |
                      +---+---+

   If now we make a copy of the same array into another variable 'b':

     (poke) var b = a

The elements of the array are copied "by shared value", i.e.

        +---+---+---+           +---+---+---+
      a |   |   |   |         b |   |   |   |
        +---+---+---+           +---+---+---+
          |   |   |   +---+---+   |   |   |
          |   |   +---| 5 | 6 |---+   |   |
          |   |       +---+---+       |   |
          |   |                       |   |
          |   |       +---+---+       |   |
          |   +-------| 3 | 4 |-------+   |
          |           +---+---+           |
          |                               |
          |           +---+---+           |
          +-----------| 1 | 2 |-----------+
                      +---+---+

The elements are indeed shared between the original array and the copy!
If now we modify any of the shared values, this will be reflected in
both containing values:

     (poke) a[1][1] = 9
     (poke) a
     [[1,2],[3,9],[5,6]]
     (poke) b
     [[1,2],[3,9],[5,6]]

or graphically:

        +---+---+---+           +---+---+---+
      a |   |   |   |         b |   |   |   |
        +---+---+---+           +---+---+---+
          |   |   |   +---+---+   |   |   |
          |   |   +---| 5 | 6 |---+   |   |
          |   |       +---+---+       |   |
          |   |                       |   |
          |   |       +---+---+       |   |
          |   +-------| 3 | 9 |-------+   |
          |           +---+---+           |
          |                               |
          |           +---+---+           |
          +-----------| 1 | 2 |-----------+
                      +---+---+

   Back to our image, it follows that if we wanted to change the color
of some SBM pixel stored at offset OFFSET, we would do this:

     (poke) var a = byte[3] @ OFFSET
     (poke) a[1] = 10

There is no need to poke the array back explicitly: the side effect of
assigning 10 to a[1] is that the byte at offset 'OFFSET+1' is poked.

   Generally speaking, mapped values can be handled in exactly the same
way than non-mapped values.  This is actually a very central concept in
poke.  However, it is possible to check whether a given value is mapped
or not using the ''mapped' attribute.

   As we said, "simple values" such as integers and strings are never
mapped, regardless of where they come from.  Both 'ppl' and 'lines' are
integers, therefore:

     (poke) ppl'mapped
     0
     (poke) lines'mapped
     0

However, 'image_data' is an array that was the result of the application
of a map operator, so:

     (poke) image_data'mapped
     1

When a value is mapped, you can ask for the offset where it is mapped,
and the IO space where it is mapped, using the attributes ''offset' and
''ios' respectively.  Therefore:

     (poke) image_data'ios
     1
     (poke) image_data'offset
     40UL#b

In other words, 'image_data' is mapped in the IO space with id 1 (the
'*scratch*' buffer) at offset 40 bits, or 5 bytes.  We already knew
that, because we mapped the image data ourselves, but in other
situations these attributes are most useful.  We shall see how later.

   Well, at this point it should be clear how to paint pixels.  First,
let's define our background and foreground pixels:

     (poke) var bga = [255UB, 255UB, 255UB]
     (poke) var fga = [255UB, 99UB, 71UB]

Then, we just update the pixels in the image data using the right
coordinates:

     (poke) image_data[4][2] = fga
     (poke) image_data[5][3] = fga
     (poke) image_data[6][3] = fga
     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 5342 4d05 07ff ffff ff63 47ff 6347 ffff  SBM......cG.cG..
     00000010: ffff ffff ffff ffff 6347 ffff ffff 6347  ........cG....cG
     00000020: ffff ffff ffff ff63 47ff ffff ff63 47ff  .......cG....cG.
     00000030: ffff ffff ffff 6347 ff63 47ff ffff ffff  ......cG.cG.....
     00000040: ffff ffff ff63 47ff 6347 ffff ffff ffff  .....cG.cG......
     00000050: ffff ffff 6347 ffff ffff 6347 ffff ffff  ....cG....cG....
     00000060: ffff ff63 47ff ffff ff63 47ff ffff 0000  ...cG....cG.....
     00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

4.3.3 Cropping the R
--------------------

Looking at our new image, we realize that the first and the last column
are all background pixels.  We are aware that the recutils project is
always short of resources, so we would like to modify the image to
remove these columns, "cropping" it so it looks like this:

       | 0 | 1 | 2 |
       +---+---+---+
     0 | * | * |   |
     1 | * |   | * |
     2 | * |   | * |
     3 | * | * |   |
     4 | * | * |   |
     5 | * |   | * |
     6 | * |   | * |

In order to perform this operation we need to rework the stream of
pixels to reflect the desired result, and then to update the header
metadata accordingly.

4.3.4 Shortening and Shifting Lines
-----------------------------------

Let's think in term of lines.  In the original image, each line has 5
pixels, that we can enumerate as:

          +----+----+----+----+----+
     line | p0 | p1 | p2 | p3 | p4 |
          +----+----+----+----+----+

What we want is to crop out the first and the last column, so the
resulting line would look like:

          +----+----+----+
     line | p1 | p2 | p3 |
          +----+----+----+

   Let's get the first line from the original 'image_data':

     (poke) var l0 = image_data[0]
     (poke) l0
     [[255UB,255UB,255UB],[255UB,99UB,71UB],...]

We could create the corresponding cropped line, by doing something like
this:

     (poke) var cl0 = [l0[1],l0[2],l0[3]]

And the same for the other lines.  However, Poke provides a better way
to easily obtain sub portions of arrays.  It is called "trimming".
Given an array like the line 'l0', we can obtain the desired portion of
it by issuing:

     (poke) l0[1:4]
     [[255UB,99UB,71UB],[255UB,99UB,71UB]]

Note how the limits of the semi-open interval specified in the trim
reflect array indexes, and hence they are 0 based.  Also, the left limit
is closed and the right limit is open.  The result of an array trimming
is always another array, which may be empty:

     (poke) l0[1:3]
     [[255UB,99UB,71UB]]

   Armed with this new operation, we can very easily mount the sequence
of pixels for our cropped image:

     (poke) var l0 = image_data[0]
     (poke) var l1 = image_data[1]
     (poke) var l2 = image_data[2]
     (poke) var l3 = image_data[3]
     (poke) var l4 = image_data[4]
     (poke) var l5 = image_data[5]

And then update the lines in the mapped image data:

     (poke) image_data[0] = l0[1:4]
     (poke) image_data[0] = l1[1:4]
     (poke) image_data[1] = l2[1:4]
     (poke) image_data[2] = l3[1:4]
     (poke) image_data[3] = l4[1:4]
     (poke) image_data[4] = l5[1:4]

4.3.5 Updating the Header
-------------------------

The last step is to update the header to reflect the new dimensions of
the image:

     (poke) byte[] @ 0#B = ['S','B','M']
     (poke) byte @ 3#B = 3
     (poke) byte @ 4#B = 7

And we are done.  Note how this time we wrote the magic bytes as an
array, to save some typing and silly manual offset arithmetic.  You may
have noticed that the type specifier we used this time in the map is
'byte[]' instead of 'byte[3]'.  This type specifier denotes an array of
any number of bytes, which certainly includes arrays of three bytes,
like in the example.

4.3.6 Saving the Result
-----------------------

And finally, let's write out the new file as 'r.sbm':

     (poke) save :from 0#B :size 5#B + image_data'size :file "r.sbm"

   ---------- Footnotes ----------

   (1) http://www.gnu.org/s/recutils


File: poke.info,  Node: Defining Types,  Next: Pickles,  Prev: Modifying SBM Images,  Up: Structuring Data

4.4 Defining Types
==================

4.4.1 Naming your Own Abstractions
----------------------------------

During the process of creating and manipulating SBM files we soon
started talking about things like lines, pixel sequences, pixels,
colors, and so on.  What is more, very naturally we started _thinking_
in terms of these entities: let's drop this or that line, or let's
change the green component of this pixel.

   Consider for example RGB colors.  We know that each color is defined
by three levels of light: red, green and blue.  These components are
also called color beams.  Since each color beam has a range of 0 to 255,
many formats, like SBM, use bytes to encode them.

   Therefore, in the previous sections we used the type specifier 'byte'
when we needed to map RGB color beams, like in:

     (poke) byte[3] @ 5#B

Recall that the mapping operation above means "map three bytes at the
offset 5 bytes in the current IO space".  But what we really want is to
map color beams, not bytes!

   Poke provides a way to assign names to type specifiers:

     (poke) type RGB_Color_Beam = byte

The definition above tells poke that a RGB color beam is composed of a
byte, i.e.  an unsigned 8-bit integer.  Any type specifier can be used
at the right side of the assignment sign, and also names of already
defined types.  From this point on, we can map in terms of color beams:

     (poke) RGB_Color_Beam[3] @ 5#B

Meaning "map three RGB color beams at the offset 5 in the current IO
space".

   Once a type is defined, the name can be used anywhere where a type
specifier is expected.

   By the way, we mentioned many times how 'byte' is a synonym for
'uint<8>', 'int' is a synonym for 'int<32>' and so on.  These synonyms
are actually result of type definitions that are in the poke "standard
library".  This library is loaded by poke at startup time.

4.4.2 Abstracting the Structure of Entities
-------------------------------------------

Since we didn't know better, during our work with SBM images we had to
remember how these entities were constructed from more simple entities
such as bits and bytes, every time we needed to map them, or to poke
them.  For example, if we wanted to map a pixel at some particular
offset, we had to issue the following command:

     (poke) var pixel = byte[3] @ 5#B

Now that we made poke aware of what a RGB color beam is, we can rewrite
the above as:

     (poke) var pixel = RGB_Color_Beam[3] @ 5#B

This is better, but still adoleces from a big problem: what if at some
point the SBM pixels get expanded to also have a transparency index,
stored in a fourth byte?  If that ever happens (and _will_ happen later
in this book) then we would need to remember it before issuing commands
like:

     (poke) var image_data = RGB_Color_Beam[4][ppl][lines] @ 5#B

   To avoid this problem, we define yet another type, this time
describing the structure of a SBM pixel:

     (poke) type SBM_Pixel = RGB_Color_Beam[3]

And then we can define 'image_data' as a table of SBM pixels, instead of
as a table of triplets of RGB color beams:

     (poke) var image_data = SBM_Pixel[ppl][lines] @ 5#B

   This later definition doesn't need to be changed if we change the
definition of what a SBM pixel is.  This is called "encapsulation" and
is a very useful abstraction in computing.


File: poke.info,  Node: Pickles,  Next: Poking Structs,  Prev: Defining Types,  Up: Structuring Data

4.5 Pickles
===========

4.5.1 poke Commands versus Poke Constructions
---------------------------------------------

In *note Nomenclature:: we mentioned that poke, the program, implements
a domain specific programming language called Poke, with a big p.  In
the examples so far we have already used the Poke language, somewhat
extensively, while interacting with the program using the REPL.

   For example, in:

     (poke) 10 + 2
     12

We are giving poke a "Poke expression" '10 + 2' to be evaluated.  Once
the expression is evaluated, the REPL prints the resulting value for us.

   Similarly, when we define a variable or a type with 'var' and 'type'
respectively, we are providing poke definitions to be evaluated.  When
we assign a value to a variable we are actually providing a Poke
statement to be executed.

   So the REPL accepts "poke commands", some of which happen to be Poke
expressions, definitions or statements.  But we also have used
dot-commands like '.file' or '.info'.  These dot-commands are not part
of the Poke programming language.

   Every time we insert a line in the REPL and hit <enter>, poke
recognizes the nature of the line, and then does the right thing.  If
the line is recognized as a Poke expression, for example, the Poke
compiler is used to compile the statement into a routine, that is
executed by the Poke Virtual Machine.  The resulting value is then
printed for the benefit of the user.

4.5.2 Poke Files
----------------

Poke programs are basically a collection of definitions and statements,
which most often than not are stored in files, which avoids the need to
type them again and again.  By convention, we use the '.pk' file
extension when naming files containing Poke programs.

   Remember how we defined the foreground and background pixels for
'p.sbm' in the REPL?

     (poke) var bga = [255UB, 255UB, 255UB]
     (poke) var fga = [255UB, 99UB, 71UB]

Where 'bga' is a white pixel and 'fga' is a tomato colored pixel.  We
could write these definitions in a file 'colors.pk' like this:

     var white = [255UB, 255UB, 255UB];
     var tomato = [255UB, 99UB, 71UB];

Note that variable definitions in Poke are terminated by a semicolon
(';') character, but we didn't need to specify them when we issued the
definitions in the REPL. This is because poke adds the trailing
semicolon for us when it detects a Poke construction requiring it is
introduced in the REPL.

Another difference is that Poke constructions can span for multiple
lines, like in most programming languages.  For example, we could have
the following variable definition in a file:

     var matrix = [[10, 20, 30],
                   [40, 50, 60],
                   [70, 80, 90]];

   Once we have written our 'colors.pk' file, how can we make poke aware
of it?  A possibility is to use the 'load' construction:

     (poke) load colors

Assuming a file named 'colors.pk' exists in the current working
directory, poke will load it and evaluate its contents.  After this, we
can use the colors:

     (poke) tomato
     [0xffUB,0x63UB,0x47UB]

Before, we would need to define these colors every time we would like to
poke SBM files or, in fact, any RGB24 data.  Now we just have to load
the file 'colors.pk' and use the variables defined there.

   If you try to load a file whose name contains a dash character ('-')
you will get an error message:

     (poke) load my-colors
     <stdin>:1:8: error: syntax error, unexpected '-', expecting ';'
     load my-colors;
            ^

This is because the argument to 'load' is interpreted as a Poke
identifier, and dash characters are not allowed in identifiers.  To
alleviate this problem, you can also specify the name of the file to
load encoded in a string, line in:

     (poke) load "my-colors.pk"

If you use this form of 'load', however, you are required to specify the
complete name of the file, including the '.pk' file extension.

   Since loading files is such a common operation, poke provides a
dot-command '.load' that does auto-completion:

     (poke) .load my-colors.pk

Which is equivalent to 'load "my-colors.pk"'.

   Since 'load' is part of the Poke language, it can also be used in
Poke programs stored in files.  We will explore this later.

4.5.3 Pickling Abstractions
---------------------------

In the last section we defined a couple of RGB colors 'white' and
'tomato' in a file called 'colors.pk'.  If we keep adding colors to the
file, we may end with a nice collection of colors that are available to
us at any time, by just loading the file.

   Since there are many ways to understand the notion of "color", and
also many ways to implement these many notions, it would be better to be
more precise and call our file 'rgb24.pk', since the notion of color we
are using is of that RGB24.  While are at it, let's also rename the
variables to reflect the fact they denote not just any kind of colors,
but RGB24 colors:

     var rgb24_white = [255UB, 255UB, 255UB];
     var rgb24_tomato = [255UB, 99UB, 71UB];

At this point, we can also add the definitions of a couple of types to
our 'rgb24.pk':

     type RGB_Color_Beam = byte;
     type RGB24_Color = RGB_Color_Beam[3];

     var rgb24_white = [255UB, 255UB, 255UB];
     var rgb24_tomato = [255UB, 99UB, 71UB];

Any time we want to manipulate RGB24 colors we can just load the file
'rgb24.pk' and use these types and variables.

   In poke parlance we call files like the above, that contain
definitions of conceptually related entities, "pickles".  Pickles can be
very simple, like the 'rgb24.pk' sketched above, or fairly complicated
like 'dwarf.pk'.

   It is common for pickles to 'load' other pickles.  For example, if we
were to write a SBM pickle, we would load the RGB24 pickle from it:

     load rgb24;

     [... SBM definitions ...]

This way, when we 'load sbm' from the repl, the dependencies get loaded
as well.

   GNU poke includes several already written pickles for commonly used
file formats, and other domains.  The 'load' construction knows where
these pickles are installed, so in order to load the pickle to
manipulate ELF files, for example, all you have to do is to:

     (poke) load elf

4.5.4 Exploring Pickles
-----------------------

As we have seen, a pickle provides Poke variables, types and functions
related to some definite domain.  Let's say we are interested in editing
an ELF file.  We know that GNU poke comes with a pre-installed pickle
named 'elf.pk'.  We can load it like this:

     (poke) load elf

   By convention, the entities provided by a pickle 'foo.pk' are usually
prefixed like:

   - Variables, units and functions are prefixed with 'foo_'.
   - Types are prefixed with 'Foo_'.

Therefore, once the pickle is loaded we can use the '.info' dot-command
in order to get a glimpse of the functionality provided by the pickle.
*Note info command::.  Example:

     (poke) .info variables elf
     Name            Declared at
     elf_stb_names   elf-common.pk:53
     elf_stt_names   elf-common.pk:72
     elf_stv_names   elf-common.pk:84

The above tells us that the 'elf.pk' pickle provides these three
variables.  Types are way more interesting:

     (poke) .info types Elf64
     Name                 Declared at
     Elf64_Ehdr           elf-64.pk:184
     Elf64_Off            elf-64.pk:26
     Elf64_SectionFlags   elf-64.pk:130
     Elf64_Shdr           elf-64.pk:152
     Elf64_RelInfo        elf-64.pk:36
     Elf64_Chdr           elf-64.pk:85
     Elf64_Rela           elf-64.pk:61
     Elf64_Phdr           elf-64.pk:169
     Elf64_Sxword         elf-64.pk:24
     Elf64_Sym            elf-64.pk:71
     Elf64_Rel            elf-64.pk:45
     Elf64_File           elf-64.pk:207
     Elf64_Addr           elf-64.pk:25
     Elf64_Group          elf-64.pk:121
     Elf64_Dyn            elf-64.pk:98
     Elf64_Xword          elf-64.pk:23

We immediately notice the 'Elf64_File'.  Looks like what we would need
to map in order to access the entire ELF data in some given IO space
(like a file.)  We can ask for more details about it:

     (poke) .info type Elf64_File
     Class:      struct
     Name:       Elf64_File
     Complete:   no
     Fields:
       Name     Type
       ehdr     Elf64_Ehdr
       shdr     Elf64_Shdr[]
       phdr     Elf64_Phdr[]
     Methods:
       Name                     Type
       get_section_name         (offset<Elf_Word,8>)string
       get_symbol_name          (Elf64_Shdr,,offset<Elf_Word,8>)string
       get_sections_by_name     (string)Elf64_Shdr[]
       get_sections_by_type     (Elf_Word)Elf64_Shdr[]
       section_name_p           (string)int
       get_string               (offset<Elf_Word,8>)string
       get_group_signature      (Elf64_Shdr)string
       get_group_signatures     ()string[]
       get_section_group        (string)Elf64_Shdr[]

We see that an 'Elf64_File' has three fields, and the nature of these
files: a header 'ehdr', an array of section headers 'shdr' and an array
of program headers 'phdr'.

   The type description above also lists the methods defined in the
type.  Looking at the method name and its type is very usually revealing
enough to use it.  For example, we see that 'get_sections_by_name'
returns an array of section headers, characterized by some given section
name:

     (poke) var elf = Elf64_File @ 0#B
     (poke) elf.get_sections_by_name (".text")
     [Elf64_Shdr {
       sh_name=0x1bU#B,
       sh_type=0x1U,
       sh_flags=#<ALLOC,EXECINSTR>,
       sh_addr=0x0UL#B,
       sh_offset=0x40UL#B,
       sh_size=0xbUL#B,
       sh_link=0x0U,
       sh_info=0x0U,
       sh_addralign=0x1UL,
       sh_entsize=0x0UL#b
     }]

   Ultimately, of course the best way to see what a pickle provides is
to go read its source code.

4.5.5 Startup
-------------

When poke starts it loads the file '.pokerc' located in our home
directory, if it exists.  This initialization file contains poke
commands, one per line.

   If we wanted to get some Poke file loaded at startup, we could do it
by adding a load command to our '.pokerc'.  For example:

     # My poke configuration - jemarch
     [...]
     .load ~/.poke.d/mydefs.pk


File: poke.info,  Node: Poking Structs,  Next: How Structs are Built,  Prev: Pickles,  Up: Structuring Data

4.6 Poking Structs
==================

4.6.1 Heterogeneous Related Data
--------------------------------

Let's recap the structure of the header of a Stupid BitMap:

                     SBM header
     +-------+-------+-------+-------+-------+
     |  'S'  |  'B'  |  'M'  |  ppl  | lines |
     +-------+-------+-------+-------+-------+
       byte0   byte1   byte2   byte3   byte4

The header is composed of five fields, which actually compose three
different logical "fields": a magic number, the number of pixels per
line, and the number of lines.

   We could of course abstract the header using an array of five bytes,
like this:

     type SBM_Header = byte[5];

   However, this would not capture the properties of the fields
themselves, which would need to be remembered by the user: which of
these five bytes correspond to the magic number?  Is the pixels per line
number signed or unsigned?  etc.

   Poke provides a much better way to abstract collections of
heterogeneous data: "struct types".  Using a struct type we can abstract
the SBM header like this:

     type SBM_Header =
      struct
      {
        byte[3] magic;
        uint<8> ppl;
        uint<8> lines;
      }

   Note how the struct has three named fields: 'magic', 'ppl' and
'lines'.  'magic' is an array of three bytes, while 'ppl' and 'lines'
are both unsigned integers.

4.6.2 Mapping Structs
---------------------

Once defined, struct types can be referred by name.  For example, we can
map the SBM header at the beginning of our file 'p.sbm' like this:

     (poke) SBM_Header @ 0#B
     SBM_Header {
       magic=[0x53UB,0x42UB,0x4dUB],
       ppl=0x5UB,
       lines=0x7UB
     }

The value resulting from the mapping is a struct value.  The fields of
struct values are accessed using the familiar dot-notation:

     (poke) var header = SBM_Header @ 0#B
     (poke) header.ppl * header.lines
     35UB

The total number of pixels in the image is 35.  Note how both
'header.ppl' and 'header.lines' are indeed unsigned byte values, and
thus the result of the multiplication is also an unsigned byte.  This
could be problematic if the image contained more than 255 pixels, but
this can be prevented by using a cast:

     (poke) header.ppl as uint * header.lines
     35U

Now the second operand 'header.lines' is promoted to a 32-bit unsigned
value before the multiplication is performed.  Consequently, the result
of the operation is also 32-bit wide (note the suffix of the result.)

4.6.3 Modifying Mapped Structs
------------------------------

Remember when we wanted to crop a SBM image by removing the first and
last row?  We updated the header in a byte by byte manner, like this:

     (poke) byte @ 3#B = 3
     (poke) byte @ 4#B = 7

Now that we have the header mapped in a variable, updating it is much
more easy and convenient.  The dot-notation is used to update the
contents of a struct field, by placing it at the left hand side of an
assignment:

     (poke) header.ppl = 3
     (poke) header.lines = 7

This updates the pixel per line and the number of lines, in the IO
space:

     (poke) dump :size 5#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 5342 4d03 07                             SBM..


File: poke.info,  Node: How Structs are Built,  Next: Variables in Structs,  Prev: Poking Structs,  Up: Structuring Data

4.7 How Structs are Built
=========================

First we need to define some structure to use as an example.  Let's say
we are interesting in poking Packets, as defined by the Packet
Specification 1.2 published by the Packet Foundation (none less).

   In a nutshell, each Packet starts with a byte whose value is always
'0xab', followed by a byte that defines the size of the payload.  A
stream of bytes conforming the payload follows, themselves followed by
another stream of the same number of bytes with "control" values.

   We could translate this description into the following Poke struct
type definition:

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;
         byte[size] payload;
         byte[size] control;
       };

   There are some details described by the fictitious Packet
Specification 1.2 that are not covered in this simple definition, but we
will be attending to that later in this manual.

   So, given the definition of a struct type like Packet, there are only
two ways to build a struct value in Poke.

   One is to map it from some IO space.  This is achieved using the map
operator:

     (poke) Packet @ 12#B
     Packet {
       magic == 0xab,
       size = 2,
       payload = [0x12UB,0x30UB],
       control = [0x1UB,0x1UB]
     }

   The expression above maps a Packet starting at offset 12 bytes, in
the current IO space.  See the Poke manual for more details on using the
map operator.

   The second way to build a struct value is to _construct_ one,
specifying the value to some, all or none of its fields.  It looks like
this:

     (poke) Packet {size = 2, payload = [1UB,2UB]}
     Packet {
       magic == 0xab,
       size = 2,
       payload = [0x1UB,0x2UB],
       control = [0x0UB,0x0UB]
     }

   In either case, building a struct involves to determine the value of
all the fields of the struct, one by one.  The order in which the struct
fields are built is determined by the order of appearance of the fields
in the type description.

   In our example, the value of 'magic' is determined first, then
'size', 'payload' and finally 'control'.  This is the reason why we can
refer to the values of previous fields when defining fields, such as in
the size of the 'payload' array above, but not the other way around: by
the time 'payload' is mapped or constructed, the value of 'size', has
already been mapped or constructed.

   What happens behind the curtains is that when poke finds the
definition of a struct type, like Packet, it compiles two functions from
it: a mapper function, and a constructor function.  The mapper function
gets as arguments the IO space and the offset from which to map the
struct value, whereas the constructor function gets the template
specifying the initial values for some, or all of the fields; reasonable
default values (like zeroes) are used for fields for which no initial
values have been specified.

   These functions, mapper and constructor, are invoked to create fresh
values when a map operator @ or a struct constructor is used in a Poke
program, or at the poke prompt.


File: poke.info,  Node: Variables in Structs,  Next: Functions in Structs,  Prev: How Structs are Built,  Up: Structuring Data

4.8 Variables in Structs
========================

Fields are not the only entity that can appear in the definition of a
struct type.

   Suppose that after reading more carefully the Packet Specification
1.2 (that spans for several thousand of pages) we realize that the field
'size' doesn't really store the number of bytes of the payload and
control arrays, like we thought initially.  Or not exactly: the Packet
Foundation says that if 'size' has the special value 0xff, then the size
is zero.

   We could of course do something like this:

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         byte[size == 0xff ? 0 : size] payload;
         byte[size == 0xff ? 0 : size] control;
       };

   However, we can avoid replicating code by using a variable instead:

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         var real_size = (size == 0xff ? 0 : size);

         byte[real_size] payload;
         byte[real_size] control;
       };

   Note how the variable can be used after it gets defined.  In the
underlying process of mapping or constructing the struct, the variable
is incorporated into the lexical environment.  Once defined, it can be
used in constraint expressions, array sizes, and the like.  We will see
more about this later.

   Incidentally, it is of course possible to use global variables as
well.  For example:

     var packet_special = 0xff;
     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         var real_size = (size == packet_special ? 0 : size);

         byte[real_size] payload;
         byte[real_size] control;
       };

   In this case, the global 'packet_special' gets captured in the
lexical environment of the struct type (in reality in the lexical
environment of the implicitly created mapper and constructor functions)
in a way that if you later modify 'packet_special' the new value will be
used when mapping/constructing _new_ values of type Packet.  Which is
really cool, but let's not get distracted from the main topic...  :)


File: poke.info,  Node: Functions in Structs,  Next: Struct Methods,  Prev: Variables in Structs,  Up: Structuring Data

4.9 Functions in Structs
========================

Further reading of the Packet Specification 1.2 reveals that each Packet
has an additional 'crc' field.  The content of this field is derived
from both the payload bytes and the control bytes.

   But this is no vulgar CRC we are talking about.  On the contrary, it
is a special function developed by the CRC Foundation in partnership
with the Packet Foundation, called superCRC (patented, TM).

   Fortunately, the CRC Foundation distributes a pickle 'supercrc.pk',
that provides a 'calculate_crc' function with the following spec:

     fun calculate_crc = (byte[] data, byte[] control) int:

   So let's use the function like this in our type, after loading the
supercrc pickle:

     load supercrc;

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         var real_size = (size == 0xff ? 0 : size);

         byte[real_size] payload;
         byte[real_size] control;

         int crc = calculate_crc (payload, control);
       };

   However, there is a caveat: it happens that the calculation of the
CRC may involve arithmetic and division, so the CRC Foundation warns us
that the 'calculate_crc' function may raise E_div_by_zero.  However, the
Packet 1.2 Specification tells us that in these situations, the 'crc'
field of the packet should contain zero.  If we used the type above, any
exception raised by 'calculate_crc' would be propagated by the
mapper/constructor:

     (poke) Packet @ 12#B
     unhandled division by zero exception

   A solution is to use a function that takes care of the extra needed
logic, wrapping calculate_crc:

     load supercrc;

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         var real_size = (size == 0xff ? 0 : size);

         byte[real_size] payload;
         byte[real_size] control;

         fun corrected_crc = int:
         {
           try return calculate_crc (payload, control);
           catch if E_div_by_zero { return 0; }
         }

         int crc == corrected_crc;
       };

   Again, note how the function is accessible after its definition.
Note as well how both fields and variables and other functions can be
used in the function body.  There is no difference to define variables
and functions in struct types than to define them inside other functions
or in the top-level environment: the same lexical rules apply.


File: poke.info,  Node: Struct Methods,  Next: Padding and Alignment,  Prev: Functions in Structs,  Up: Structuring Data

4.10 Struct Methods
===================

At this point you may be thinking something on the line of "hey, since
variables and functions are also members of the struct, I should be able
to access them the same way than fields, right?".

   So you will want to do:

     (poke) var p = Packet  12#B
     (poke) p.real_size
     (poke) p.corrected_crc

But sorry, this won't work.

   To understand why, think about the struct building process we
sketched above.  The mapper and constructor functions are
derived/compiled from the struct type.  You can imagine them to have
prototypes like:

     Packet_mapper (IOspace, offset) -> Packet value
     Packet_constructor (template)   -> Packet value

   You can also picture the fields, variables and functions in the
struct type specification as being defined inside the bodies of
Packet_mapper and Packet_constructor, as their contents get
mapped/constructed.  For example, let's see what the mapper does:

     Packet_mapper:

       . Map a byte, put it in a local `magic'.
       . Map a byte, put it in a local `size'.
       . Calculate the real size, put it in a local `real_size'.
       . Map an array of real_size bytes, put it in a local `payload'.
       . Map an array of real_size bytes, put it in a local `control'.
       . Compile a function, put it in a local `corrected_crc'.
       . map a byte, call the function in the local `corrected_crc',
         complain if the values are not the same, otherwise put the
         mapped byte in a local `crc'.
       . Build a struct value with the values from the locals `magic',
         `size', `payload', `control' and `crc', and return it.

   The pseudo-code for the constructor would be almost identical.  Just
replace "map a byte" with "construct a byte".

   So you see, both the values for the mapped fields and the values for
the variables and functions defined inside the struct type end as locals
of the mapping process, but only the values of the fields are actually
put in the struct value that is returned in the last step.

   This is where methods come in the picture.  A method looks very
similar to a function, but it is not quite the same thing.  Let me show
you an example:

     load supercrc;

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;

         var real_size = (size == 0xff ? 0 : size);

         byte[real_size] payload;
         byte[real_size] control;

         fun corrected_crc = int:
         {
           try return calculate_crc (payload, control);
           catch if E_div_by_zero { return 0; }
         }

         int crc = corrected_crc;

         method c_crc = int:
         {
           return corrected_crc;
         }
       };

   We have added a method 'c_crc' to our Packet struct type, that just
returns the corrected superCRC (patented, TM) of a packet.  This can be
invoked using dot-notation, once a Packet value is mapped/constructed:

     (poke) var p = Packet  12#B
     (poke) p.c_crc
     0xdeadbeef

   Now, the important bit here is that the method returns the corrected
crc _of a 'Packet'_.  That's it, it actually operates on a Packet value.
This Packet value gets implicitly passed as an argument whenever a
method is invoked.

   We can visualize this with the following "pseudo Poke":

     method c_crc = (Packet SELF) int:
     {
        return SELF.corrected_crc;
     }

   Fortunately, poke takes care to recognize when you are referring to
fields of this implicit struct value, and does The Right Thing(TM) for
you.  This includes calling other methods:

     method foo = void: { ... }
     method bar = void:
     {
      [...]
      foo;
     }

   The corresponding "pseudo-poke" being:

     method bar = (Packet SELF) void:
     {
      [...]
      SELF.foo ();
     }

   It is also possible to define methods that modify the contents of
struct fields, no problem:

     var packet_special = 0xff;

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size;
         [...]

         method set_size = (byte s) void:
         {
           if (s == 0)
             size = packet_special;
           else
             size = s;
         }
       };

   This is what is commonly known as a "setter".  Note, incidentally,
how a method can also use regular variables.  The Poke compiler knows
when to generate a store in a normal variable such as 'packet_special',
and when to generate a set to a 'SELF' field.

   Given the different nature of the variables, functions and methods,
there are a couple of restrictions:

   * Functions can't set fields defined in the struct type.

     This will be rejected by the compiler:

          type Foo =
            struct
            {
               int field;
               fun wrong = void: { field = 10; }
            };

     Remember the construction/mapping process.  When a function
     accesses a field of the struct type like in the example above, it
     is not doing one of these pseudo 'SELF.field = 10'.  Instead, it is
     simply updating the value of the local created in this step in
     Foo_mapper:

          Foo_mapper:

           . Map an int, put it in a local `field'.
           . [...]

     Setting that local would impact the mapping of the subsequent
     fields if they refer to 'field' (for example, in their constraint
     expression) but it wouldn't actually alter the value of the field
     'field' in the struct value that is created and returned from the
     mapper!

     This is very confusing, so we just disallow this with a compiler
     error "invalid assignment to struct field", for your own sanity 8-)

   * Methods can't be used in field constraint expressions, nor in
     variables or functions defined in a struct type.

     How could they be?  The field constraint expressions, the
     initialization expressions of variables, and the functions defined
     in struct types are all executed as part of the mapper/constructor
     and, at that time, there is no struct value yet to pass to the
     method.

     If you try to do this, the compiler will greet you with an "invalid
     reference to struct method" message.

   Something to keep in mind about methods is that they can destroy the
integrity of the data stored in a struct.  Consider for example the
following struct type:

     type Packet =
       struct
       {
         byte magic == 0xab;
         byte size : size <= 4096;
         [...]

         method set_size = (byte s) void:
         {
           if (s == 0)
             size = packet_special;
           else
             size = s;
         }
       };

Observe how this new version of 'Packet' has an additional constraint
that specifies 'size' should not exceed 4096.  However, when the method
'set_size' is executed the constraints are not checked again.  This is
useful at times, but can also lead to unintended data corruption.

   A solution for this problem is to make methods aware of the
restrictions.  Like in this case:

     type Packet =
       struct
       {
         var MAXSIZE = 4096;

         byte magic == 0xab;
         byte size : size <= MAXSIZE;
         [...]

         method set_size = (byte s) void:
         {
           if (s == 0)
             size = packet_special;
           else if (s > MAXSIZE)
             raise E_inval;
           else
             size = s;
         }
       };

Note how we use a variable 'MAXSIZE' in order to avoid hard-coding 4096
twice in the struct definition.

   Occasionally it is useful to access to additional properties of a
containing struct or union in a method, other than its fields.  For this
purpose it is possible to refer explicitly to the struct using the
'SELF' keyword.  Note that the value referred has type 'any'.

   For example, this is how we could print the name of the current
alternative in a pretty-printer for an union:

     type Foo =
       union int<32>
         {
           int<32> One == 1;
           int<32> Two == 2;
           method _print = void:
           {
             printf ("%s (%v)", SELF'ename (0), SELF'elem (0));
           }
         };


File: poke.info,  Node: Padding and Alignment,  Next: Dealing with Alternatives,  Prev: Struct Methods,  Up: Structuring Data

4.11 Padding and Alignment
==========================

It is often the case in binary formats that certain elements are
separated by some data that is not really used for any meaningful
purpose other than occupy that space.  The reason for keeping that space
varies from case to case; sometimes to reserve it for future use,
sometimes to make sure that the following data is aligned to some
particular alignment.  This is known as "padding".  There are several
ways to implement padding in GNU poke.  This article shows these
techniques and discusses their advantages and disadvantages.

* Menu:

* Esoteric and exoteric padding::       External and internal padding.
* Reserved fields::                     Extra space not to be used.
* Payloads::                            Extra space to be used.
* Aligning struct fields::              Some stuff requires an alignment.
* Padding array elements::              An useful idiom.


File: poke.info,  Node: Esoteric and exoteric padding,  Next: Reserved fields,  Up: Padding and Alignment

4.11.1 Esoteric and exoteric padding
------------------------------------

Padding is the technique of keeping some amount of space between two
different elements in some data stream.  GNU poke provides two different
ways to express sequences of data elements: the fields of a struct type,
which are defined one after the other, and elements in an array.

   We call adding space between two struct fields "esoteric" (or
internal) padding.

   We call adding space between two array elements "exoteric" (or
external) padding.

   The following sections contain examples of the two kinds of padding
and how to better handle them in Poke.


File: poke.info,  Node: Reserved fields,  Next: Payloads,  Prev: Esoteric and exoteric padding,  Up: Padding and Alignment

4.11.2 Reserved fields
----------------------

People designing binary encoded formats tend to be cautious and try to
avoid future backward incompatibilities by keeping some unused fields
that are reserved for future use.  This is the first kind of padding we
will be looking at, and is particularly common in structures like
headers.

   See for example the header used to characterize compressed section
contents in ELF files:

     type Elf64_Chdr =
       struct
       {
         Elf_Word ch_type;
         Elf_Word ch_reserved;
         offset<Elf64_Xword,B> ch_size;
         offset<Elf64_Xword,B> ch_addralign;
       };

   where the 'ch_reserved' field is reserved for future use.  When the
time comes the space occupied by that field (32 bits in this case) will
be used to hold additional data in the form of one or more fields.  The
idea is that implementations of the older formats will still work.

   The most obvious way to handle this in Poke is using a named field
like 'ch_reserved' above.  This field will be decoded/encoded by poke
when constructing/mapping/writing struct values of this type, and will
be available to the user as 'chdr.ch_reserved'.

   Sometimes reserved space is required to be filled with certain data
values, such as zeroes.  This may be to simplify things, or to force
data producers to initialize the memory in order to avoid potential
leaking of sensible information.  In these cases we can use Poke initial
values:

     type Elf64_Chdr =
       struct
       {
         Elf_Word ch_type;
         Elf_Word ch_reserved == 0;
         offset<Elf64_Xword,B> ch_size;
         offset<Elf64_Xword,B> ch_addralign;
       };

   This will make poke to check that 'ch_reserved' is zero when
constructing or mapping headers for compressed sections raising a
constraint violation exception otherwise.  It will also make poke to
make sure 'ch_reserved' to 0 when constructing 'Elf64_Chdr' struct
values:

     (poke) Elf64_Chdr { ch_reserved = 23 }
     unhandled constraint violation exception

   An alternative way to characterize reserved space in Poke is to use
anonymous fields.  For example:

     type Elf64_Chdr =
       struct
       {
         Elf_Word ch_type;
         Elf_Word;
         offset<Elf64_Xword,B> ch_size;
         offset<Elf64_Xword,B> ch_addralign;
       };

   Using Poke anonymous fields to implement reserved fields has at least
two advantages.  First, the user cannot anymore temper with the data in
the reserved space in an easy way, i.e.  'chdr.ch_reserved = 666' is no
longer valid.  Second, the printed representation of anonymous struct
fields is more compact and denotes better than the involved space is not
to be messed with:

     (poke) Elf64_Chdr {}
     Elf64_Chdr {
       ch_type=0x0U,
       0x0U,
       ch_size=0x0UL#B,
       ch_addralign=0x0UL#B
     }

   A disadvantage of using anonymous fields is that you cannot specify
constraint expressions for them, nor initial values.  At some point we
will probably add syntax to declare certain struct fields as read-only.

   At this point, it is important to note that anonymous fields are
still encoded/decoded by poke every time the struct value is mapped or
written, exactly like regular fields.  Therefore using them doesn't pose
any advantage in terms of performance.


File: poke.info,  Node: Payloads,  Next: Aligning struct fields,  Prev: Reserved fields,  Up: Padding and Alignment

4.11.3 Payloads
---------------

The reserved fields discussed in the previous section are most often
discrete units like words, double-words, and the like, they are usually
of some fixed size, and they are used to delimit some space that is not
to be used.

   Another kind of padding happens when an entity contains space to be
used to store some kind of payload whose contents are not determined.
This would be such an example:

     type Packet =
       struct
       {
         offset<uint<32>,B> payload_size;
         byte[payload_size] payload;
         int flags;
       };

   In this example we are using a 'payload' field which is an array of
bytes.  The size of the payload is determined by the packet header, and
the contents are not determined.  Of course this assumes that the
payload sizes are divisible in whole bytes; a bit-oriented format may
need to use an array of bits instead.

   This approach of using a byte (or bit) array like in the example
above has the advantage of providing a field with the bytes (or bits) to
the user, for inspection and modification:

     (poke) packet.payload
     [23UB, ...]
     (poke) packet.payload[0] = 0

   The user can still map whatever payload structure in that space using
the attributes of a mapped 'Packet'.  For example, if the packet
contains an array of ULEB128 numbers, we could do:

     (poke) var numbers = ULEB128[packet.payload'size] @ packet.payload'offset

   But this approach has a disadvantage: every time the packet structure
is mapped or written the entire payload array gets decoded and encoded.
If the payloads are big enough (think about the data blocks of a file
described by a file system i-node for example) this can be a big problem
in terms of performance.

   Another problem of using byte (or bit) arrays for payloads is that
the printed representation of the struct values include the contents of
the arrays, and most often the user won't be interested in seeing that:

     (poke) Packet { payload_size = 23#B }
     Packet {
       payload_size=0x17U#B,
       payload=[0x0UB,0x0UB,0x0UB,0x0UB,0x0UB,...],
       flags=0x0
     }

   Another alternative is to implement the padding implied by a payload
using field labels:

     type Packet =
       struct
       {
         offset<uint<32>,B> payload_size;:
         int flags @ OFFSET + payload_size;
       };

   Note how a 'payload' field no longer exists in the struct type, and
the field 'flags' is defined to start at offset 'OFFSET + payload_size'.
This way no explicit array is encoded/decoded when manipulating 'Packet'
values:

     (poke) .set omaps yes
     (poke) Packet { payload_size = 500#Mb }
     Packet {
       payload_size=62500000U#B @ 0UL#b,
       flags=0 @ 4000000032UL#b
     } @ 0UL#b

   In this example we used the 'omaps' option, which asks poke to print
the offsets of the fields.  The offset of 'flags' is 4000000032 bits, or
500 megabytes:

     (poke) 4000000032UL #b/#MB
     500UL

   Mapping this new 'Packet' involves reading and decoding five bytes,
for the 'payload_size' and 'flags' only.  This is clearly much faster
and avoids unneeded IO.

   However you may be wondering, if there is no explicit 'payload'
field, how to access the payload space?  A way is to define a method to
the struct to provide the payload attributes:

     type Packet =
       struct
       {
         offset<uint<32>,B> payload_size;:
         var payload_offset = OFFSET;
         int flags @ OFFSET + payload_size;

         method get_payload_offset = off64:
         {
           return payload_offset;
         }
       };

   Note how we captured the offset of the payload using a variable in
the strict type definition.  Returning 'OFFSET' in 'get_payload_offset'
wouldn't work for obvious reasons: in the body of the method 'OFFSET'
evaluates to the end of 'flags' in this case.

   Using this method you can easily access the payload (again as an
array of ULEB128 numbers) like this:

     var numbers = ULEB128[packet.payload_size @ packet.get_payload_offset

   Finally, using labels for this purpose makes the printed
representation of the struct values more readable by not including the
payload bytes in it:

     (poke) Packet {}
     Packet {
       payload_size=0x0U#B,
       flags=0x0
     }


File: poke.info,  Node: Aligning struct fields,  Next: Padding array elements,  Prev: Payloads,  Up: Padding and Alignment

4.11.4 Aligning struct fields
-----------------------------

Another kind of esoteric padding happens when certain fields in entities
are required to be aligned to some particular alignment.  For example,
suppose that the 'flags' field in the packets used in the previous
sections is required to always be aligned to 4 bytes regardless of the
size of the payload.  This would be a common requirement if the format
is intended to be implemented in systems where data is to be accessed
using its "natural" alignment.

   Using explicit fields for both the payload and the additional
padding, we could come with:

     type Packet =
       struct
       {
         offset<uint<32>,B> payload_size;
         byte[payload_size] payload;
         byte[alignto (OFFSET, 4#B)] padding;
         int flags;
       };

   Where 'alignto' is a little function defined in the Poke standard
library, like this:

     fun alignto = (uoff64 offset, uoff64 to) uoff64:
     {
       return (to - (offset % to)) % to;
     }

   Alternatively, using the labels approach (which is generally better
as we discussed in the last section) the definition would become:

     type Packet =
       struct
       {
         offset<uint<32>,B> payload_size;:
         var payload_offset = OFFSET;
         int flags @ OFFSET + payload_size + alignto (payload_size, 4#B);

         method get_payload_offset = off64:
         {
           return payload_offset;
         }
       };

   In this case, the payload space is still completely characterized by
the 'payload_size' field and the 'get_payload_offset' method.


File: poke.info,  Node: Padding array elements,  Prev: Aligning struct fields,  Up: Padding and Alignment

4.11.5 Padding array elements
-----------------------------

Up to now all the examples of padding we have shown are in the category
of esoteric or internal padding, i.e.  it was intended to add space
between fields of some particular entity.

   However, sometimes we want to specify some padding between the
elements of a sequence of entities.  In Poke this basically means an
array.

   Suppose we have a simple file system that is conformed by a sequence
of inodes.  The contents of the file system have the following form:

     +-----------------+
     |      inode      |
     +-----------------+
     :                 :
     :      data       :
     :                 :
     +-----------------+
     |      inode      |
     +-----------------+
     :                 :
     :      data       :
     :                 :
     +-----------------+
     |      ...        |

   That's it, each inode describes a block of data of variable size that
immediately follows.  Then more pairs of inode-data follow until the end
of the device.  However, a requirement is that each inode has to be
aligned to 128 bytes.

   Let's start by writing a simple type definition for the inodes:

     type Inode =
       struct
       {
         string filename;
         int perms;
         offset<uint<32>,B> data_size;
       };

   This definition is simple enough, but it doesn't allow us to just map
an array of inodes like this:

     (poke) Inode[]  0#B

   We could of course add the data and padding explicitly to the inode
structure:

     type Inode =
       struct
       {
         string filename;
         int perms;
         offset<uint<32>,B> data_size;
         byte[data_size] data;
         byte[alignto (data_size, 128#B) padding;
       };

   Then we could just map 'Inode[] @ 0#B' and we would the get expected
result.

   But this is not a good idea.  On one hand because, as we know, this
would imply mapping the full file system data byte by byte, and that
would be very very slow.  On the other hand, because the data is not
part of the inode, conceptually speaking.

   A better solution is to use this idiom:

     type Inode =
       struct
       {
         string filename;
         int perms;
         offset<uint<32>,B> data_size;

         byte[0] @ OFFSET + data_size + alignto (data_size, 128#B);
       };

   This uses an anonymous field at the end of the struct type, of size
zero, located at exactly the offset where the data plus padding would
end in the version with explicit fields.

   This later solution is fast and still allows us to get an array of
inodes reflecting the whole file system with:

     (poke) var inodes = Inode[] @ 0#B

   Like in the previous sections, a method =get_data_offset= can be
added to the struct type in order to allow accessing the data blocks
corresponding to a given inode.


File: poke.info,  Node: Dealing with Alternatives,  Next: Structured Integers,  Prev: Padding and Alignment,  Up: Structuring Data

4.12 Dealing with Alternatives
==============================

4.12.1 BSON
-----------

BSON (1) is a binary encoding for JSON documents.  The top-level entity
described by the spec is the 'document', which contains the total size
of the document, a sequence of elements, and a trailing null byte.

   We can describe the above in Poke with the following type definition:

     type BSON_Doc =
       struct
       {
         offset<int<32>,B> size;
         BSON_Elem[size - size'size - 1#B] elements;
         byte endmark : endmark == 0x0;
       };

   BSON elements come in different kinds, which correspond to the
different types of JSON entities: 32-bit integers, 64-bit integers,
strings, arrays, timestamps, and so on.  Every element starts with a
tag, which is a 8-bit unsigned integer that identifies it's kind, and a
name encoded as a NULL-terminated string.  What comes next depends on
the kind of element.

   The following Poke type definition describes a subset of BSON
elements, namely integers, big integers and strings:

     type BSON_Elem =
       struct
       {
         byte tag;
         string name;

         union
         {
           int32 integer32 : tag == 0x10;
           int64 integer64 : tag == 0x12;
           BSON_String str : tag == 0x02;
         } value;
       };

   The union in 'BSON_Elem' corresponds to the variable part.  When poke
decodes an union, it tries to decode each alternative (union field) in
turn.  The first alternative that is successfully decoded without
raising a constraint violation exception is the chosen one.  If no
alternative can be decoded, a constraint violation exception is raised.

   To see this process in action, let's use the BSON corresponding to
the following little JSON document:

     {
         "name" : "Jose E. Marchesi",
         "age" : 40,
         "big" : 1076543210012345
     }

   Let's take a look to the different elements:

     (poke) .load bson.pk
     (poke) var d = BSON_Doc  0#B
     (poke) d.elements'length
     0x3UL
     (poke) d.elements[0]
     BSON_Elem {
       tag=0x2UB,
       name="name",
       value=struct {
         str=BSON_String {
           size=0x11,
           value="Jose E. Marchesi",
           chars=[0x4aUB,0x6fUB,0x73UB,0x65UB...]
         }
       }
     }
     (poke) d.elements[1]
     BSON_Elem {
       tag=0x10UB,
       name="age",
       value=struct {
         integer32=0x27
       }
     }
     (poke) d.elements[2]
     BSON_Elem {
       tag=0x12UB,
       name="big",
       value=struct {
         integer64=0x3d31c3f9e3eb9L
       }
     }

   Note how unions decode into structs featuring different fields.  What
field is available depends on the alternative chosen while decoding.

   In the session above, 'd.elements[1].value' contains an 'integer32'
field, whereas 'd.elements[2].value' contains an 'integer64' field.
Let's see what happens if we try to access the wrong field:

     (poke) d.elements[1].value.integer64
     unhandled invalid element exception

   We get a run-time exception.  This kind of errors cannot be caught at
compile time, since both 'integer32' and 'integer64' are potentially
valid fields in the union value.

4.12.2 Unions are Tagged
------------------------

Unlike in C, Poke unions are tagged.  Unions have their own lexical
closures, and it is the capured values that determine what field is
chosen at every time.  Wherever the union goes, its tag accompanies it.

   To see this more clearly, consider the following alternative Poke
description of the BSON elements:

     type BSON_Elem =
       union
       {
         struct
         {
           byte tag : tag == 0x10;
           string name;
           int32 value;
         } integer32;

         struct
         {
           byte tag : tag == 0x12;
           string name;
           int64 value;
         } integer64;

         struct
         {
           byte tag : tag == 0x12;
           string name;
           BSON_String value;
         } str;
       };

   This description is way more verbose than the one used in previous
sections, but it shows a few important properties of Poke unions.

   First, the constraints guiding the decoding are not required to
appear in the union itself: it is a recursive process.  In this example,
'BSON_String' could have constraints on it's own, and these constraints
will also impact the decoding of the union.

   Second, there are generally many different ways to express the same
plain binary using different type structures.  This is no different than
getting different parse trees from the same sequence of tokens using
different grammars denoting the same language.

   See how different a BSON element looks (and feels) using this
alternative description:

     (poke) d.elements[0]
     BSON_Elem {
       str=struct {
         tag=0x2UB,
         name="name",
         value=BSON_String {
           size=0x11,
           value="Jose E. Marchesi",
           chars=[0x4aUB,0x6fUB,0x73UB,0x65UB...]
         }
       }
     }
     (poke) d.elements[1]
     BSON_Elem {
       integer32=struct {
         tag=0x10UB,
         name="age",
         value=0x27
       }
     }
     (poke) d.elements[2]
     BSON_Elem {
       integer64=struct {
         tag=0x12UB,
         name="big",
         value=0x3d31c3f9e3eb9L
       }
     }

   What is the best way?  It certainly depends on the kind of data you
want to manipulate, and the level of abstraction you want to achieve.
Ultimately, it is up to you.

   Generally speaking, the best structuring is the one that allows you
to manipulate the data in terms of the structured abstractions as
naturally as possible.  That's the art and craft of writing good
pickles.

   ---------- Footnotes ----------

   (1) http://bsonspec.org/spec.html


File: poke.info,  Node: Structured Integers,  Next: Working with Incorrect Data,  Prev: Dealing with Alternatives,  Up: Structuring Data

4.13 Structured Integers
========================

When we structure data using Poke structs, arrays and the like, we often
use the same structure than a C programmer would use.  For example, to
model ELF RELA structures, which are defined in C like:

     typedef struct
     {
       Elf64_Addr   r_offset;  /* Address */
       Elf64_Xword  r_info;    /* Relocation type and symbol index */
       Elf64_Sxword r_addend;  /* Addend */
     } Elf64_Rela;

we could use something like this in Poke:

     type Elf64_Rela =
       struct
       {
         Elf64_Addr r_offset;
         Elf64_Xword r_info;
         Elf64_Sxword r_addend;
       };

   Here the Poke struct type is pretty equivalent to the C incarnation.
In both cases the fields are always stored in the given order,
regardless of endianness or any other consideration.

   However, there are situations where stored integral values are to be
interpreted as composite data.  This is the case of the 'r_info' field
above, which is a 64-bit unsigned integer ('Elf64_Xword') which is
itself composed by several fields, depicted here:

      63                                          0
     +----------------------+----------------------+
     |       r_sym          |      r_type          |
     +----------------------+----------------------+
     MSB                                         LSB

   In order to support this kind of composition of integers, C
programmers usually resort to either bit masking (most often) or to the
often obscure and undefined behaviour-prone C bit fields.  In the case
of ELF, the GNU implementations define a few macros to access these
"sub-fields":

     #define ELF64_R_SYM(i)         ((i) >> 32)
     #define ELF64_R_TYPE(i)        ((i) & 0xffffffff)
     #define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))

   Where 'ELF64_R_SYM' and 'ELF64_R_TYPE' are used to extract the fields
from an 'r_info', and 'ELF64_R_INFO' is used to compose it.  This is
typical of C data structures.

   We could of course mimic the C implementation in Poke:

     fun Elf64_R_Sym = (Elf64_Xword i) uint<32>:
        { return i .>> 32; }
     fun Elf64_R_Type = (Elf64_Xword i) uint<32>:
        { return i & 0xffff_ffff; }
     fun Elf64_R_Info = (uint<32> sym, uint<32> type) Elf64_Xword:
        { return sym as Elf64_Xword <<. 32 + type; }

   However, this approach has a huge disadvantage: since we are not able
to encode the logic of these "sub-fields" in proper Poke fields, they
become second class citizens, with all that implies: no constraints on
their own, can't be auto-completed, can't be assigned individually, etc.

   But we can use the so-called "integral structs"!  These are structs
that are defined exactly like your garden variety Poke structs, with a
small addition:

     type Elf64_RelInfo =
       struct uint<64>
       {
         uint<32> r_sym;
         uint<32> r_type;
       };

   Note the 'uint<64>' addition after 'struct'.  This can be any integer
type (signed or unsigned).  The fields of an integral struct should be
integral themselves (this includes both integers and offsets) and the
total size occupied by the fields should be the same size than the one
declared in the struct's integer type.  This is checked and enforced by
the compiler.

   The Elf64 RELA in Poke can then be encoded like:

     type Elf64_Rela =
       struct
       {
         Elf64_Addr r_offset;
         struct Elf64_Xword
         {
           uint<32> r_sym;
           uint<32> r_type;
         } r_info;
         Elf64_Sxword r_addend;
       };

   When an integral struct is mapped from some IO space, the total
number of bytes occupied by the struct is read as a single integer
value, and then the values of the fields are extracted from it.  A
similar process is using when writing.  That is what makes it different
with respect a normal Poke struct.

   It is possible to obtain the integral value corresponding to an
integral struct using a cast to an integral type:

     (poke) type Foo = struct int<32> { int<16> hi; uint<16> lo; };
     (poke) Foo { hi = 1 } as int<32>
     0x10000

   An useful idiom, that doesn't require to specify an explicit integral
type, is this:

     (poke) type Foo = struct int<32> { int<16> hi; uint<16> lo; };
     (poke) var x = Foo @ 0#B;
     (poke) +x
     0xfe00aa

   These casts allow to "integrate" struct values explicitly, but the
compiler also implicitly promotes integral struct values to integers in
all contexts where an integer is expected:

   * Operator to an addition, subtraction, multiplication, division,
     ceil division, bit left shift, bit right shift, bit-wise not,
     bit-wise and, bit-wise or, bit-wise xor, logical and, logical or,
     logical not, logical implication, positive, negative,
     bit-concatenation, condition in conditional expression.
   * Argument to a function whose formal expects an integer.
   * Value returned from a function that returns an integer.
   * Condition in loop statement.
   * Constraint expression in a struct field.
   * Expression in a conditional struct field.

   Note that the above list doesn't include relational operators, since
these operators work with struct values.


File: poke.info,  Node: Working with Incorrect Data,  Prev: Structured Integers,  Up: Structuring Data

4.14 Working with Incorrect Data
================================

We have seen how Poke type definitions very often include constraint
expressions reflecting the integrity of the data stored in these types.

   Consider for example the following abbreviated description of the
header of an ELF file:

     type Elf64_Ehdr =
       struct
       {
         struct
         {
           byte[4] ei_mag = [0x7fUB, 'E', 'L', 'F'];
           byte ei_class;
           [...]
         } e_ident;

         Elf_Half e_type;
         Elf_Half e_machine;
         Elf_Word e_version = EV_CURRENT;
         [...]
         Elf_Half e_shstrndx : e_shnum == 0 || e_shstrndx < e_shnum;
       };

There are three constraint expressions in the definition above:

   * The constraint expression in the field 'ei_mag' makes sure that a
     right magic number begins the header.
   * The constraint expression in 'e_version' checks that the ELF
     version is the current version.
   * The constraint expression in 'e_shstrndx' checks that the index
     stored in the field doesn't overflow the section header table of
     the file.

   Every time we construct or map an 'Elf64_Ehdr' value the constraint
expressions are checked.  In case any of the constraints are not
satisfied we get a "constraint violation exception".  This is useful to
realize that we are facing invalid data (when mapping) or that we are
trying to build an invalid ELF header (when constructing.)

   However, the exception avoids the completion of the mapping or
construction operation.  Sometimes this is inconvenient:

   * When we are given invalid data that we want to explore or fix.
     Imagine for example a programmer investigating a possible assembler
     or linker bug that results in an invalid ELF file.
   * When we are discovering or inferring the structure of some data: we
     suspect at some point there may be something that is similar to an
     ELF header.
   * When we want to create invalid data.  Suppose for example a
     programmer who is building a test case for the linker, that
     requires a corrupted ELF file.

   The way poke provides support for these situation is using the
concept of "map strictness".  Suppose we map an ELF header in some IO
space:

     (poke) load elf
     (poke) var ehdr = Elf64_Ehdr @ 0#B

The mapping operator '@' performs a "strict mapping".  This means that
constraint expressions are evaluated and the operation is interrupted if
any constraint fails, as described above.  Also, this means the
integrity will be checked when the data is modified:

     (poke) ehdr.e_version = 666
     unhandled constraint violation exception

So the mapping operator generates "strict" values.  We can check the
strictness of a mapped value using the ''strict' attribute:

     (poke) ehdr'strict
     1

   If we know that we are facing corrupted data, or if we want to
corrupt the ELF header, we perform a "non-strict mapping" using a
variant of the mapping operator:

     (poke) var ehdr_ns = Elf64_Ehdr @! 0#B
     (poke) ehdr_ns'strict
     0

When mapping is performend in non-strict mode, the constraint
expressions are still executed, but their resulting value is discarded.
The constraint expressions are executed regardless of strictness because
it is fairly common for them to include side-effects that have a
calculated impact in subsequent operations, such as for example setting
the endianness or some other global state.

   We can now corrupt the header in the example above:

     (poke) ehdr_ns.e_version = 666


File: poke.info,  Node: Maps and Map-files,  Next: Writing Pickles,  Prev: Structuring Data,  Up: Top

5 Maps and Map-files
********************

Editing data with GNU poke mainly involves creating mapped values and
storing them in Poke variables.  However, this may not be that
convenient when poking several files simultaneously, and when the
complexity of the data increases.  poke provides a convenient mechanism
for this: maps and map files.

* Menu:

* Editing using Variables::     Data is usually edited mapping variables.
* poke Maps::                   Maps and map-files.
* Loading Maps::                Using maps defined in files.
* Multiple Maps::               Multiple perspectives of the same data.
* Auto-map::                    Loading maps automagically.
* Constructing Maps::           Creating and managing maps on the fly.
* Predefined Maps::             Collection of already-written maps.


File: poke.info,  Node: Editing using Variables,  Next: poke Maps,  Up: Maps and Map-files

5.1 Editing using Variables
===========================

Editing data with GNU poke mainly involves creating mapped values and
storing them in Poke variables.  For example, if we were interested in
altering the fields of the header in an ELF file, we would map an
'Elf64_Ehdr' struct at the beginning of the underlying IO space (the
file), like in:

     (poke) .file foo.o
     (poke) load elf
     (poke) var ehdr = Elf64_Ehdr @ 0#B

   At this point the variable 'ehdr' holds an 'Elf64_Ehdr' structure,
which is mapped.  As such, altering any of the fields of the struct will
update the corresponding bytes in 'foo.o'.  For example:

     (poke) ehdr.e_entry = 0#B

   A Poke value has three mapping related attributes: whether it is
mapped, the offset at which it is mapped in an IO space, and in which IO
space.  This information is accessible for both the user and Poke
programs using the following attributes:

     (poke) ehdr'mapped
     1
     (poke) ehdr'offset
     0UL#b
     (poke) ehdr'ios
     0

   That's it, 'ehdr' is mapped at offset zero byte in the IO space '#0',
which corresponds to 'foo.o':

     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #0	FILE	rw	0x00000000#B	0x000004c8#B   ./foo.o

   Now that we have the ELF header, we may use it to get access to the
ELF section header table in the file, that we will reference using
another variable 'shdr':

     (poke) var shdr = Elf64_Shdr[ehdr.e_shnum] @ ehdr.e_shoff
     (poke) shdr[1]
     Elf64_Shdr {
       sh_name=0x1bU#B,
       sh_type=0x1U,
       sh_flags=#<ALLOC,EXECINSTR>,
       sh_addr=0x0UL#B,
       sh_offset=0x40UL#B,
       sh_size=0xbUL#B,
       sh_link=0x0U,
       sh_info=0x0U,
       sh_addralign=0x1UL,
       sh_entsize=0x0UL#b
     }

   Variables are convenient entities to manipulate in Poke.  Let's
suppose that the file has a lot of sections and we want to do some
transformation in every section.  It is a time consuming operation, and
we may forget which sections we have already processed and which not.
We could create an empty array to hold the sections already processed:

     (poke) var processed = Elf64_Shdr[] ()

   And then, once we have processed some given section, add it to the
array:

     ... edit shdr[23] ...
     (poke) processed += [shdr[23]]

   Note how the array =processed= is not mapped, but the sections
contained in it are mapped: Poke uses copy by shared value.  So, after
we spend the day carefully poking our ELF file, we can ask poke, are we
done with all the sections in the file?

     (poke) shdr'length == processed'length
     1

   Yes, we are.  This can be made as sophisticated as desired.  We could
easily write a function that saves the contents of 'processed' in files,
so we can continue hacking tomorrow, for example.

   We can then concluding that using mapped variables to edit data
structures stored in IO spaces works well in common and simple cases
like the above: we make our ways mapping here and there, defining
variables to hold data that interests us, and it is easy to remember
that the variables 'ehdr' and 'shdr' are mapped, where are they mapped,
and that they are mapped in the file 'foo.o'.

   However, GNU poke allows to edit more than one IO space
simultaneously.  Let's say we now want to poke the sections of another
ELF file: 'bar.o'.  We would start by opening the file:

     (poke) .file bar.o
     (poke) .info ios
       Id	Type	Mode	Bias		Size		Name
     * #1	FILE	rw	0x00000000#B	0x000004c8#B	./bar.o
       #0	FILE	rw	0x00000000#B	0x000004c8#B	./foo.o

   Now that 'bar.o' is the current IO space, we can map its header.  But
now, what variable to use?  We would rather not redefine 'ehdr', because
that is already holding the header of 'foo.o'.  We could adapt our
naming schema on the fly:

     (poke) var foo_ehdr = ehdr
     (poke) var bar_ehdr = Elf64_Ehdr @ 0#B

   But then we would need to do the same for the other variables too:

     (poke) var foo_shdr = shdr
     (poke) var bar_shdr = Elf64_Shdr[bar_ehdr.e_shnum] @ bar_ehdr.e_shoff

   However, we can easily see how this can degenerate quickly: what
about 'processed', for example?  In general, as the number of IO spaces
being edited increases it becomes more and more difficult to manage our
mapped variables, which are associated to each IO space.


File: poke.info,  Node: poke Maps,  Next: Loading Maps,  Prev: Editing using Variables,  Up: Maps and Map-files

5.2 poke Maps
=============

As we have seen mapping variables is a very powerful, general and
flexible mean to edit stored binary data in one or more IO spaces.
However it is easy to lose track of where the variables are mapped and,
ideally speaking, we would want to have a mean to refer to, say, the
"ELF header", and get the header as a mapped value regardless of what
specific file we are editing.  Sort of a "meta variable".  GNU poke
provides a way to do this: "maps".

   A "map" can be conceived as a sort of "view" that can be applied to a
given IO space.  Maps have entries, which are values mapped at some
given offset, under certain conditions.  For example, we have seen an
ELF file contains, among other things, a header at the beginning of the
file and a table of section headers of certain size and located at
certain location determined by the header.  These would be two entries
of a so-called ELF map.

   poke maps are defined in "map files".  These files use the '.map'
extension.  A map file 'self.map' (for sectioned/simple elf) defining
the view of an ELF file as a header and a table of section header would
look like this:

     /* self.map - map file for a simplified view of an ELF file.  */

     load elf;

     %%

     %entry
     %name ehdr
     %type Elf64_Ehdr
     %offset 0#B

     %entry
     %name shdr
     %type Elf64_Shdr[(Elf64_Ehdr @ 0#B).e_shnum]
     %condition (Elf64_Ehdr @ 0#B).e_shnum > 0
     %offset (Elf64_Ehdr @ 0#B).e_shoff

   This map file defines a view of an ELF file as a header entry 'ehdr'
and an entry with a table of section headers 'shdr'.

   The first section of the file, which spans until the separator line
containing '%%', is arbitrary Poke code which as we shall see, gets
evaluated before the map entries are processed.  This is called the map
"prologue".  In this case, the prologue contains a comment explaining
the purpose of the file, and a single statement 'load' that loads the
'elf.pk' pickle, since the entries below use definitions like
'Elf64_Ehdr' that are defined by that pickle.  The prologue is useful to
define Poke functions and other entities that are then used in the
definitions of the entries.

   A separator line containing only '%%' separates the prologue from the
next section, which is a list of entries definitions.  Each entry
definition starts with a line '%entry', and has the following
attributes:

'%name'
     Like 'ehdr' and 'shdr'.  These names should follow the same rules
     than Poke variables, but as we shall see later, map entries are not
     Poke variables.  This attribute is mandatory.

'%type'
     This can be any Poke expression denoting a type, like 'int',
     'Elf64_Ehdr' or 'Elf64_Shdr[(Elf64_Ehdr @ 0#B).e_shnum]'.  This
     attribute is mandatory.

'%condition'
     If specified, will determine whether to include the entry in the
     map.  In the example above, the map will have an entry 'shdr' only
     if the ELF file has one or more sections.  Any Poke expression
     evaluating to a boolean can be used as conditions.  This attribute
     is optional: entries not having a condition will always be included
     in the map.

'%offset'

     Offset in the IO space where the entry will be mapped.  Any Poke
     expression evaluating to an offset can be used as entry offset.
     This attribute is mandatory.


File: poke.info,  Node: Loading Maps,  Next: Multiple Maps,  Prev: poke Maps,  Up: Maps and Map-files

5.3 Loading Maps
================

So we have written our =self.map=, which denotes a view or structure of
ELF files we are interested on, and that resides in the current working
directory.  How to use it?

   The first step is to fire up poke and open some object file.  Let's
start with 'foo.o':

     (poke) .file foo.o

Now, we can load the map using the '.map load' dot-command:

     (poke) .map load self
     [self](poke)

   The '.map load self' command makes poke to look in certain
directories for a file called 'self.map', and to load it.  The list of
directories where poke looks for map files is encoded in the variable
'map_load_path' as a string containing a maybe empty list of directories
separated by ':' characters.  Each directory is tried in turn.  This
variable is initialized with suitable defaults:

     (poke) map_load_path
     "/home/jemarch/.poke.d:.:/home/jemarch/.local/share/poke:[...]"

   Once a map is loaded, observe how the prompt changed to contain a
prefix '[self]'.  This means that the map 'self' is loaded for the
current IO space.  You can choose to not see this information in the
prompt by setting the 'prompt-maps' option either at the prompt or in
your '.pokerc':

     poke) .set prompt-maps no

   By default 'prompt-maps' is 'yes'.  This prompt aid is intended to
provide a cursory look of the "views" or maps loaded for the current IO
space.  If we load another IO space and switch to it, the prompt changes
accordingly:

     (poke) [self](poke) .mem foo
     The current IOS is now `*foo*'.
     (poke) .ios #0
     The current IOS is now `./foo.o'.
     [self](poke)

   At any time the '.info maps' dot-command can be used to obtain a full
list of loaded maps, with more information about them:

     (poke) .info maps
     IOS   Name   Source
     #0    self   ./self.map

   In this case, there is a map 'self' loaded in the IO space '#0',
which corresponds to 'foo.o'.

   Once we make 'foo.o' our current IO space, we can ask poke to show us
the entries corresponding to this map using another dot-command:

         : (poke) .map show self
         : Offset     Entry
         : 0x0UL#B    $self::ehdr
         : 0x208UL#B  $self::shdr

   This tells us there are two entries for 'self' in 'foo.o':
'$self::ehdr' and '$self::shdr=' Note how map entries use names that
start with the '$' character, then contain the name of the map an the
name of the entry we defined in the map file, separated by '::'.

   We can now use these entries at the prompt like if they were regular
mapped variables:

     [self](poke) $self::ehdr
     Elf64_Ehdr {
       e_ident=struct {
         ei_mag=[0x7fUB,0x45UB,0x4cUB,0x46UB],
         [...]
       },
      e_type=0x1UH,
      e_machine=0x3eUH,
      [...]
     }
     (poke) $self::shdr'length
     11UL

   It is important to note, however, that map entries like '$foo::bar'
are _not_ part of the Poke language, and are only available when using
poke interactively.  Poke programs and scripts can't use them.

   Let's now open another ELF file, and the =self= map in it:

     (poke) .file /usr/local/lib/libpoke.so.0.0.0
     (poke) .map load self
     [self](poke)

   So now we have two ELF files loaded in poke: 'foo.o' and
'libpoke.so.0.0.0', and in both IO spaces we have the 'self' map loaded.
We can easily see that the map entries are different depending on the
current IO space:

     [self](poke) .map show self
     Offset       Entry
     0UL#B        $self::ehdr
     3158952UL#B  $self::shdr
     [self](poke) .ios #0
     The current IOS is now `./foo.o'.
     [self](poke) .map show self
     Offset   Entry
     0UL#B    $self::ehdr
     520UL#B  $self::shdr

'foo.o' is an object file, whereas 'libpoke.so.0.0.0' is a DSO:

     (poke) .ios #0
     The current IOS is now `./foo.o'.
     [self](poke) $self::ehdr.e_type
     1UH
     [self](poke) .ios #2
     The current IOS is now `/usr/local/lib/libpoke.so.0.0.0'.
     [self](poke) $self::ehdr.e_type
     3UH

   The interpretation of the map entry '$self::ehdr' is different
depending on the current IO space.  This makes it possible to refer to
the "ELF header" of the current file.

   Underneath, poke implements this by defining mapped variables and
"redirecting" the entry names '$foo::bar' to the right variable
depending on the IO space that is currently selected.  It hides all that
complexity from us.


File: poke.info,  Node: Multiple Maps,  Next: Auto-map,  Prev: Loading Maps,  Up: Maps and Map-files

5.4 Multiple Maps
=================

It is perfectly possible (and useful!)  to load more than one map in the
same IO space.  It is very natural for a single file, for example, to
contain data that can be interpreted in several ways, or of different
nature.

   Let's for example open again an ELF file, this time compiled with
'-g':

     (poke) .file foo.o

   We now load our 'self' map, to get a view of the file as a collection
of sections:

     (poke) .map load self
     [self](poke)

   And now we load the 'dwarf' map that comes with poke, to get a view
of the file as having debugging information encoded in DWARF:

     [self(poke) .map load dwarf
     [dwarf,self](poke)

   See how the prompt now reflects the fact that the current IO space
contains DWARF info!  Let's take a look:

     [dwarf,self](poke) .info maps
     IOS   Name    Source
     #0    dwarf   /home/jemarch/gnu/hacks/poke/maps/dwarf.map
     #0    self    ./self.map
     [dwarf,self](poke) .map show dwarf
     Offset    Entry
     0x5bUL#B  $dwarf::info

   Now we can access entries from any of the loaded maps, i.e.  access
the file in terms of different perspectives.  As an ELF file:

     [dwarf,self](poke) $self::shdr[1]
     Elf64_Shdr {
       sh_name=0xb5U#B,
       sh_type=0x11U,
       sh_flags=#<>,
       sh_addr=0x0UL#B,
       sh_offset=0x40UL#B,
       sh_size=0x8UL#B,
       sh_link=0x18U,
       sh_info=0xfU,
       sh_addralign=0x4UL,
       sh_entsize=0x4UL#b
     }

And as a file containing DWARF info:

     [dwarf,self](poke) $dwarf::info
     Dwarf_CU_Header {
       unit_length=#<0x0000004eU#B>,
       version=0x4UH,
       debug_abbrev_offset=#<0x00000000U#B>,
       address_size=0x8UB#B
     }

   If you are curious about how the DWARF entries are defined, look at
'maps/dwarf.map' in the poke source distribution, or in your installed
poke ('.info maps' will tell you the file the map got loaded from.)

   It is possible to unload or remove a map from a given IO space using
the '.map remove' dot-command.  Say we are done looking at the DWARF in
'foo.o', and we are no longer interested in it as a file containing
debugging info.  We can do:

     [dwarf,self](poke) .map remove dwarf
     [self](poke)

   Note how the prompt was updated accordingly: only 'self' remains as a
loaded map on this file.


File: poke.info,  Node: Auto-map,  Next: Constructing Maps,  Prev: Multiple Maps,  Up: Maps and Map-files

5.5 Auto-map
============

Certain maps make sense when editing certain types of data.  For
example, 'dwarf.map' is intended to be used in ELF files.  In order to
ease using maps, poke provides a feature called "auto mapping", which is
disabled by default.

You can set auto mapping like this:

     (poke) .set auto-map yes

   When auto mapping is enabled, poke will look to the value of the
pre-defined variable 'auto_map', which must contain an array of pairs of
strings, associating a regular expression with a map name.

   For example, you may want to initialize 'auto_map' like this in your
'.pokerc' file:

     auto_map = [[".*\\.mp3$", "mp3"],
                 [".*\\.o$", "elf"],
                 ["a\\.out$", "elf"]];

   This will make poke to load =mp3.map= for every file whose name ends
with '.mp3', and 'elf.map' for files having names like 'foo.o' and
'a.out'.

   Following the usual pokeish philosophy of being as less as intrusive
by default as possible, the default value of 'auto_map' is the empty
string.


File: poke.info,  Node: Constructing Maps,  Next: Predefined Maps,  Prev: Auto-map,  Up: Maps and Map-files

5.6 Constructing Maps
=====================

As we have seen, we can define our own maps using map files like
'self.map', which contain a prologue and a set of map entries.  However,
sometimes it is useful to create maps "on the fly" while we explore some
data with poke.

   To make this possible, poke provides a suitable set of dot-commands.
Let's say we are poking some data, and we want to create a map for it.
We can do that like this:

     (poke) .map create mymap

This creates an empty map named 'mymap', with no entries:

     [mymap](poke) .map show mymap
     Offset   Entry

   Adding entries is easy.  First, we have to map some variable, and
then use it as the base for the new entry:

     [mymap](poke) var foo = int[3]  0#B
     [mymap](poke) .map entry add mymap, foo
     [mymap](poke) .map show mymap
     Offset   Entry
     0x0UL#B  $mymap::foo

   Note how the entry '$mymap::foo' gets created, associated to the
current IO space and mapped at the same offset than the variable 'foo'.

   We can remove entries from existing maps using the '.map entry
remove' dot-command:

     [mymap](poke) .map entry remove mymap, foo
     [mymap](poke) .map show mymap
     Offset   Entry
     [mymap](poke)

   We plan to add an additional command to save maps to map files.  The
idea is that you can create your maps on the fly, save them, and then
load them back some other day when you are ready to continue poking.
This is not implemented yet though.


File: poke.info,  Node: Predefined Maps,  Prev: Constructing Maps,  Up: Maps and Map-files

5.7 Predefined Maps
===================

GNU poke comes with a set of useful pre-written maps, which get
installed in a system location.  We want to expand this collection, so
please send us your map files!


File: poke.info,  Node: Writing Pickles,  Next: Writing Binary Utilities,  Prev: Maps and Map-files,  Up: Top

6 Writing Pickles
*****************

GNU poke encourages the user to write little pieces of code in order to
face spontaneous needs and fix situations.  Is that name in the file
encoded in a fixed array of characters padded with white spaces?  No
problem, just write a three lines function so you can update the file
using a comfortable NULL-terminated string.  Better than waiting for
some poke maintainer to add that function for you, isn't it?

   Just save your functions in some personal '.pk' file that you load at
startup, and your magic tricks bag will increase in time, making your
poking more and more efficient.

   However, when it comes to share the code with other people, it is
important to follow certain conventions in order to achieve certain
uniformity.  This makes it easier for other people to discover what your
hack provides, and how it works.  It is this consistency, and these
conventions, that makes some random '.pk' file a "pickle".

   This guide contains guidelines and recommendations for the pickle's
writer.

* Menu:

* Pretty-printers::		Conventions for pretty-printed output.
* Setters and Getters::		Anatomy getters and setters.


File: poke.info,  Node: Pretty-printers,  Next: Setters and Getters,  Up: Writing Pickles

6.1 Pretty-printers
===================

6.1.1 Convention for pretty-printed Output
------------------------------------------

Very often the structure of the data encoded in binary is not very
intelligible.  This is because it is usual for binary formats to be
designed with goals in mind other than being readable by humans:
compactness, detail etc.

   In our pickle we of course want to provide access to the very finer
detail of the data structures.  However, we also want for the user to be
able to peruse the data visually, and only look at the fine detail on
demand.

   Consider for example an ID3V1 tag data from some MP3 file.  This is
the result of mapping a 'ID3V1_Tag':

     ID3V1_Tag {
       id=[0x54UB,0x41UB,0x47UB],
       title=[0x30UB,0x31UB,0x20UB,0x2dUB,0x20UB,...],
       artist=[0x4aUB,0x6fUB,0x61UB,0x71UB,0x75UB,...],
       album=[0x4dUB,0x65UB,0x6eUB,0x74UB,0x69UB,...],
       year=[0x20UB,0x20UB,0x20UB,0x20UB],
       data=struct {
         extended=struct {
           comment=[0x20UB,0x20UB,0x20UB,0x20UB,0x20UB,...],
           zero=0x0UB,
           track=0x1UB
         }
       },
       genre=0xffUB
     }

   Not very revealing.  Fortunately, poke supports pretty printers.  If
a struct type has a method called '_print', it will be used by poke as a
pretty printer if the 'pretty-print' option is set:

     (poke) .set pretty-print yes

   By convention, the output of pretty-printers should always start with
'#<' and end with '>'.  The convention makes it explicit for the user
that everything she sees between '#<' and '>' is pretty-printed, and do
_not_ necessarily reflect the physical structure of the data.  Also some
information may be missing.  In order to get an exact and complete
description of the data, the user should '.set pretty-print no' and
evaluate the value again at the prompt.

   For example, in the following BPF instructions it is obvious at first
sight that the shown register values are pretty-printed:

     BPF_Insn = {
       ...
       regs=BPF_Regs {
          src=#<%r3>,
          dst=#<%r0>
       }
       ...
     }

   If the pretty-printed representation spans for more than one line,
please place the opening '#<' in its own line, then the lines with the
data, and finally '>' in its own line, starting at column 0.

   Example of the MP3 tag above, this time pretty-printed:

     #<
       genre: 255
       title: 01 - Eclipse De Mar
       artist: Joaquin Sabina
       album: Mentiras Piadosas
       year:
       comment:
       track: 1
     >

6.1.2 Pretty Printing Optional Fields
-------------------------------------

Let's say we are writing a pretty-printer method for a struct type that
has an optional field.  Like for example:

     type Packet =
       struct
       {
         byte magic : magic in [MAGIC1,MAGIC2];
         byte n;
         byte[n] payload;
         if (magic == MAGIC2)
          PacketTrailer trailer;
       }

In this case, the struct value will have a 'trailer' conditionally,
which has to be tackled on the pretty-printer somehow.

   An approach that often works good is to replicate the logic in the
optional field condition expression, like this:

       struct
       {
         byte magic : magic in [MAGIC1,MAGIC2];
         [...]
         PacketTrailer trailer if packet_magic2_p (magic);

         method _print = void:
         {
           [...]
           if (magic == MAGIC2)
             pretty_print_trailer;
         }
       }

This works well in this simple example.  In case the expression is big
and complicated, we can avoid rewriting the same expression by
encapsulating the logic in a function:

     fun packet_magic2_p = int: { return magic == MAGIC2; }
     type Packet =
       struct
       {
         byte magic : magic in [MAGIC1,MAGIC2];
         [...]
         if (packet_magic2_p (magic))
         PacketTrailer trailer;

         method _print = void:
         {
           [...]
           if (packet_magic2_p (magic))
             pretty_print_trailer;
         }
       }

However, this may feel weird, as the internal logic of the type somehow
leaks its natural boundary into the external function 'packet_magic2_p'.

   An alternative is to use the following idiom, that checks whether the
field actually exists in the struct:

     type Packet =
       struct
       {
         byte magic : magic in [MAGIC1,MAGIC2];
         [...]
         if (packet_magic2_p (magic))
           PacketTrailer trailer;

         method _print = void:
         {
           [...]
           try pretty_print_trailer;
           catch if E_elem {}
         }
       }

This approach also works with unions:

     type ID3V1_Tag =
       struct
       {
         [...]
         union
         {
           /* ID3v1.1  */
           struct
           {
             char[28] comment;
             byte zero = 0;
             byte track : track != 0;
           } extended;
           /* ID3v1  */
           char[30] comment;
         } data;
         [...]

         method _print = void:
         {
           [...]
           try print "  comment: " + catos (data.comment) + "\n";
           catch if E_elem
           {
             print "  comment: " + catos (data.extended.comment) + "\n";
             printf "  track: %u8d", data.extended.track;
           }
         }
       }


File: poke.info,  Node: Setters and Getters,  Prev: Pretty-printers,  Up: Writing Pickles

6.2 Setters and Getters
=======================

Given a struct value, the obvious way to access the value of a field is
to just refer to it using dot-notation.

   For example, for the following struct type:

     type ID3V1_Tag =
       struct
       {
         [...]
         char[30] title;
         char[30] artist;
         char[30] album;
         char[4] year;
         [...]
       }

   Suppose the find out the year in the tag is wrong, off by two years:
the song was release in 1980, not in 1978!.  Unfortunately, due to the
bizarre way the year is stored in the file (as a sequence of digits
encoded in ASCII, non-NULL terminated) we cannot just write:

     (poke) tag.year = tag.year + 2
     error

   Instead, we can use facilities from the standard library and a bit of
programming:

     (poke) stoca (format ("%d", atoi (catos (tag.year)) + 2), tag.year)

   The above line basically transforms the data we want to operate on
(the tag year) from the stored representation into a more useful
representation (from an array of character digits to an integer) then
operates with it (adds two) then converts back to the stored
representation.  Let's call this "more useful" representation the
"preferred representation".

   A well written pickle should provide "getter" and "setter" methods
for fields in struct types for which the stored representation is not
the preferred representation.  By convention, getter and setter methods
have the following form:

     method get_FIELD PREFERRED_TYPE: { ... }
     method set_FIELD (PREFERRED_TYPE val) void: { ... }

Using the 'get_' and 'set_' prefixes consistently is very important,
because the pokist using your pickle can easily find out the available
methods for some given value using tab-completion in the REPL.

   For example, let's add setter and getter methods for the field 'year'
in the ID3V1 tag struct above:

     type ID3V1_Tag =
       struct
       {
         [...]
         char[4] year;

         method get_year = int: { return atoi (catos (year)); }
         method set_year = (int val) void:
         {
           var str = format ("%d", val);
           stoca (str, year);
         }
         [...]
       }

   What constitutes the preferred representation of a field is up to the
criteria of the pickle writer.  For the tag above, I would say the
preferred representations for the title, artist, album and year are
string for title, artist and album, and an integer for the year.


File: poke.info,  Node: Writing Binary Utilities,  Next: Configuration,  Prev: Writing Pickles,  Up: Top

7 Writing Binary Utilities
**************************

GNU poke is, first and foremost, intended to be used as an interactive
editor, either directly on the command line or using a graphical user
interface built on it.  However, since its conception poke was intended
to also provide a suitable and useful foundation on which other
programs, the so-called "binary utilities", could be written.  This
chapter shows how to write Poke scripts and programs.

* Menu:

* Poke Scripts::                Using poke as an interpreter.
* Command-Line Arguments::      Handling command-line arguments.
* Exiting from Scripts::        Exit with an error status.
* Loading pickles as Modules::  Importing pickles in programs.
* elfextractor::                An example Poke binary utility.
* Filters::                     Writing filters for binary data.


File: poke.info,  Node: Poke Scripts,  Next: Command-Line Arguments,  Up: Writing Binary Utilities

7.1 Poke Scripts
================

In interactive usage, there are two main ways to execute Poke code: at
the interactive prompt (or REPL), and loading "pickles".

   Executing Poke code at the REPL is as easy as introducing a statement
or expression:

     (poke) print "Hello\n"
     Hello

   Executing Poke code in a pickle is performed by loading the file
containing the code:

     (poke) .load say-hello.pk
     Hello

Where 'say-hello.pk' contains simply:

     print "Hello\n";

   However, we would like to have Poke scripts, i.e.  to be able to
execute Poke programs as standalone programs, from the shell.  In other
words, we want to use GNU poke as an interpreter.  This is achieved by
using a shebang, which should appear at the top of the script file.  The
poke shebang looks like this:

     #!/usr/bin/poke -L
     !#

   The '-L' command line option tells poke that it is being used as an
interpreter.  Additional arguments for poke can be specified before '-L'
(but not after).  The '#! ... !#' is an alternative syntax for
multi-line comments, which allows to have the shebang at the top of a
Poke program without causing a syntax error.  This nice trick has been
borrowed from guile.

   Therefore, we could write say-hello as a Poke script like this:

     #!/usr/bin/poke -L
     !#

     print "Hello\n";

And then execute it like any other program or script:

     $ ./say-hello


File: poke.info,  Node: Command-Line Arguments,  Next: Exiting from Scripts,  Prev: Poke Scripts,  Up: Writing Binary Utilities

7.2 Command-Line Arguments
==========================

When a Poke script is executed, the command line arguments passed to the
script become available in the array argv.  Example:

     #!/usr/bin/poke -L
     !#

     for (arg in argv)
       print "Argument: " + arg + "\n";

Executing this script results in:

     $ ./printargs foo bar 'baz quux'
     Argument: foo
     Argument: bar
     Argument: baz quux

   Note how it is not needed to have an argc variable, since the number
of elements stored in a Poke array can be queried using an attribute:
'argv'length'.

   Note also that 'argv' is only defined when poke runs as an
interpreter:

     $ poke
     [...]
     (poke) argv
     <stdin>:1:1: error: undefined variable 'argv'
     argv;
     ^~~~

   Accessing the 'argv' is more than enough for many simple programs.
However, we may need a more sophisticated handling of command-line
options: support for both short and long style options, adherence to the
GNU coding standards, and the like.  For these cases poke provides a
pickle 'argp'.  *Note argp::.


File: poke.info,  Node: Exiting from Scripts,  Next: Loading pickles as Modules,  Prev: Command-Line Arguments,  Up: Writing Binary Utilities

7.3 Exiting from Scripts
========================

By default a Poke script will communicate a successful status to the
environment, upon exiting:

     $ cat hello
     #!/usr/bin/poke -L
     !#

     print "hello\n";
     $ ./hello && echo $?
     0

   In order to exit with some other status code, most typically to
signal an erroneous situation, the Pokeish way is to raise an 'E_exit'
exception with the desired exit status code:

     raise Exception { code = EC_exit, exit_status = 1 };

   This can be a bit cumbersome to write, so poke provides a more
conventional syntax in the form of an 'exit' function:

     fun exit = (int<32> exit_code = 0) void:
     {
       raise Exception { code = EC_exit, exit_status = exit_code };
     }

Using 'exit', the above raise statement becomes the much simpler:

     exit (1);


File: poke.info,  Node: Loading pickles as Modules,  Next: elfextractor,  Prev: Exiting from Scripts,  Up: Writing Binary Utilities

7.4 Loading pickles as Modules
==============================

Suppose we want to write a Poke program to extract the contents of
sections in a given ELF object file.  Extracting sections requires
dealing with several data structures encoded in the ELF file, such as
the header, the section header table, the string table (that contains
the names of the sections) and so on.  It would be of course possible to
define Poke types for these structures in the script itself but, as it
happens, GNU poke ships with an already written pickle that describes
the ELF structures.  It is called 'elf.pk'.

   So a script needing to mess with ELF data structures can just make
use of 'elf.pk' using the load construction:

     load elf;

   This looks for a file called 'elf.pk' in a set of directories, which
are predefined by poke, and loads it.  The list of directories where
poke looks for pickles is stored in the load_path variable as a colon
separated list of directory names, and can be customized:

     $ poke
     [...]
     (poke) load_path
     "/home/jemarch/.poke.d:.:/home/jemarch/.local/share/poke:..."

   The default value of 'load_path' contains both user-specific
directories and system-wide directories.  This assures that all the
pickles installed by poke are available, and that the user can load her
own pickles in her scripts.

   Once a pickle is loaded in a script the types, functions and
variables defined in it (either directly or indirectly by loading its
own pickles) become available.


File: poke.info,  Node: elfextractor,  Next: Filters,  Prev: Loading pickles as Modules,  Up: Writing Binary Utilities

7.5 elfextractor
================

As an example, in this section we will be hacking a very simple utility
called elfextractor, that extracts the contents of the sections of an
ELF file, whose name is provided as an argument in the command line,
into several output files.  This is the synopsis of the program:

     elfextractor FILE [SECTION_NAME]

   Where FILE is the name of the ELF file from which to extract
sections, and an optional SECTION_NAME specifies the name of the section
to extract.

   Say we have a file 'foo.o' and we would like to extract its text
section.  We would use elfextractor like:

     $ elfextractor foo.o .text

   Provided 'foo.o' indeed has a section named '.text', the utility will
create a file 'foo.o.text' with the section's contents.  Note how the
names of the output files are derived concatenating the name of the
input ELF file and the name of the extracted section.

   If no section name is specified, then all sections are extracted.
For example:

     $ elfextractor foo.o
     $ ls foo.o*
     foo.o          foo.o.eh_frame       foo.o.shstrtab  foo.o.symtab
     foo.o.comment  foo.o.rela.eh_frame  foo.o.strtab    foo.o.text

   This is a possible implementation of elfextractor:

     #!/usr/bin/poke -L
     !#

     /* elfextractor - Extract sections from ELF64 files. */

     load elf;

     if (!(argv'length in [1,2]))
       {
         print "Usage: elfextractor FILE [SECTION_NAME]\n";
         exit (1);
       }

     var file_name = argv[0];
     var section_name = (argv'length > 1) ? argv[1] : "";

     try
       {
         var fd = open (file_name, IOS_M_RDONLY);
         var elf = Elf64_File @ fd : 0#B;

         for (shdr in elf.shdr where shdr.sh_type != 0x0)
           {
             var sname = elf.get_string (shdr.sh_name);

             if (section_name == "" || sname == section_name)
               save :ios elf'ios :file file_name + sname
                    :from shdr.sh_offset :size shdr.sh_size;
           }

         close (fd);
       }
     catch (Exception e)
       {
         if (e == E_constraint)
           printf ("error: `%s' is not a valid ELF64 file\n", file_name);
         else if (e == E_io)
           printf ("error: couldn't open file `%s'\n", file_name);
         else
           raise e;

         exit (1);
       }

   First the command line arguments are handled.  The script checks
whether the right number of arguments have been passed (either 1 or 2)
exiting with an error code otherwise.  The file name and the section
name are then extracted from the 'argv' array.

   Once we have the file name and the optional desired section name, it
is time to do the real work.  The code is enclosed in a try-catch block
statement, because some of the operations may result on exceptions being
raised.

   First, the ELF file whose name is specified in the command line is
opened for reading:

     var fd = open (file_name, IOS_M_RDONLY);

   The built-in function 'open' returns a file descriptor that can be
subsequently used in mapping operations.  If the provided file name
doesn't identify a file, or if the file can't be read for whatever
reason, an 'E_io' exception is raised.  Note how the exception is
handled in the 'catch' block, emitting an appropriate diagnostic message
and exiting with an error status.

   Once the ELF file is open for reading, we map an 'Elf64_File' on it,
at the expected offset (zero bytes from the beginning of the file):

     var elf = Elf64_File @ fd : 0#B;

   If the file doesn't contain valid ELF data, this map will fail and
raise an 'E_constraint' exception.  Again, the 'catch' block handles
this situation.

   At this point the variable 'elf' contains an 'Elf64_File'.  Since we
want to extract the sections contained in the file, we need to somehow
iterate on them.  The section header table is available in 'elf.shdr'.
A for-in-where loop is used to iterate on all the headers, skipping the
"null" ELF sections which are always empty, and are characterized by a
'shdr.sh_type' of 0.  An inner conditional filters out sections whose
name do not match the provided name in the command line, if it was
specified at all.

   For each matching section we then save its contents in a file named
after the input ELF file, by calling a function 'save', which is
provided by poke:

     save :ios elf'ios :file file_name + sname
          :from shdr.sh_offset :size shdr.sh_size;

   The above is exactly what we would have written at the poke REPL!
(modulus trailing semicolon).  How is this supposed to work?  Thing is,
GNU poke commands are implemented as Poke functions.  Let's consider
'save', for example.  It is defined as a function having the following
prototype:

     fun save = (int ios = get_ios,
                 string file = "",
                 off64 from = 0#B,
                 off64 size = 0#B,
                 int append = 0,
                 int verbose = 0) void:
     { ... }

   Once a Poke function is defined in the environment, it becomes
available as such.  Therefore, in a poke session we could call it like:

     (poke) save (get_ios, "filename", 0#B, 12#B, 0, 1)

   However, this is cumbersome and error prone.  To begin with, we
should remember the name, position and nature of each argument accepted
by the command.  What is even more annoying, we are forced to provide
explicit values for them, like in the example above we have to pass the
current IOS (the default), and 0 for 'append' (the default) just to
being able to set 'verbose'.  Too bad.

   To ease commanding poke, the Poke language supports an alternative
syntax to call functions, in which the function arguments are referred
by name, can be given in any order, and can be omitted.  The command
above can be thus written like:

     (poke) save :from 0#B :size 12#B :verbose 1

   This syntax is mostly intended to be used interactively, but nothing
prevents to use it in Poke programs and scripts whenever it is deemed
appropriate, like we did in elfextractor.  We could of course have used
the more conventional syntax:

     if (section_name == "" || sname == section_name)
       save (elf'ios, file_name + sname,
             shdr.sh_offset, shdr.sh_size, 0, 0);

What style to use is certainly a matter of taste.

   Anyhow, once the sections have been written out, the file descriptor
is closed and the program exits with the default status, which is
success.  Should the 'save' function find any problem saving the data,
such as a full disk, not enough permissions or the like, exceptions will
be raised, caught and maybe handled by our 'catch' block.

   And this is it!  The complete program is 44 lines long.  This is a
good example that shows how, given a pickle providing a reasonable
description of some binary-oriented format (ELF in this case) poke can
be leveraged to achieve a lot in a very concise way, free from the many
details involved in the encoding, reading and writing of binary data.


File: poke.info,  Node: Filters,  Prev: elfextractor,  Up: Writing Binary Utilities

7.6 Filters
===========

The classic notion of "filter" in Unix-like systems and other Operating
Systems is of a program that reads certain input using its standard
input, realized some transformations on it, and writes the result on its
standard output.  The filter doesn't need to operate on all the data at
once, nor to buffer it: it reads input in chunks once it becomes
available and is needed, and write output as necessary.

   GNU poke provides the so called "stream IO spaces" in order to
implement binary utilities that act like filters.

* Menu:

* Stream IO Spaces::      Standard input, output and error streams.
* Reading from Streams::  Reading and flushing input streams.
* Writing to Streams::    Writing and flushing output streams.
* pk-strings::            Putting everything together with a simple example.


File: poke.info,  Node: Stream IO Spaces,  Next: Reading from Streams,  Up: Filters

7.6.1 Stream IO Spaces
----------------------

GNU poke provides support for opening and operating on several kinds of
IO spaces: files, memory buffers, process memory, etc.  An IO space can
be opened for reading, for writing or both, and they all can be accessed
randomly, i.e.  to read or write some data from/to a particular offset
in the IO space.

   Writing a filter would involve to peek data from the standard input
and then poke the data (maybe transformed) to the standard output or the
standard error output.  However, we know that these devices are not
random oriented devices that can be accessed at any offset, but rather
stream-like devices whose special characteristics are:

   - They are either read-only or write-only.  You cannot write to an
     input stream and you cannot read from an output stream.
   - Once data is read from an input stream, it can't be read again.  It
     is not buffered.
   - Once data is written to an output stream, it can't be altered
     again.

Given the above characteristics of streams like the standard input and
output, it is clear we cannot use the File IO streams on them.  It is
also not clear how could we perform a map operation on a stream device:
in poke these operations always require an explicit offset.

   GNU poke solves this by providing three special IO spaces that the
user can open using the following handlers:

'<stdin>'
     Read-only stream IOS that is connected to the standard input of the
     poke process.
'<stdout>'
     Write-only stream IOS that is connected to the standard output of
     the poke process.
'<stderr>'
     Write-only stream IOS that is connected to the standard error of
     the poke process.

Opening these IO spaces is done exactly like with any other IO space.
Example:

     var stdin = open ("<stdin>");


File: poke.info,  Node: Reading from Streams,  Next: Writing to Streams,  Prev: Stream IO Spaces,  Up: Filters

7.6.2 Reading from Streams
--------------------------

Unlike normal Unix file descriptors, read-only poke streams are
buffered.  Let's supposed we open the standard input:

     var stdin = open ("<stdin>");

Then we map some data (one byte) at some particular offset:

     var b = byte @ stdin : 28#B;

The mapping operation above causes poke to read 28 bytes from the
standard input and to set the variable 'b' to the 28-th byte.  The bytes
read from the stream are still available (buffered) and the offsets are
still relative from the "beginning" of the standard input:

     var c = byte @stdin : 0#B;

The byte in 'c' is the byte that appeared in the standard input 27 bytes
before the byte in 'b'.

   This buffering is nice, and it is what allows us to access the
standard input like if it were a random oriented device.  However, it is
obvious we would be in trouble if we filter big amounts of data, like in
a network interface: we would likely use all available memory.

   To allow filtering big amount of data, poke allows to "flush" the
read-only streams.  Flushing means that the buffered data in the
read-only stream is "forgotten", and trying to access it will result in
an exception:

     var stdin = open ("<stdin>");

     var b = byte @ stdin : 28#B;
     var c = byte @ stdin : 29#B;
     flush (stdin, 29#B);
     var d = byte @ stdin : 30#B;
     var e = byte @ stdin : 20#B; /* Exception.  */


File: poke.info,  Node: Writing to Streams,  Next: pk-strings,  Prev: Reading from Streams,  Up: Filters

7.6.3 Writing to Streams
------------------------

Similarly, unlike normal Unix file descriptors, write-only poke streams
are also buffered and can be accesses randomly:

     var stdout = open ("<stdout>");

We can write to the output stream by mapping as usual:

     byte @ stdout : 28#B = 0xff;

The mapping operation above writes 27 null bytes, i.e.  it fills until
reaching the requested offset in the output stream.  Then it writes the
byte '0xff' at offset 28 bytes.  If we then write to one of the buffered
bytes:

     byte @ stdout : 27#B = 0xab;

This results in updating the byte that will be written right before the
'0xff' once the output stream is flushed.

   Again, we cannot buffer ad-infinitum: we would exhaust all available
output.  Therefore, XXX


File: poke.info,  Node: pk-strings,  Prev: Writing to Streams,  Up: Filters

7.6.4 pk-strings
----------------

Below you can find a very simple Poke program that works like the
standard Unix utility 'strings'.

     #!/usr/local/bin/poke -L
     !#

     /* Printable ASCII characters: 0x20..0x7e */

     var stdin = open ("<stdin>");
     var stdout = open ("<stdout>");

     var offset = 0#B;

     try
     {
       flush (stdin, offset);

       var b = byte @ stdin : offset;
       if (b >= 0x20 && b <= 0x7e)
         byte  stdout : iosize (stdout) = b;

       offset = offset + 1#B;
     }
     until E_eof;

     close (stdin);
     close (stdout);


File: poke.info,  Node: Configuration,  Next: IOS,  Prev: Writing Binary Utilities,  Up: Top

8 Configuration
***************

* Menu:

* pokerc::			User's initialization file.
* Load Path::			Determining location of modules.
* Styling::			Changing the appearance of poke's output.


File: poke.info,  Node: pokerc,  Next: Load Path,  Up: Configuration

8.1 '.pokerc'
=============

Upon invocation poke will read and execute the commands of an
initialization file, if it exists: the 'pokerc' file.  There are two
ways to keep an initialization file.

   The simple, traditional way is to have a file named '.pokerc' in your
home directory.  GNU poke will look for a file like that first.

   If '.pokerc' is not found your home directory, poke looks in the
locations specified by the "XDG Base Directory Specification"(1) for a
file named 'poke/pokerc.conf'.  For example, you could use
'~/.config/poke/pokerc.conf'.

   Which way is better depends on your specific requirements and taste.

   GNU poke can be insturcted to not read the initialization file by
passing '-q' or '--no-init-file' in the command line.

   Example of initialization file:

     # My poke configuration.
     .set endian host
     .set obase 16
     .set pretty-print yes
     pk_dump_cluster_by = 4
     .load ~/.poke.d/mypickles.pk

   ---------- Footnotes ----------

   (1) 
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html


File: poke.info,  Node: Load Path,  Next: Styling,  Prev: pokerc,  Up: Configuration

8.2 Load Path
=============

The 'load_path' Poke variable contains a list of directories separated
by the colon character (':').  When a module is loaded using the 'load'
construction, these directories are searched in sequential order for the
file corresponding to the requested module.

   Empty directory names and entries that do not name existing
directories are ignored.

   Some entries have special meanings:

'%DATADIR%'
     This is interpreted as the system-wide datadir directory, that
     depends on the prefix where poke is installed.

   For example, say you want to maintain '.pk' files in your '~/.poke.d'
directory.  You will probably want to add that directory to the
'load_path', when poke initializes.  A way to do that is to add a
command like this to your 'pokerc' file:

     load_path = getenv ("HOME") + "/.poke.d:" + load_path

   If the environment variable 'POKE_LOAD_PATH' is defined in the
environment, its value is added to 'load_path' at poke startup time.


File: poke.info,  Node: Styling,  Prev: Load Path,  Up: Configuration

8.3 Styling
===========

XXX


File: poke.info,  Node: IOS,  Next: Time,  Prev: Configuration,  Up: Top

9 IOS
*****

The 'ios' pickle contains functions that are useful to work with IO
spaces.

* Menu:

* ios_dump_bytes::              Dumping bytes on the terminal.
* ios_copy_bytes::              Copying bytes between IO spaces.
* ios_save_bytes::              Saving a range of bytes to a file.


File: poke.info,  Node: ios_dump_bytes,  Next: ios_copy_bytes,  Up: IOS

9.1 ios_dump_bytes
==================

The 'ios_dump_bytes' function prints a byte dump of an area in a given
IO space.

   It has the following prototype:

     fun ios_dump_bytes = (int<32> IOS,
                           offset<uint<64>,b> FROM,
                           offset<uint<64>,b> SIZE,
                           offset<uint<64>, b> GROUP_BY = 2#B,
                           int<32> CLUSTER_BY = 8,
                           int<32> RULER = 0,
                           int<32> ASCII = 0,
                           string UNKNOWN_BYTE = "??",
                           uint<8> NONPRINTABLE_CHAR = '.') void

Where IOS is the IO space form which dump bytes.

   FROM is the offset from which start dumping bytes.  This location is
truncated to bytes.

   SIZE is an offset specifying the amount of bytes to dump.  The offset
is rounded up to the next byte.

   GROUP_BY determines how the bytes are grouped together in the output.
Defaults to two bytes.

   CLUSTER_BY specifies to display additioanl space after the specified
number of groups have been displayed.  Defaults to 8.

   RULER is a boolean determining whether to include a ruler line in the
output.  Defaults to 0.

   ASCII_P is a boolean determining whether to include an ASCII dump.
Defaults to 0.

   UNKNOWN_BYTE is the string to use to denote bytes that can't be read
from the IO space.  Defaults to '"??"'.  Note this string is expected to
be of length two characters.

   NONPRINTABLE_CHAR is the character code to use to denote
non-printable characters.  Defaults to ''.''.

   This function may raise 'E_io', 'E_perm', and 'E_eof' on several
error conditions.


File: poke.info,  Node: ios_copy_bytes,  Next: ios_save_bytes,  Prev: ios_dump_bytes,  Up: IOS

9.2 ios_copy_bytes
==================

The 'ios_copy_bytes' copies a range of bytes between IO spaces.

   It has the following prototype:

     fun ios_copy_bytes = (int<32> FROM_IOS, int<32> TO_IOS,
                           offset<uint<64>,B> from,
                           offset<uint<64>,B> to,
                           offset<uint<64>,B> size) void

Where FROM_IOS is the origin IO space, i.e.  the IO space from which
bytes are to be copied.

   TO_IOS is the destination IO space, i.e.  the IO space to which bytes
are to be copied.

   FROM is a byte offset in FROM_IOS with the beginning of the range to
copy.

   TO is a byte offset in TO_IOS where the bytes will be copied.

   SIZE is a byte offset specifying the amount of data to be copied.


File: poke.info,  Node: ios_save_bytes,  Prev: ios_copy_bytes,  Up: IOS

9.3 ios_save_bytes
==================

The function 'ios_save_bytes' saves a range of bytes from an IO space to
a file.

   It has the following prototype:

     fun ios_save_bytes = (int<32> ios, string file,
                           offset<uint<64>,B> from,
                           offset<uint<64>,B> size,
                           int<32> append_p) void

Where IOS is the IO space from which save bytes.

   FILE is the name of the file where to save the bytes.

   TO and SIZE are byte offsets in the IO space determining the range of
bytes to save.

   By default the output file is truncated if it already exists.  If
APPEND_P is true, then the data is instead appended at the end of the
file.


File: poke.info,  Node: Time,  Next: Colors,  Prev: IOS,  Up: Top

10 Time
*******

Systems encode time-stamps or dates in several ways.  GNU poke provides
support for some of them.

* Menu:

* POSIX Time::			The 'time' pickle.


File: poke.info,  Node: POSIX Time,  Up: Time

10.1 POSIX Time
===============

In POSIX systems time is encoded as a certain number of seconds elapsed
since some origin date, namely the first of January 1970.  The 'time'
pickle provides two types for 32-bit and 64-bit POSIX time encodings:

     POSIX_Time32
     POSIX_Time64

   A function 'ptime' is also provided, that prints a human-readable
representation of a POSIX date, given a number of seconds.


File: poke.info,  Node: Colors,  Next: Audio,  Prev: Time,  Up: Top

11 Colors
*********

Colors are often found in binary data, encoded in several different
ways.  GNU poke provides several pickles that makes it easier to work
with these colors.

* Menu:

* The Color Registry::		The 'color' pickle.
* RGB24 Encoding::		Encoding colors with three bytes.


File: poke.info,  Node: The Color Registry,  Next: RGB24 Encoding,  Up: Colors

11.1 The Color Registry
=======================

The 'color' pickle provides a registry of "standard colors", organized
as a space of integers.  Each integer identifies a standard color, which
are accessible as variables named 'color_*' after the pickle is loaded.
Example:

     (poke) load color
     (poke) color_tomato
     114

   The purpose of having this register is to have a global namespace for
colors that can be used in different pickles.  The position of each
color in the registry is totally unrelated to how the color may be
encoded.  Other pickles, as we shall see below, contain tables
associating standard colors with their encoding, such as RGB.

   If you want to add a new color that is not in the standard
collection, you can use the 'color_register' function, which gets no
arguments:

     (poke) var mycolor = color_register
     (poke) mycolor
     490

   The total number of registered colors is recorded in the variable
'color_num_colors'.  You can use it to iterate on all the colors in the
register, from '0' to 'color_num_colors - 1'.

   The index in the registry of the first user-defined color is hold in
the variable 'color_LAST'.  For example, if you wanted to store a frob
per standard color, you would do it like:

     (poke) type Frobs = Frob[color_LAST]

   The pickle also provides a function 'color_name' that, given a color
code, returns a printable name for the color, i.e.  a string describing
it.  For user defined colors, this string is fixed:

     (poke) color_name (23)
     "lavender blush"
     (poke) color_name (color_register)
     "user-defined color"

If a non-existent color code is passed to 'color_name' the function
raises 'E_out_of_bounds':

     (poke) color_name (color_num_colors)
     unhandled out of bounds exception


File: poke.info,  Node: RGB24 Encoding,  Prev: The Color Registry,  Up: Colors

11.2 RGB24 Encoding
===================

The "RGB24" encoding encodes each color as a triplet of "color beans",
each beam indicating a level of red, green and blue respectively.

   Types are provided for both the color beams, and the triplets:

     type RGB24_Color_Beam = uint<8>;
     type RGB24_Color = RGB24_Color_Beam[3];

The indexes 'RGB24_RED', 'RGB24_GREEN' and 'RGB24_BLUE' can be used to
access to a specific beam of a given color:

     (poke) rgb24_color[color_tomato][RGB24_GREEN]
     99UB

   The 'rgb24' pickle also provides a table associating poke standard
colors (*note The Color Registry::) with their RGB24 encodings.  Once
the pickle is loaded, this table is available in the variable
'rgb24_color'.  The table is to be indexed by color codes:

     (poke) load rgb24
     (poke) rgb24_color[color_tomato]
     [255UB,99UB,71UB]


File: poke.info,  Node: Audio,  Next: Object Formats,  Prev: Colors,  Up: Top

12 Audio
********

* Menu:

* MP3::				Editing MP3 files.


File: poke.info,  Node: MP3,  Up: Audio

12.1 MP3
========

* Menu:

* ID3V1 Tags::			The 'id3v1' pickle.


File: poke.info,  Node: ID3V1 Tags,  Up: MP3

12.1.1 ID3V1 Tags
-----------------

The 'id3v1' pickle provides abstractions in order to edit the metadata
stored in a MP3 file.

12.1.1.1 Song Genres
....................

The ID3V1 tags support the notion of "song genre".  The space for genres
is from 0 to 254.  The genre code 255 is reserved to mean "no genre".

   The table 'id3v1_genres' can be indexed with a code in order to get
the corresponding genre name:

     (poke) id3v1_genres[14]
     "rhythm and blues"

   Conversely, the function 'id3v1_search_genre' gives us the code of a
genre, given its name.  The prototype of this function is:

     fun id3v1_search_genre = (string name) uint<8>:

For example:

     (poke) id3v1_search_genre ("rock")
     17UB

   If 'id3v1_search_genre' is given a name that doesn't correspond with
any genre in the genres table, then 'E_inval' is raised.

12.1.1.2 The ID3V1_Tag Type
...........................

The main data structure defined in the 'id3v1' pickle is 'ID3V1_Tag',
which corresponds to a ID3V1 tag (surprise!).

   Tags comprise the following information:

   - The title of the song, which is limited to 30 bytes.
   - The artist, which is limited to 30 bytes.
   - The album, which is limited to 30 bytes.
   - The year, which is encoded as text in 4 bytes, each byte containing
     the ASCII code for the corresponding digit.
   - A comment, which is limited to either 28 or 30 bytes, depending
     whether the tag contains track information or not.
   - An optional track, which is an unsigned 8-bit number.

   The specification does not mention any specific encoding for the
entries that store text (such as title or artist), but it is safe to
assume some ASCII-compatible encoding is used.

   The text entries are stored as arrays of characters, and they are
_not_ finished by NULL characters.  Instead the arrays of characters are
filled with whitespaces (ASCII code 0x20) at the right.  For example,
the artist name Picasso encoded in ID3V1 would be:

     ['P','i','c','a','s','s','o',' ',' ', ..., ' ']

   In order to ease the manipulation of the text fields, setters and
getters are provided in order to handle these values as strings and not
as whitespace-filled arrays of characters.  Example:

     (poke) tag.title
     [48UB,49UB,32UB,45UB,32UB,...]
     (poke) tag.get_title
     "01 - Eclipse De Mar"

Also for setters:

     (poke) tag.set_title ("Join us Now")
     (poke) tag.title
     [74UB,111UB,105UB,110UB,32UB,...]

   Setters and getters are also provided in order to manipulate the year
as an integer value:

     (poke) tag.year
     [0x31UB,0x39UB,0x38UB,0x30UB]
     (poke) tag.get_year
     1980
     (poke) tag.set_year (1988)


File: poke.info,  Node: Object Formats,  Next: Programs,  Prev: Audio,  Up: Top

13 Object Formats
*****************

This chapter is of special interest to toolchain developers, people
doing reverse-engineering, and similar low-level development activities.

* Menu:

* ELF::                         Editing ELF files.
* Dwarf::	                Editing DWARF data.


File: poke.info,  Node: ELF,  Next: Dwarf,  Up: Object Formats

13.1 ELF
========

XXX


File: poke.info,  Node: Dwarf,  Prev: ELF,  Up: Object Formats

13.2 Dwarf
==========

XXX


File: poke.info,  Node: Programs,  Next: poked,  Prev: Object Formats,  Up: Top

14 Programs
***********

This chapter describes pickles whose purpose is to facilitate the
writing of binary utilities in Poke.

* Menu:

* argp::			Handling of command-line options.


File: poke.info,  Node: argp,  Up: Programs

14.1 argp
=========

Like any other program, Poke scripts often need to handle options passed
in the command line.  The 'argp' pickle provides a convenient and easy
way to handle these arguments.

   The main entry point of the pickle is the function 'argp_parse', with
the following prototype:

     fun argp_parse = (string PROGRAM,
                       string VERSION = "",
                       string SUMMARY = "",
                       Argp_Option[] OPTS = Argp_Option[](),
                       string[] ARGV = string[](),
                       int ALLOW_UNKNOWN = 0) string[]

Where PROGRAM is the name of the program providing the command-line
options.  VERSION is either a string identifying the version of the
program, or the empty string.  SUMMARY is a short summary of what the
program does.  OPTS is an array of 'Argp_Option' structs, each of which
describe a command line option and, in particular, a handler for that
option.  ARGV is an array of string containing the command line elements
to process.  Finally, ALLOW_UNKNOWN specifies whether unknown options
constitute an error or not.  This last option is useful in order to
support sub-parsers.

   Once invoked, 'argp_parse' analyzes the command line provided in
ARGV, recognizes options, performs checks making sure that all specified
options are well formed, and that every option requiring an argument
gets one, invokes the handlers registered for each option, and finally
returns an array of non-option arguments in ARGV, for further processing
by the user.

   Each 'Argp_Option' struct describes an option.  They have this form:

     type Argp_Option =
       struct
       {
         string NAME;
         string LONG_NAME;
         string SUMMARY;
         string ARG_NAME;
         int ARG_REQUIRED;
         Argp_Option_Handler HANDLER;
       };

Where NAME is a string of size one character specifying the short name
for the option.  LONG_NAME is a non-empty string of any size specifying
the long name for the option.  SUMMARY is a short paragraph with a
summary of that the option does.  ARG_NAME, if specified, is a string to
be used to describe the argument of the option in the '--help' output.
If ARG_NAME is not specified then '"ARG"' is used.  ARG_REQUIRED is a
boolean specifying whether the option accepts and expects an argument.
Defaults to 0.  Finally, HANDLER is a function that will be invoked to
process the option.  The function has the following prototype:

     type Argp_Option_Handler = (string)void

   The 'argp_parse' function provides default handlers for several
standard options:

'--help'
     The default handler for this option prints out an usage message in
     the standard GNU way, and exits.  In particular, this output is
     compatible with the 'help2man' utility.
'--version'
     The default handler for this option prints out the name and the
     version of the program, and exits.

If the user provides handlers for the options above, these take
precedence wrt the default handlers.

   Several short options can be accumulated this way:

     foo -qyz

   The special option '--', if found in the command line, stops the
processing of options.  Everything found about it is considered
non-option arguments.


File: poke.info,  Node: poked,  Next: Programming Emacs Modes,  Prev: Programs,  Up: Top

15 poked
********

The 'poke' application is a REPL (Read-Evaluate-Print-Loop) and
therefore the user interacts with it by providing Poke statements or
expressions (or dot-commands) in the standard input, and then the
program prints the response to the commands in the standard output, or
standard error.  This is good for human users, but not that convenient
for other programs that may wish to communicate with a poke incremental
compiler.

   'poked' is a different sort of application that accepts Poke code
(and more) over Unix sockets and provides responses over the same
socket.  This is very convenient for programs to interact with the poke
incremental compiler.  The client programs that interact with 'poked'
are called _pokelets_.

   This form of interaction is particularly userful to write user
interfaces to GNU poke, in the form of several pokelets.  Examples of
such interfaces are Emacs interface to poke
(https://git.savannah.gnu.org/cgit/poke/poke-el.git) and pacme
(https://sourceware.org/pacme/).

   'poked' is basically a message broker that provides (for now) 120
input channels and 120 output channels.  The first 60 channels are
reserved for the 'poked' developers in order to provide standard
channels whose meaning is fixed and the same for any pokelet.  The rest
of the channels can be freely dedicated for any purpose by anybode else.

   The combination of _channel number_ and _channel direction_ creates
the client's _role_.  For now, it's a single byte.  The most significant
bit determines whether it's an input or output channel.  Or in poke
syntax:

     var PDAP_DIRECTION_IN  = 0 as uint<1>,
         PDAP_DIRECTION_OUT = 1 as uint<1>;

     type PDAP_Role = struct uint<8>
       {
         uint<1> direction;
         uint<7> channel : 0 < channel && channel <= 120;
       };

   Pokelets are expected to write their role over the socket when
they're connected to the 'poked'.

   'poked', on start up, will create a Unix socket and prints current
options to the 'stdout'.  Options are a pair of space-separated
key/values, each on one line.  Options will end with an empty line.  An
example of 'poked' output:

     socket_path /tmp/poked.ipc
     pdap_version 0


   Currently, only first two input channels are active.  Input channel
number 1 is for _code input_ which means anything sent to this channel
will be compiled and executed using 'pk_compile_buffer' function of
'libpoke'; and input channel number 2 is for _command input_ which will
compile and execute the input message using 'pk_compile_statement'
function.

   For output channels:

"Channel 1"
     Terminal output.
"Channel 2"
     View (vu) output.
"Channel 3"
     Poke Virtual Machine (PVM) disassembly output.
"Channel 4"
     Treevu (tree view) output (not supported yet).
"Channel 5"
     Auto-completion output.
"Channel 6"
     CPU disassembly output.

   The format of each message written to output channels are documented
in 'pdap.pk' pickle.

   The following functions are available for pokelets:

'poked_pdap_version'
     Version of current PDAP (PokeD Application Protocol).
'poked_libpoke_version'
     Version of 'libpoke'.
'poked_restart'
     Restart the Poke environment of 'poked'.
'poked_exit'
     Exit the 'poked'.
'poked_chan_send'
     Signature: '(uint<7> chan, byte[] data) void'.  Send data to the
     specified output channel.

   The following variable is also available for pokelets to use:

'poked_after_cmd_hook'
     An array of callbacks to be run after executing the _command_
     (received from input channel 2).  Callback signature: '()void'.


File: poke.info,  Node: Programming Emacs Modes,  Next: Vim Syntax Highlighting,  Prev: poked,  Up: Top

16 Programming Emacs Modes
**************************

GNU poke ships with a bunch of Emacs major modes that eases writing Poke
and PVM assembly.  This chapter documents these modes.

* Menu:

* poke-mode::                   Major mode for writing Poke programs.
* poke-map-mode::               Major mode for writing map-files.
* poke-ras-mode::               Major mode for writing RAS programs.


File: poke.info,  Node: poke-mode,  Next: poke-map-mode,  Up: Programming Emacs Modes

16.1 poke-mode
==============

'poke-mode' is a major mode for editing Poke source files, i.e.  '.pk'
files.  It provides font-lock, auto-completion and indentation features.


File: poke.info,  Node: poke-map-mode,  Next: poke-ras-mode,  Prev: poke-mode,  Up: Programming Emacs Modes

16.2 poke-map-mode
==================

'poke-map-mode' is a major mode for editing poke map-files.  It provides
font-lock.  *Note Maps and Map-files::.


File: poke.info,  Node: poke-ras-mode,  Prev: poke-map-mode,  Up: Programming Emacs Modes

16.3 poke-ras-mode
==================

'poke-ras-mode' is a major mode for editing PVM assembly.  It is used in
the development of GNU poke.  See the file 'libpoke/ras' in the source
distribution for more information about RAS, our Retarded Assembler.


File: poke.info,  Node: Vim Syntax Highlighting,  Next: Dot-Commands,  Prev: Programming Emacs Modes,  Up: Top

17 Vim Syntax Highlighting
**************************

GNU poke ships with a vim syntax highlighter for *.pk files.  Normally
this should be installed as part of your existing poke installation and
work out of the box.  If that is not the case this chapter explains how
to install it manually.

* Menu:

* poke.vim::    Poke syntax highlighter


File: poke.info,  Node: poke.vim,  Up: Vim Syntax Highlighting

17.1 'poke.vim'
===============

'etc/vim/syntax/poke.vim' is a syntax highlighter for Poke source i.e.
'.pk' files.  To use it, first place the file in your '~/.vimrc/syntax/'
folder on Unix based systems, or in '$HOME/vimfiles/syntax/' on Windows.
There are a few ways to tell Vim to use 'poke.vim' for '.pk' files, but
the quickest is to add the following line to your '.vimrc':

     au BufRead,BufNewFile *.pk set filetype=poke


File: poke.info,  Node: Dot-Commands,  Next: Commands,  Prev: Vim Syntax Highlighting,  Up: Top

18 Dot-Commands
***************

* Menu:

* load command::		Loading pickles.
* source command::              Executing commands in files.
* file command::		Opening and selecting file IO spaces.
* mem command::			Opening and selecting memory IO spaces.
* nbd command::			Opening and selecting NBD IO spaces.
* proc command::                Opening and selecting process IO spaces.
* sub command::                 Opening IO sub-spaces.
* ios command::			Switching between IO spaces.
* close command::		Closing IO spaces.
* doc command::                 Online manual.
* editor command::		Using an external editor for input.
* info command::		Getting information about open files, etc.
* set command::			Querying and setting global options.
* vm command::			Poke Virtual Machine services.
* exit command::		Exiting poke :(
* quit command::                Likewise.


File: poke.info,  Node: load command,  Next: source command,  Up: Dot-Commands

18.1 '.load'
============

The '.load' command loads a file containing Poke code and compiles and
executes it.  These files usually have the extension '.pk'.

   If a relative path is provided, then 'PREFIX/share/poke' is tried
first as a base directory to find the specified file.  If it is not
found, then the current directory is tried next.

   If the environment variable 'POKEDATADIR' is defined, it replaces
'PREFIX/share/poke'.  This is mainly intended to test a poke program
before it gets installed in its final location.

   If an absolute path is provided, it is used as-is.


File: poke.info,  Node: source command,  Next: file command,  Prev: load command,  Up: Dot-Commands

18.2 '.source'
==============

The '.source' command executes command lines from some given file.  The
syntax is:

     .source PATH

where PATH is a path to the file containing the commands.  *Note Command
Files::.


File: poke.info,  Node: file command,  Next: mem command,  Prev: source command,  Up: Dot-Commands

18.3 '.file'
============

The '.file' command opens a new IO space backed by a file, or switches
to a previously opened file.  The syntax is:

     .file PATH

where PATH is a path to a file to open, which can be relative to poke's
current working directory or absolute.

   Tilde expansion is performed in PATH, much like it's done in the
shell.  This means you can include special characters like '~' (which
will expand to your home directory) delimit the file name with '"' in
case it includes leading or trailing blank characters, etc.

   When a new file is opened it becomes the current IO space.  From that
point on, every map executed in the REPL or while loading a Poke program
will operate on that IO space:

     (poke) .file foo.o
     The current file is now `foo.o'.

   When '.file' opens a file, it is opened in whatever mode makes more
sense: if the file allows to be written and read then the IO space is
open in read/write mode, for example.

   If the specified file path doesn't exist then poke emits an error.
However, the flag '/c' ( for "create") can be passed to the command to
tell poke it should create a new file.


File: poke.info,  Node: mem command,  Next: nbd command,  Prev: file command,  Up: Dot-Commands

18.4 '.mem'
===========

The '.mem' command opens a new IO space backed by a memory buffer.  The
syntax is:

     .mem NAME

where NAME is the name of the buffer to create.  Note that poke adds
prefix and trailing asterisk characters, to differentiate file names
from buffer names.

   When invoked with no NAME, poke generates a new unique name for the
buffer.

   When a new memory buffer IOS is opened it becomes the current IO
space.  *Note file command::.


File: poke.info,  Node: nbd command,  Next: proc command,  Prev: mem command,  Up: Dot-Commands

18.5 '.nbd'
===========

The '.nbd' command opens a new IO space backed by an external NBD
server.  The syntax is:

     .nbd URI

where URI is the name of the newly created buffer, matching the NBD URI
specification
(https://github.com/NetworkBlockDevice/nbd/blob/master/doc/uri.md).

   When a new NBD IOS is opened, it becomes the current IO space.  *Note
file command::.

   NBD support in GNU poke is optional, depending on whether poke was
compiled against libnbd.

   For an example of connecting to the guest-visible content of a qcow2
image, with the default export name as exposed by using qemu as an NBD
server:

     $ qemu-nbd --socket=/tmp/mysock -f qcow2 image.qcow2
     $ poke
     (poke) .nbd nbd+unix:///socket=?/tmp/mysock
     The current file is now `nbd+unix:///socket=?/tmp/mysock'.


File: poke.info,  Node: proc command,  Next: sub command,  Prev: nbd command,  Up: Dot-Commands

18.6 '.proc'
============

The '.proc' command opens a new IO space backed by the memory mapped for
some live process, or switches to a previously opened process.  The
syntax is:

     .proc PID

where PID is a process identifier.  In most systems this is a number.


File: poke.info,  Node: sub command,  Next: ios command,  Prev: proc command,  Up: Dot-Commands

18.7 '.sub'
===========

The '.sub' command opens a new IO sub-space.  The syntax is:

     .sub IOS, BASE, SIZE[, NAME]

where IOS is the tag of some existing IO space, BASE and SIZE are
integers denoting the base and size of the range covered by the
sub-space (in bytes) and NAME is an optional name.


File: poke.info,  Node: ios command,  Next: close command,  Prev: sub command,  Up: Dot-Commands

18.8 '.ios'
===========

A list of open files, and their corresponding tags, can be obtained
using the '.info ios' command.  Once a tag is known, you can use the
'.ios' command to switch back to that file:

     (poke) .ios #1
     The current IOS is now `foo.o'.


File: poke.info,  Node: close command,  Next: doc command,  Prev: ios command,  Up: Dot-Commands

18.9 '.close'
=============

The '.close' command closes the selected IO space.  The syntax is:

     .close #TAG

where #TAG is a tag identifying an open IO space.

   Note that closing an IO space with this dot-command implies closing
any sub IO space having it as a base.


File: poke.info,  Node: doc command,  Next: editor command,  Prev: close command,  Up: Dot-Commands

18.10 '.doc'
============

The '.doc' command is used to display this manual in poke's REPL. The
syntax is:

     .doc [NODE]

where NODE is an optional parameter which indicates the chapter or
section at which the manual should be opened.

   This command uses whatever documentation viewer configured using
'.set doc-viewer' whose valid options are either 'info' and 'less'.

   Unless 'doc-viewer' is set to 'less', this command uses the info
program (*note (info)Top::) to interactively present the manual.  If
info is not installed, then less is tried next.

   When using less to display the documentation, the entry in the Table
of Contents corresponding to the requested entry is highlighted.  Just
press </> and then <RET> to jump to the corresponding section in the
manual.

   If neither info nor less are installed, the '.doc' command will fail.
If poke is not running interactively then '.doc' does nothing.


File: poke.info,  Node: editor command,  Next: info command,  Prev: doc command,  Up: Dot-Commands

18.11 '.editor'
===============

The '.editor' command (usually abbreviated as '.edit') invokes an
external text editor on a temporary file.  You can then put contents on
that file, save it and exit the editor.  At that point poke will read
the file contents, turn them into a single line and execute them in the
repl.  If poke is not running interactively, then '.editor' does
nothing.

   The editor used is identified by the 'EDITOR' environment variable.


File: poke.info,  Node: info command,  Next: set command,  Prev: editor command,  Up: Dot-Commands

18.12 '.info'
=============

The '.info' command provides information about several kinds of
entities.  The recognized sub commands are:

'.info ios'
     Display a list of open files.

          (poke) .info ios
            Id	Type	Mode	Bias		Size		Name
            #1	FILE	r	0x00000000#B	0x0000df78#B	foo.o
          * #0	FILE	rw	0x00000000#B	0x00000022#B	foo.bson

     The file acting as the current IO space is marked with an asterisk
     character '*' at the beginning of the file.  The mode in which the
     file is open is also specified.  The 'Id' field is the tag of the
     file that can be passed to the '.file' command in order to switch
     to it as the new current IO space:

          (poke) .ios #1
          The current file is now `foo.o'.
          (poke) .info ios
            Id	Type	Mode	Bias		Size		Name
          * #1	FILE	r	0x00000000#B	0x0000df78#B	foo.o
            #0	FILE	rw	0x00000000#B	0x00000022#B	foo.bson

'.info variables [REGEXP]'
     Shows a list of defined variables along with their current values
     and the location where the variables were defined.  If a regular
     expression is provided then only the types whose name match the
     expression are listed.  If a regular expression is provided then
     only the types whose name match the expression are listed.
'.info functions [REGEXP]'
     Shows a list of defined functions along with their prototypes and
     the location where the functions were defined.  If a regular
     expression is provided then only the types whose name match the
     expression are listed.  If a regular expression is provided then
     only the types whose name match the expression are listed.
'.info types [REGEXP]'
     Shows a list of defined types along with the locations where the
     types were defined.  If a regular expression is provided then only
     the types whose name match the expression are listed.
'.info type NAME'
     Prints a description of the type with name NAME.


File: poke.info,  Node: set command,  Next: vm command,  Prev: info command,  Up: Dot-Commands

18.13 '.set'
============

The '.set' command allows you to inspect and set the value of global
settings.  The following invocations are valid:

'.set'
     Prints all settings along with their values.
'.set SETTING'
     Prints the value of the given SETTING.
'.set SETTING VALUE'
     Sets the value of SETTING to VALUE.

The following settings can be handled with '.set':

'pretty-print'
     This setting determines whether poke should use pretty-printers
     while printing out the written representation of struct values.

     Pretty-printers are defined as methods named '_print'.

'auto-map'
     This setting determines whether to automatically load map files
     when opening IO spaces.

     The decision of what maps to load is driven by the contents of the
     array 'auto_map'.  Each entry in the array is an array whose first
     element is a regular expression, and the second element is the name
     of a map.

     Example:

     auto_map = [["\.o", "elf"], ["\.o", "dwarf"]];

     The entry above makes poke to automatically load the maps 'elf.map'
     and 'dwarf.map' when opening any file whose name ends in '.o',
     provided 'auto-map' is set to 'yes'.

'prompt-commented'
     This setting determines whether the prompt is a shebang-comment,
     allowing for easy copy-paste of full terminal lines because the
     prompt will be a syntactic no-op.

     Example of a prompt with prompt-commented enabled:

     #!!# 1+2; 3

     Example of a prompt with prompt-commented, map information, and
     'prompt-maps' set to 'yes':

     #!!# .file foo.o #![dwarf,elf]!# 1+2; 3 #![dwarf,elf]!#

'prompt-maps'
     This setting determines whether a list of open maps is displayed
     before the poke prompt.

     Example of a prompt with map information and 'prompt-maps' set to
     'yes':

     (poke) .file foo.o [dwarf,elf](poke)

     Which indicates that the opening of the IO space 'foo.o' resulted
     in the 'elf.map' and 'dwarf.map' maps to be automatically loaded.

'omaps'
     This sort of misnamed setting determines whether to show the mapped
     offsets and element/field offsets of composite values like arrays
     and structs.

     Example:

     (poke) .set omaps yes (poke) [1,2,3] [0x1 @ 0x0UL#b,0x2 @
     0x20UL#b,0x3 @ 0x40UL#b] @ 0x0UL#b

     This setting defaults to 'no'.

'obase'
     This setting determines the output numerical base to use when
     printing integral values like integers, offset magnitudes, and the
     like.  The supported bases are 2 for binary, 8 for octal, 10 for
     decimal and 16 for hexadecimal.

'oacutoff'
     This setting determines the maximum number of elements to output
     when printing out array values.  Once the maximum number of
     elements is reached, an ellipsis '...'  is printed to represent the
     rest of the elements.

     Example:

     (poke) [1,2,3,4,5] [1,2,3,4,5] (poke) .set oacutoff 3 [1,2,3,...]

     The default value is 0, which means no limit.

'odepth'
     This setting determines the maximum number of nested structs to
     output when printing struct and union values.  Once the maximum
     number of nested values is reached, a collapsed form 'Type {...}'
     is printed.

     Example:

     (poke) type Foo = struct { struct { int i; } bar; } (poke) Foo {}
     Foo { bar=struct {...} }

     The default value for 'odepth' is 0, which means infinite depth.

'oindent'
     This setting determines the width (in blank characters) of each
     indentation level when printing out struct values in 'tree' mode.

     Example:

     (poke) .set oindent 4 (poke) Foo {} Foo { i=0x0, l=0x0L }

     This setting defaults to 2.  See also ".help omode".

'omode'
     This setting determines the way binary struct data is displayed.

     In 'flat' mode data is not formatted in any special way.  Each
     value, be it simple or composite, is printed on one line.

     In 'tree' mode composite values like structs and arrays are
     displayed in an hierarchical way, using newlines and indentation.

     Examples:

     (poke) .set omode flat (poke) Foo {} Foo {i=0x0,l=0x0L}

     (poke) .set omode tree (poke) Foo {} Foo { i=0x0, l=0x0L }

     The default value of 'omode' is 'flat'.

'endian'
     This setting determines the byte endianness used when accessing IO
     spaces.  Valid values are 'big', 'little', 'host' and 'network'.

     The meaning of 'big' and 'little' is the obvious one: the
     endianness is set to big-endian and little-endian respectively.

     The 'host' endianness is the endianness used by the computer and
     operating system that is running poke in order to handle it's own
     memory and files.

     The 'network' endianness is the endianness used by the host machine
     in order to communicate with the network.

'doc-viewer'
     This setting determines what mechanism to use to open the online
     user manual.

     If 'info' is selected, the GNU info standalone program is launched
     to show the info version of the user manual.

     If 'less' is selected, the less utility is launched ot show a plain
     text version of the user manual.

     See also ".help .doc".

'pager'
     This setting determines whether the output of poke commands will be
     paged or not.  Each page will have the height of the terminal.

     This setting is 'no' by default.

'tracer'
     This setting determines whether the Poke compiler and runtime will
     generate tracing events or not.  This is mainly useful for
     debugging puposes.

     Beware that enabling tracer will undoubtly have an impact in
     performance, and that every type compiled when tracing is enabled
     will contain instrumentalization.  This means you will most likely
     want to re-compile the types with tracing disabled once the
     debugging is done.

     This setting is 'no' by default.

'autoremap'
     This setting determines whether poke will remap mapped values
     automatically when they are referred to.  This assures that the
     values are always up to date with respect the contents of the IO
     space.

     Turning auto-remap off may be useful in situations where it is very
     slow to keep all the data structures up to date.  In these case,
     you can '.set autoremap off' and then use the 'remap' Poke operator
     to force the re-mapping of any given value, explicitly.

     This setting is 'yes' by default.


File: poke.info,  Node: vm command,  Next: exit command,  Prev: set command,  Up: Dot-Commands

18.14 '.vm'
===========

The Poke Virtual Machine (PVM) executes the programs that are the result
of the compilation of what you write in the REPL or the pickles you
load.  The '.vm' command provides sub-commands to interact with the PVM.

* Menu:

* .vm disassemble::		PVM and native disassembler.
* .vm profile::               Profiling Poke programs.
* .vm dispatch::              PVM dispatching strategy.


File: poke.info,  Node: .vm disassemble,  Next: .vm profile,  Up: vm command

18.14.1 '.vm disassemble'
-------------------------

The '.vm disassemble' command provides access to the PVM disassembler.
It supports the following subcommands:

'.vm disassemble expression EXPR'
     Dumps the assembler corresponding to the Poke expression EXPR.
'.vm disassemble function FUNCTION'
     Dumps the assembler corresponding to the Poke function called
     FUNCTION.  The function shall be reachable from the top-level.
'.vm disassemble mapper EXPR'
     If EXPR is a mapped value, dumps the assembler corresponding to its
     mapper function.
'.vm disassemble writer EXPR'
     If EXPR is a mapped value, dumps the assembler corresponding to its
     writer function.

   The disassembler will provide a PVM disassembly by default, but it
can be passed the flag '/n' to do a native disassembly instead in
whatever architecture running poke.


File: poke.info,  Node: .vm profile,  Next: .vm dispatch,  Prev: .vm disassemble,  Up: vm command

18.14.2 '.vm profile'
---------------------

The '.vm profile' command provides access to the PVM profiler.  This
profiler is only available if poke has been configured with PVM
profiling support.  This command supports the following subcommands:

'.vm profile reset'
     Resets the profiling counts in the virtual machine.
'.vm profile show'
     Outputs a summary with both counts and sample information.


File: poke.info,  Node: .vm dispatch,  Prev: .vm profile,  Up: vm command

18.14.3 '.vm dispatch'
----------------------

The '.vm dispatch' command prints the current dispatching strategy in
PVM (provided by Jitter).  There are four different kind of dispatches:

   * switch
   * direct threading
   * minimal threading
   * no threading

   'no threading' is the fastest one and the least portable dispatch,
and 'switch' is the slowest and the most portable one.

   Jitter by default will use the most efficient dispatch which is both
stable and available for the current configuration.


File: poke.info,  Node: exit command,  Next: quit command,  Prev: vm command,  Up: Dot-Commands

18.15 '.exit'
=============

The '.exit' command exits poke.  The syntax is:

     .exit [STATUS]

Poke will terminate, returning the exit status STATUS.  If STATUS is
omitted, then the exit status zero will be returned.


File: poke.info,  Node: quit command,  Prev: exit command,  Up: Dot-Commands

18.16 '.quit'
=============

The '.quit' command behaves exactly like '.exit'.  *Note exit command::.


File: poke.info,  Node: Commands,  Next: The Poke Language,  Prev: Dot-Commands,  Up: Top

19 Commands
***********

* Menu:

* dump::			Binary dumps.
* copy::			Copying data around.
* save::			Save data into a file.
* sdiff::                       Comparing mapped values byte by byte.
* extract::			Extract contents of values to memory IOS.
* scrabble::			Scrabble memory chunks based on patterns.


File: poke.info,  Node: dump,  Next: copy,  Up: Commands

19.1 'dump'
===========

At the most basic level, memory can be examined byte by byte.  To do
this, use the 'dump' command.

   This command has the following synopsis.

     dump [:from OFFSET] [:size OFFSET] [:ios INT] [:ruler BOOL]
          [:ascii BOOL] [:group_by INT] [:cluster_by INT]

All arguments are optional, which means the simplest use of the command
is to simply type 'dump':

     (poke) dump
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000000: 9b07 5a61 4783 f306 4897 f37c fe39 4cd3  ..ZaG...H..|.9L.
     00000010: b6a2 a578 8d82 7b7f 2076 374c 3eab 7150  ...x..{. v7L>.qP
     00000020: 31df 8ecb 3d33 ee12 429b 2e13 670d 948e  1...=3..B...g...
     00000030: 86f1 2228 ae07 d95c 9884 cf0a d1a8 072e  .."(...\........
     00000040: f93c 5368 9617 6c96 3d61 7b92 9038 a93b  .<Sh..l.=a{..8.;
     00000050: 3b0d f8c9 efbd a959 88d0 e523 fd3b b029  ;......Y...#.;.)
     00000060: e2eb 51d5 cb5b 5ba9 b890 9d7a 2746 72ad  ..Q..[[....z'Fr.
     00000070: 6cbd 6e27 1c7f a554 8d2e 77f9 315a 4415  l.n'...T..w.1ZD.

The first row is the "ruler" which serves as a heading for each
subsequent row.  On the left hand side is the offset of the io space
under examination.  The centre block displays the hexadecimal
representation of each byte, and on the right hand side is their ascii
representation.  If a byte is not representable in ascii, then the byte
will be displayed as a dot.

   By default the 'dump' command reads from the currently selected IO
space.  However, it is possible to specify an explicit IO space using
the 'ios' option:

     (poke) var myfile = open ("/path/to/file")
     (poke) dump :ios myfile

* Menu:

* Information dump shows::         Changing what 'dump' shows.
* Presentation options for dump::  Changing how 'dump' shows it.


File: poke.info,  Node: Information dump shows,  Next: Presentation options for dump,  Up: dump

19.1.1 Information 'dump' shows
-------------------------------

By default 'dump' displays 128 bytes of memory starting at offset 0#B.
You can change the quantity and starting offset by using the 'size' and
'from' arguments.  For example:

     (poke) dump :from 0x10#B :size 0x40#B
     76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
     00000010: b6a2 a578 8d82 7b7f 2076 374c 3eab 7150  ...x..{. v7L>.qP
     00000020: 31df 8ecb 3d33 ee12 429b 2e13 670d 948e  1...=3..B...g...
     00000030: 86f1 2228 ae07 d95c 9884 cf0a d1a8 072e  .."(...\........
     00000040: f93c 5368 9617 6c96 3d61 7b92 9038 a93b  .<Sh..l.=a{..8.;

Note that both the 'size' and 'from' arguments are offsets.  As such,
both must be specified using '#' and an appropriate unit.  (*note Offset
Literals::).

   The other arguments change the appearance of the dump.  If the
'ruler' argument is zero, then the ruler will be omitted:

     (poke) dump :ruler 0 :size 0x40#B
     00000000: b1fd 1608 2346 759c 46a6 aa94 6fcd 846a  ....#Fu.F...o..j
     00000010: e39f 473f 3247 415f 174d a32b ed89 a435  ..G?2GA_.M.+...5
     00000020: d2c6 2c52 bc82 e0a7 e767 31ea 84de 41e5  ..,R.....g1...A.
     00000030: 2add 2869 e9c2 226b e222 8c74 4b94 af24  *.(i.."k.".tK..$

   To omit the ascii representation of the memory, call 'dump' with the
'ascii' argument set to zero:

     (poke) dump :ruler 0 :size 0x40#B :ascii 0
     00000000: 4393 85e7 0b0c 3921 5a26 39ec 2f5f 5f15
     00000010: cc46 e6f3 d50f 6ae6 8988 d50e f8c4 d1c6
     00000020: 5a2f 7c3e 490b 18d8 d867 4b6f 2549 1f6c
     00000030: 34a9 a0d7 24d2 e9ac 9240 8247 10cb 4ba1

