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. See 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"