Named Number Registers: PART 1 - Of streams, compose and registers

XPP registers

The implementation of the CSS counters in XPP is build on top of number registers.
In this first part of this series of articles, we will give an overview of the different registers that are available in XPP and how compose interacts with them.

In the XPP world we make the distinction between register that hold numeric values and registers that hold text.
Numeric registers come in 2 flavors: x-registers and number registers. Both types can only hold whole numbers (integers).
Text registers come also in 2 flavors: dynamic registers and frills registers.
Before we go into more details lets talk first about streams.


When you import a new document into XPP, the document gets shredded into different holding areas called streams. The bulk of the text will go into the main stream. Things like floating tables or figures will go into the pickup stream and the footnotes end up in the footnote stream.
Just after import, when you haven't pressed compose yet, you will see that you end up with a couple of main pages holding the text that ended up in the main stream and if there were any pickups or footnotes in the input, you end up with a couple of lost&found pages (the p1, p2, .. and f1, f2,... pages) that hold your footnotes and pickups. When you open up the division, you will just see an uncomposed page(s) holding just the main stream text.
When you open up the division and press compose, the XPP composition engine will start processing the main stream and will create the necessary number of pages to hold all the main text. As the main text is being composed, the composition engine might encounter a reference to a footnote of a pickup. When that happens the content of that footnote or pickup is transferred from the lost&found pages onto the current page.
Every page can contain a number of frill blocks with some content, as defined in the PL spec. Everything these blocks contain belongs to the frills stream.

So although you see all items sitting all together on the a page, internally XPP will keep things in totally separated containers: the streams. On a page you may have the following streams: main, pickup, footnote and last but not least frills. (there is one other stream called story but that one can only be present when you have the Magazine Layout option, so lets forget about that one).


  • there are 10,000 X-registers available
  • the user can only use X-registers 1 till 99 and 1001 till 9999, the rest is reserved for system use
  • X-registers can only store whole numbers (integers)
  • an X-register stores a signed 32 bit binary value = any value between -2,147,483,648 and 2,147,483,647 
  • X-registers are global: the same X-register is shared over all streams
  • X-registers are temporary: they need to set and read within the same page for consistent results

The following screenshot of page 3 of a test division, demonstrates this.
Every main text line starts with incrementing x-register 1 and reading out the current value.
In the pickups and footnote, we just read out the current value of that same x-register 1 and do not increment it:

As you can see, the lines of text are composed in order and when we reach line 6 (x1 = 6), we find the reference to pickup p4. The content of pickup p4 then gets composed and that is why in p4 we find that x-register 1 equals 6. The footnote is referenced on line 11 and hence in the footnote x-register equals 11. And the same for pickup p5 that is referenced in line 15. When all the main text lines and pickups and footnotes are composed, the system will then compose frill block 1 and 2 and we see that x-register equals 28, the same value as on the last line of main text.

In the test division, x-register 1 get initialized on page 2 and set to 0. So whenever I compose the whole division, I will get the same results on page 3. But when I am on page 3 and I do a compose one page, you will get the following:

Since we are in the same session, the value stored in x-register is 28 (= value on the last line of the previous compose). So this second compose starts with a value of 28 in x-register and we get new numbers for each line. That is the reason why we say x-registers are temporary. X-registers should not be trusted to carry values between pages or between sessions. And since we can generally not predict what part of the text remains on the same page, I would say that you have use an X-register as really temporary storage place when you are doing calculations. They are however useful for transferring information from any stream into the frill stream.

Using x-registers to transfer information from the main stream into a pickup or footnote stream and vice versa can be dangerous. In the following screenshot I only redefined pickup p 5 to be no longer placed in the center of the page, but now I asked for a placement at the top of the page.
In this situation you get the following numbering:

You will notice that pickup p4 and p5 and the footnote keep the value for x1, but now the main text lines all output a new value. Line 1 is now just 1 higher than what p5 is outputting. This is because composition will still compose p5 when it is referenced, but because later on it is floated to the top of the page, XPP needs to recalculate all of the lines of text that sit next or follow p5, as p5 might eat into the available line length for those lines. So never think that you can predict the order in which things will get composed. There are a lot of other cases where you might be surprised by the result, especially around end of line and around the bottom and top of pages. 

Number registers

  • there are 256 number registers available (per stream)
  • the user can only use number registers 6 to 255, registers 0 to 5 are reserved by the system
  • number registers can only hold whole numbers (integers)
  • a number register stores a 16 bit signed binary value = any value between -32768 and 32767
  • each stream has its own number registers. Number register 10 in the main stream is something else than number register 10 in the footnotes stream or in the frills stream
  • number registers are persistent. Their values are stored within the page file. You can open an existing division on any page you like, start composing and the value stored in a number register will remain the same as with the previous compose.
  • frills can read 'main' number registers (pending, first, last)
  • frills processing can read number registers from any other stream, any block, any line

I modified our page 3 of our test division and switched to using number register 10 that gets dumped and incremented at the start of each line. In the pickups, footnotes and frills we then set number register to a different value and read it out again on the next line:

You will notice that the footnotes 2 and 3 are using the same instance of number register 10 and that the frills blocks share also their instance of number register 10. But the 2 pickups are using 2 different instances of number register 10. In a pickup all blocks share the same number registers, but different pickups use different number registers.

When using number registers it really does not matter what kind of compose you are using. compose one page or compose whole division. It really does not matter. With number registers you will always get the same answer thanks to the persistent nature of number registers.

Text Registers

  • 255 dynamic text registers: 1-255
  • 255 frills text registers: 1-255
  • dynamic and frills text register 0 is special
  • text registers can store strings up to 2500 utf-8 strings
  • dynamic and frills text registers are shared between streams
  • dynamic text registers are temporary and have to be set and read within the same page for consistent results
  • frills text registers are persistent.
  • frills can read pending, first or last instance of a frills text register
  • frills processing can read current content of frills text register 0 from any stream, any block, any line

The use of text registers is illustrated in the screenshot below:

As you can see both the dynamic and frills text register can be accessed from any stream.