1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2004
3114402Sru   Free Software Foundation, Inc.
4114402Sru     Written by James Clark (jjc@jclark.com)
5114402Sru
6114402SruThis file is part of groff.
7114402Sru
8114402Srugroff is free software; you can redistribute it and/or modify it under
9114402Sruthe terms of the GNU General Public License as published by the Free
10114402SruSoftware Foundation; either version 2, or (at your option) any later
11114402Sruversion.
12114402Sru
13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
15114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16114402Srufor more details.
17114402Sru
18114402SruYou should have received a copy of the GNU General Public License along
19114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21114402Sru
22114402Sru
23114402Sru// diversions
24114402Sru
25114402Sru#include "troff.h"
26114402Sru#include "dictionary.h"
27114402Sru#include "hvunits.h"
28151497Sru#include "stringclass.h"
29151497Sru#include "mtsm.h"
30114402Sru#include "env.h"
31114402Sru#include "request.h"
32114402Sru#include "node.h"
33114402Sru#include "token.h"
34114402Sru#include "div.h"
35114402Sru#include "reg.h"
36114402Sru
37151497Sru#include "nonposix.h"
38151497Sru
39114402Sruint exit_started = 0;		// the exit process has started
40114402Sruint done_end_macro = 0;		// the end macro (if any) has finished
41114402Sruint seen_last_page_ejector = 0;	// seen the LAST_PAGE_EJECTOR cookie
42114402Sruint last_page_number = 0;	// if > 0, the number of the last page
43114402Sru				// specified with -o
44114402Srustatic int began_page_in_end_macro = 0;	// a new page was begun during the end macro
45114402Sru
46114402Srustatic int last_post_line_extra_space = 0; // needed for \n(.a
47114402Srustatic int nl_reg_contents = -1;
48114402Srustatic int dl_reg_contents = 0;
49114402Srustatic int dn_reg_contents = 0;
50114402Srustatic int vertical_position_traps_flag = 1;
51114402Srustatic vunits truncated_space;
52114402Srustatic vunits needed_space;
53114402Sru
54114402Srudiversion::diversion(symbol s)
55114402Sru: prev(0), nm(s), vertical_position(V0), high_water_mark(V0),
56151497Sru  any_chars_added(0), no_space_mode(0), needs_push(0), saved_seen_break(0),
57151497Sru  saved_seen_space(0), saved_seen_eol(0), saved_suppress_next_eol(0),
58151497Sru  marked_place(V0)
59114402Sru{
60114402Sru}
61114402Sru
62114402Srustruct vertical_size {
63114402Sru  vunits pre_extra, post_extra, pre, post;
64114402Sru  vertical_size(vunits vs, vunits post_vs);
65114402Sru};
66114402Sru
67114402Sruvertical_size::vertical_size(vunits vs, vunits post_vs)
68114402Sru: pre_extra(V0), post_extra(V0), pre(vs), post(post_vs)
69114402Sru{
70114402Sru}
71114402Sru
72114402Sruvoid node::set_vertical_size(vertical_size *)
73114402Sru{
74114402Sru}
75114402Sru
76114402Sruvoid extra_size_node::set_vertical_size(vertical_size *v)
77114402Sru{
78114402Sru  if (n < V0) {
79114402Sru    if (-n > v->pre_extra)
80114402Sru      v->pre_extra = -n;
81114402Sru  }
82114402Sru  else if (n > v->post_extra)
83114402Sru    v->post_extra = n;
84114402Sru}
85114402Sru
86114402Sruvoid vertical_size_node::set_vertical_size(vertical_size *v)
87114402Sru{
88114402Sru  if (n < V0)
89114402Sru    v->pre = -n;
90114402Sru  else
91114402Sru    v->post = n;
92114402Sru}
93114402Sru
94114402Srutop_level_diversion *topdiv;
95114402Sru
96114402Srudiversion *curdiv;
97114402Sru
98114402Sruvoid do_divert(int append, int boxing)
99114402Sru{
100114402Sru  tok.skip();
101114402Sru  symbol nm = get_name();
102114402Sru  if (nm.is_null()) {
103114402Sru    if (curdiv->prev) {
104151497Sru      curenv->seen_break = curdiv->saved_seen_break;
105151497Sru      curenv->seen_space = curdiv->saved_seen_space;
106151497Sru      curenv->seen_eol = curdiv->saved_seen_eol;
107151497Sru      curenv->suppress_next_eol = curdiv->saved_suppress_next_eol;
108114402Sru      if (boxing) {
109114402Sru	curenv->line = curdiv->saved_line;
110114402Sru	curenv->width_total = curdiv->saved_width_total;
111114402Sru	curenv->space_total = curdiv->saved_space_total;
112114402Sru	curenv->saved_indent = curdiv->saved_saved_indent;
113114402Sru	curenv->target_text_length = curdiv->saved_target_text_length;
114114402Sru	curenv->prev_line_interrupted = curdiv->saved_prev_line_interrupted;
115114402Sru      }
116114402Sru      diversion *temp = curdiv;
117114402Sru      curdiv = curdiv->prev;
118114402Sru      delete temp;
119114402Sru    }
120114402Sru    else
121114402Sru      warning(WARN_DI, "diversion stack underflow");
122114402Sru  }
123114402Sru  else {
124114402Sru    macro_diversion *md = new macro_diversion(nm, append);
125114402Sru    md->prev = curdiv;
126114402Sru    curdiv = md;
127151497Sru    curdiv->saved_seen_break = curenv->seen_break;
128151497Sru    curdiv->saved_seen_space = curenv->seen_space;
129151497Sru    curdiv->saved_seen_eol = curenv->seen_eol;
130151497Sru    curdiv->saved_suppress_next_eol = curenv->suppress_next_eol;
131151497Sru    curenv->seen_break = 0;
132151497Sru    curenv->seen_space = 0;
133151497Sru    curenv->seen_eol = 0;
134114402Sru    if (boxing) {
135114402Sru      curdiv->saved_line = curenv->line;
136114402Sru      curdiv->saved_width_total = curenv->width_total;
137114402Sru      curdiv->saved_space_total = curenv->space_total;
138114402Sru      curdiv->saved_saved_indent = curenv->saved_indent;
139114402Sru      curdiv->saved_target_text_length = curenv->target_text_length;
140114402Sru      curdiv->saved_prev_line_interrupted = curenv->prev_line_interrupted;
141114402Sru      curenv->line = 0;
142114402Sru      curenv->start_line();
143114402Sru    }
144114402Sru  }
145114402Sru  skip_line();
146114402Sru}
147114402Sru
148114402Sruvoid divert()
149114402Sru{
150114402Sru  do_divert(0, 0);
151114402Sru}
152114402Sru
153114402Sruvoid divert_append()
154114402Sru{
155114402Sru  do_divert(1, 0);
156114402Sru}
157114402Sru
158114402Sruvoid box()
159114402Sru{
160114402Sru  do_divert(0, 1);
161114402Sru}
162114402Sru
163114402Sruvoid box_append()
164114402Sru{
165114402Sru  do_divert(1, 1);
166114402Sru}
167114402Sru
168114402Sruvoid diversion::need(vunits n)
169114402Sru{
170114402Sru  vunits d = distance_to_next_trap();
171114402Sru  if (d < n) {
172114402Sru    truncated_space = -d;
173114402Sru    needed_space = n;
174114402Sru    space(d, 1);
175114402Sru  }
176114402Sru}
177114402Sru
178114402Srumacro_diversion::macro_diversion(symbol s, int append)
179114402Sru: diversion(s), max_width(H0)
180114402Sru{
181114402Sru#if 0
182114402Sru  if (append) {
183114402Sru    /* We don't allow recursive appends eg:
184114402Sru
185114402Sru      .da a
186114402Sru      .a
187114402Sru      .di
188114402Sru
189114402Sru      This causes an infinite loop in troff anyway.
190114402Sru      This is because the user could do
191114402Sru
192114402Sru      .as a foo
193114402Sru
194114402Sru      in the diversion, and this would mess things up royally,
195114402Sru      since there would be two things appending to the same
196114402Sru      macro_header.
197114402Sru      To make it work, we would have to copy the _contents_
198114402Sru      of the macro into which we were diverting; this doesn't
199114402Sru      strike me as worthwhile.
200114402Sru      However,
201114402Sru
202114402Sru      .di a
203114402Sru      .a
204114402Sru      .a
205114402Sru      .di
206114402Sru
207114402Sru       will work and will make `a' contain two copies of what it contained
208114402Sru       before; in troff, `a' would contain nothing. */
209114402Sru    request_or_macro *rm
210114402Sru      = (request_or_macro *)request_dictionary.remove(s);
211114402Sru    if (!rm || (mac = rm->to_macro()) == 0)
212114402Sru      mac = new macro;
213114402Sru  }
214114402Sru  else
215114402Sru    mac = new macro;
216114402Sru#endif
217114402Sru  // We can now catch the situation described above by comparing
218114402Sru  // the length of the charlist in the macro_header with the length
219114402Sru  // stored in the macro. When we detect this, we copy the contents.
220151497Sru  mac = new macro(1);
221114402Sru  if (append) {
222114402Sru    request_or_macro *rm
223114402Sru      = (request_or_macro *)request_dictionary.lookup(s);
224114402Sru    if (rm) {
225114402Sru      macro *m = rm->to_macro();
226114402Sru      if (m)
227114402Sru	*mac = *m;
228114402Sru    }
229114402Sru  }
230114402Sru}
231114402Sru
232114402Srumacro_diversion::~macro_diversion()
233114402Sru{
234114402Sru  request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm);
235114402Sru  macro *m = rm ? rm->to_macro() : 0;
236114402Sru  if (m) {
237114402Sru    *m = *mac;
238114402Sru    delete mac;
239114402Sru  }
240114402Sru  else
241114402Sru    request_dictionary.define(nm, mac);
242114402Sru  mac = 0;
243114402Sru  dl_reg_contents = max_width.to_units();
244114402Sru  dn_reg_contents = vertical_position.to_units();
245114402Sru}
246114402Sru
247114402Sruvunits macro_diversion::distance_to_next_trap()
248114402Sru{
249114402Sru  if (!diversion_trap.is_null() && diversion_trap_pos > vertical_position)
250114402Sru    return diversion_trap_pos - vertical_position;
251114402Sru  else
252114402Sru    // Substract vresolution so that vunits::vunits does not overflow.
253114402Sru    return vunits(INT_MAX - vresolution);
254114402Sru}
255114402Sru
256114402Sruvoid macro_diversion::transparent_output(unsigned char c)
257114402Sru{
258114402Sru  mac->append(c);
259114402Sru}
260114402Sru
261114402Sruvoid macro_diversion::transparent_output(node *n)
262114402Sru{
263114402Sru  mac->append(n);
264114402Sru}
265114402Sru
266114402Sruvoid macro_diversion::output(node *nd, int retain_size,
267114402Sru			     vunits vs, vunits post_vs, hunits width)
268114402Sru{
269114402Sru  no_space_mode = 0;
270114402Sru  vertical_size v(vs, post_vs);
271114402Sru  while (nd != 0) {
272114402Sru    nd->set_vertical_size(&v);
273114402Sru    node *temp = nd;
274114402Sru    nd = nd->next;
275151497Sru    if (temp->interpret(mac))
276114402Sru      delete temp;
277114402Sru    else {
278114402Sru#if 1
279114402Sru      temp->freeze_space();
280114402Sru#endif
281114402Sru      mac->append(temp);
282114402Sru    }
283114402Sru  }
284114402Sru  last_post_line_extra_space = v.post_extra.to_units();
285114402Sru  if (!retain_size) {
286114402Sru    v.pre = vs;
287114402Sru    v.post = post_vs;
288114402Sru  }
289114402Sru  if (width > max_width)
290114402Sru    max_width = width;
291114402Sru  vunits x = v.pre + v.pre_extra + v.post + v.post_extra;
292114402Sru  if (vertical_position_traps_flag
293114402Sru      && !diversion_trap.is_null() && diversion_trap_pos > vertical_position
294114402Sru      && diversion_trap_pos <= vertical_position + x) {
295114402Sru    vunits trunc = vertical_position + x - diversion_trap_pos;
296114402Sru    if (trunc > v.post)
297114402Sru      trunc = v.post;
298114402Sru    v.post -= trunc;
299114402Sru    x -= trunc;
300114402Sru    truncated_space = trunc;
301114402Sru    spring_trap(diversion_trap);
302114402Sru  }
303114402Sru  mac->append(new vertical_size_node(-v.pre));
304114402Sru  mac->append(new vertical_size_node(v.post));
305114402Sru  mac->append('\n');
306114402Sru  vertical_position += x;
307114402Sru  if (vertical_position - v.post > high_water_mark)
308114402Sru    high_water_mark = vertical_position - v.post;
309114402Sru}
310114402Sru
311114402Sruvoid macro_diversion::space(vunits n, int)
312114402Sru{
313114402Sru  if (vertical_position_traps_flag
314114402Sru      && !diversion_trap.is_null() && diversion_trap_pos > vertical_position
315114402Sru      && diversion_trap_pos <= vertical_position + n) {
316114402Sru    truncated_space = vertical_position + n - diversion_trap_pos;
317114402Sru    n = diversion_trap_pos - vertical_position;
318114402Sru    spring_trap(diversion_trap);
319114402Sru  }
320114402Sru  else if (n + vertical_position < V0)
321114402Sru    n = -vertical_position;
322114402Sru  mac->append(new diverted_space_node(n));
323114402Sru  vertical_position += n;
324114402Sru}
325114402Sru
326114402Sruvoid macro_diversion::copy_file(const char *filename)
327114402Sru{
328114402Sru  mac->append(new diverted_copy_file_node(filename));
329114402Sru}
330114402Sru
331114402Srutop_level_diversion::top_level_diversion()
332114402Sru: page_number(0), page_count(0), last_page_count(-1),
333114402Sru  page_length(units_per_inch*11),
334114402Sru  prev_page_offset(units_per_inch), page_offset(units_per_inch),
335114402Sru  page_trap_list(0), have_next_page_number(0),
336114402Sru  ejecting_page(0), before_first_page(1)
337114402Sru{
338114402Sru}
339114402Sru
340114402Sru// find the next trap after pos
341114402Sru
342114402Srutrap *top_level_diversion::find_next_trap(vunits *next_trap_pos)
343114402Sru{
344114402Sru  trap *next_trap = 0;
345114402Sru  for (trap *pt = page_trap_list; pt != 0; pt = pt->next)
346114402Sru    if (!pt->nm.is_null()) {
347114402Sru      if (pt->position >= V0) {
348114402Sru	if (pt->position > vertical_position
349114402Sru	    && pt->position < page_length
350114402Sru	    && (next_trap == 0 || pt->position < *next_trap_pos)) {
351114402Sru	      next_trap = pt;
352114402Sru	      *next_trap_pos = pt->position;
353114402Sru	    }
354114402Sru      }
355114402Sru      else {
356114402Sru	vunits pos = pt->position;
357114402Sru	pos += page_length;
358114402Sru	if (pos > 0 && pos > vertical_position && (next_trap == 0 || pos < *next_trap_pos)) {
359114402Sru	  next_trap = pt;
360114402Sru	  *next_trap_pos = pos;
361114402Sru	}
362114402Sru      }
363114402Sru    }
364114402Sru  return next_trap;
365114402Sru}
366114402Sru
367114402Sruvunits top_level_diversion::distance_to_next_trap()
368114402Sru{
369114402Sru  vunits d;
370114402Sru  if (!find_next_trap(&d))
371114402Sru    return page_length - vertical_position;
372114402Sru  else
373114402Sru    return d - vertical_position;
374114402Sru}
375114402Sru
376114402Sruvoid top_level_diversion::output(node *nd, int retain_size,
377114402Sru				 vunits vs, vunits post_vs, hunits width)
378114402Sru{
379114402Sru  no_space_mode = 0;
380114402Sru  vunits next_trap_pos;
381114402Sru  trap *next_trap = find_next_trap(&next_trap_pos);
382114402Sru  if (before_first_page && begin_page())
383114402Sru    fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
384114402Sru  vertical_size v(vs, post_vs);
385114402Sru  for (node *tem = nd; tem != 0; tem = tem->next)
386114402Sru    tem->set_vertical_size(&v);
387114402Sru  last_post_line_extra_space = v.post_extra.to_units();
388114402Sru  if (!retain_size) {
389114402Sru    v.pre = vs;
390114402Sru    v.post = post_vs;
391114402Sru  }
392114402Sru  vertical_position += v.pre;
393114402Sru  vertical_position += v.pre_extra;
394114402Sru  the_output->print_line(page_offset, vertical_position, nd,
395114402Sru			 v.pre + v.pre_extra, v.post_extra, width);
396114402Sru  vertical_position += v.post_extra;
397114402Sru  if (vertical_position > high_water_mark)
398114402Sru    high_water_mark = vertical_position;
399114402Sru  if (vertical_position_traps_flag && vertical_position >= page_length)
400114402Sru    begin_page();
401114402Sru  else if (vertical_position_traps_flag
402114402Sru	   && next_trap != 0 && vertical_position >= next_trap_pos) {
403114402Sru    nl_reg_contents = vertical_position.to_units();
404114402Sru    truncated_space = v.post;
405114402Sru    spring_trap(next_trap->nm);
406114402Sru  }
407114402Sru  else if (v.post > V0) {
408114402Sru    vertical_position += v.post;
409114402Sru    if (vertical_position_traps_flag
410114402Sru	&& next_trap != 0 && vertical_position >= next_trap_pos) {
411114402Sru      truncated_space = vertical_position - next_trap_pos;
412114402Sru      vertical_position = next_trap_pos;
413114402Sru      nl_reg_contents = vertical_position.to_units();
414114402Sru      spring_trap(next_trap->nm);
415114402Sru    }
416114402Sru    else if (vertical_position_traps_flag && vertical_position >= page_length)
417114402Sru      begin_page();
418114402Sru    else
419114402Sru      nl_reg_contents = vertical_position.to_units();
420114402Sru  }
421114402Sru  else
422114402Sru    nl_reg_contents = vertical_position.to_units();
423114402Sru}
424114402Sru
425114402Sruvoid top_level_diversion::transparent_output(unsigned char c)
426114402Sru{
427114402Sru  if (before_first_page && begin_page())
428114402Sru    // This can only happen with the .output request.
429114402Sru    fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
430114402Sru  const char *s = asciify(c);
431114402Sru  while (*s)
432114402Sru    the_output->transparent_char(*s++);
433114402Sru}
434114402Sru
435114402Sruvoid top_level_diversion::transparent_output(node * /*n*/)
436114402Sru{
437114402Sru  error("can't transparently output node at top level");
438114402Sru}
439114402Sru
440114402Sruvoid top_level_diversion::copy_file(const char *filename)
441114402Sru{
442114402Sru  if (before_first_page && begin_page())
443114402Sru    fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
444114402Sru  the_output->copy_file(page_offset, vertical_position, filename);
445114402Sru}
446114402Sru
447114402Sruvoid top_level_diversion::space(vunits n, int forced)
448114402Sru{
449114402Sru  if (no_space_mode) {
450114402Sru    if (!forced)
451114402Sru      return;
452114402Sru    else
453114402Sru      no_space_mode = 0;
454114402Sru  }
455114402Sru  if (before_first_page) {
456114402Sru    begin_page(n);
457114402Sru    return;
458114402Sru  }
459114402Sru  vunits next_trap_pos;
460114402Sru  trap *next_trap = find_next_trap(&next_trap_pos);
461114402Sru  vunits y = vertical_position + n;
462151497Sru  if (curenv->get_vertical_spacing().to_units())
463151497Sru    curenv->seen_space += n.to_units()
464151497Sru			  / curenv->get_vertical_spacing().to_units();
465114402Sru  if (vertical_position_traps_flag && next_trap != 0 && y >= next_trap_pos) {
466114402Sru    vertical_position = next_trap_pos;
467114402Sru    nl_reg_contents = vertical_position.to_units();
468114402Sru    truncated_space = y - vertical_position;
469114402Sru    spring_trap(next_trap->nm);
470114402Sru  }
471114402Sru  else if (y < V0) {
472114402Sru    vertical_position = V0;
473114402Sru    nl_reg_contents = vertical_position.to_units();
474114402Sru  }
475114402Sru  else if (vertical_position_traps_flag && y >= page_length && n >= V0)
476114402Sru    begin_page(y - page_length);
477114402Sru  else {
478114402Sru    vertical_position = y;
479114402Sru    nl_reg_contents = vertical_position.to_units();
480114402Sru  }
481114402Sru}
482114402Sru
483114402Srutrap::trap(symbol s, vunits n, trap *p)
484114402Sru: next(p), position(n), nm(s)
485114402Sru{
486114402Sru}
487114402Sru
488151497Sruvoid top_level_diversion::add_trap(symbol nam, vunits pos)
489114402Sru{
490114402Sru  trap *first_free_slot = 0;
491114402Sru  trap **p;
492114402Sru  for (p = &page_trap_list; *p; p = &(*p)->next) {
493114402Sru    if ((*p)->nm.is_null()) {
494114402Sru      if (first_free_slot == 0)
495114402Sru	first_free_slot = *p;
496114402Sru    }
497114402Sru    else if ((*p)->position == pos) {
498151497Sru      (*p)->nm = nam;
499114402Sru      return;
500114402Sru    }
501114402Sru  }
502114402Sru  if (first_free_slot) {
503151497Sru    first_free_slot->nm = nam;
504114402Sru    first_free_slot->position = pos;
505114402Sru  }
506114402Sru  else
507151497Sru    *p = new trap(nam, pos, 0);
508114402Sru}
509114402Sru
510151497Sruvoid top_level_diversion::remove_trap(symbol nam)
511114402Sru{
512114402Sru  for (trap *p = page_trap_list; p; p = p->next)
513151497Sru    if (p->nm == nam) {
514114402Sru      p->nm = NULL_SYMBOL;
515114402Sru      return;
516114402Sru    }
517114402Sru}
518114402Sru
519114402Sruvoid top_level_diversion::remove_trap_at(vunits pos)
520114402Sru{
521114402Sru  for (trap *p = page_trap_list; p; p = p->next)
522114402Sru    if (p->position == pos) {
523114402Sru      p->nm = NULL_SYMBOL;
524114402Sru      return;
525114402Sru    }
526114402Sru}
527114402Sru
528151497Sruvoid top_level_diversion::change_trap(symbol nam, vunits pos)
529114402Sru{
530114402Sru  for (trap *p = page_trap_list; p; p = p->next)
531151497Sru    if (p->nm == nam) {
532114402Sru      p->position = pos;
533114402Sru      return;
534114402Sru    }
535114402Sru}
536114402Sru
537114402Sruvoid top_level_diversion::print_traps()
538114402Sru{
539114402Sru  for (trap *p = page_trap_list; p; p = p->next)
540114402Sru    if (p->nm.is_null())
541114402Sru      fprintf(stderr, "  empty\n");
542114402Sru    else
543114402Sru      fprintf(stderr, "%s\t%d\n", p->nm.contents(), p->position.to_units());
544114402Sru  fflush(stderr);
545114402Sru}
546114402Sru
547114402Sruvoid end_diversions()
548114402Sru{
549114402Sru  while (curdiv != topdiv) {
550114402Sru    error("automatically ending diversion `%1' on exit",
551114402Sru	    curdiv->nm.contents());
552114402Sru    diversion *tem = curdiv;
553114402Sru    curdiv = curdiv->prev;
554114402Sru    delete tem;
555114402Sru  }
556114402Sru}
557114402Sru
558114402Sruvoid cleanup_and_exit(int exit_code)
559114402Sru{
560114402Sru  if (the_output) {
561114402Sru    the_output->trailer(topdiv->get_page_length());
562114402Sru    delete the_output;
563114402Sru  }
564151497Sru  FLUSH_INPUT_PIPE(STDIN_FILENO);
565114402Sru  exit(exit_code);
566114402Sru}
567114402Sru
568114402Sru// Returns non-zero if it sprung a top-of-page trap.
569114402Sru// The optional parameter is for the .trunc register.
570114402Sruint top_level_diversion::begin_page(vunits n)
571114402Sru{
572114402Sru  if (exit_started) {
573114402Sru    if (page_count == last_page_count
574114402Sru	? curenv->is_empty()
575114402Sru	: (done_end_macro && (seen_last_page_ejector || began_page_in_end_macro)))
576114402Sru      cleanup_and_exit(0);
577114402Sru    if (!done_end_macro)
578114402Sru      began_page_in_end_macro = 1;
579114402Sru  }
580114402Sru  if (last_page_number > 0 && page_number == last_page_number)
581114402Sru    cleanup_and_exit(0);
582114402Sru  if (!the_output)
583114402Sru    init_output();
584114402Sru  ++page_count;
585114402Sru  if (have_next_page_number) {
586114402Sru    page_number = next_page_number;
587114402Sru    have_next_page_number = 0;
588114402Sru  }
589114402Sru  else if (before_first_page == 1)
590114402Sru    page_number = 1;
591114402Sru  else
592114402Sru    page_number++;
593114402Sru  // spring the top of page trap if there is one
594114402Sru  vunits next_trap_pos;
595114402Sru  vertical_position = -vresolution;
596114402Sru  trap *next_trap = find_next_trap(&next_trap_pos);
597114402Sru  vertical_position = V0;
598114402Sru  high_water_mark = V0;
599114402Sru  ejecting_page = 0;
600114402Sru  // If before_first_page was 2, then the top of page transition was undone
601114402Sru  // using eg .nr nl 0-1.  See nl_reg::set_value.
602114402Sru  if (before_first_page != 2)
603114402Sru    the_output->begin_page(page_number, page_length);
604114402Sru  before_first_page = 0;
605114402Sru  nl_reg_contents = vertical_position.to_units();
606114402Sru  if (vertical_position_traps_flag && next_trap != 0 && next_trap_pos == V0) {
607114402Sru    truncated_space = n;
608114402Sru    spring_trap(next_trap->nm);
609114402Sru    return 1;
610114402Sru  }
611114402Sru  else
612114402Sru    return 0;
613114402Sru}
614114402Sru
615114402Sruvoid continue_page_eject()
616114402Sru{
617114402Sru  if (topdiv->get_ejecting()) {
618114402Sru    if (curdiv != topdiv)
619114402Sru      error("can't continue page ejection because of current diversion");
620114402Sru    else if (!vertical_position_traps_flag)
621114402Sru      error("can't continue page ejection because vertical position traps disabled");
622114402Sru    else {
623114402Sru      push_page_ejector();
624114402Sru      topdiv->space(topdiv->get_page_length(), 1);
625114402Sru    }
626114402Sru  }
627114402Sru}
628114402Sru
629114402Sruvoid top_level_diversion::set_next_page_number(int n)
630114402Sru{
631114402Sru  next_page_number= n;
632114402Sru  have_next_page_number = 1;
633114402Sru}
634114402Sru
635114402Sruint top_level_diversion::get_next_page_number()
636114402Sru{
637114402Sru  return have_next_page_number ? next_page_number : page_number + 1;
638114402Sru}
639114402Sru
640114402Sruvoid top_level_diversion::set_page_length(vunits n)
641114402Sru{
642114402Sru  page_length = n;
643114402Sru}
644114402Sru
645114402Srudiversion::~diversion()
646114402Sru{
647114402Sru}
648114402Sru
649114402Sruvoid page_offset()
650114402Sru{
651114402Sru  hunits n;
652114402Sru  // The troff manual says that the default scaling indicator is v,
653114402Sru  // but it is in fact m: v wouldn't make sense for a horizontally
654114402Sru  // oriented request.
655114402Sru  if (!has_arg() || !get_hunits(&n, 'm', topdiv->page_offset))
656114402Sru    n = topdiv->prev_page_offset;
657114402Sru  topdiv->prev_page_offset = topdiv->page_offset;
658114402Sru  topdiv->page_offset = n;
659151497Sru  topdiv->modified_tag.incl(MTSM_PO);
660114402Sru  skip_line();
661114402Sru}
662114402Sru
663114402Sruvoid page_length()
664114402Sru{
665114402Sru  vunits n;
666114402Sru  if (has_arg() && get_vunits(&n, 'v', topdiv->get_page_length()))
667114402Sru    topdiv->set_page_length(n);
668114402Sru  else
669114402Sru    topdiv->set_page_length(11*units_per_inch);
670114402Sru  skip_line();
671114402Sru}
672114402Sru
673114402Sruvoid when_request()
674114402Sru{
675114402Sru  vunits n;
676114402Sru  if (get_vunits(&n, 'v')) {
677114402Sru    symbol s = get_name();
678114402Sru    if (s.is_null())
679114402Sru      topdiv->remove_trap_at(n);
680114402Sru    else
681114402Sru      topdiv->add_trap(s, n);
682114402Sru  }
683114402Sru  skip_line();
684114402Sru}
685114402Sru
686114402Sruvoid begin_page()
687114402Sru{
688114402Sru  int got_arg = 0;
689151497Sru  int n = 0;		/* pacify compiler */
690114402Sru  if (has_arg() && get_integer(&n, topdiv->get_page_number()))
691114402Sru    got_arg = 1;
692114402Sru  while (!tok.newline() && !tok.eof())
693114402Sru    tok.next();
694114402Sru  if (curdiv == topdiv) {
695114402Sru    if (topdiv->before_first_page) {
696114402Sru      if (!break_flag) {
697114402Sru	if (got_arg)
698114402Sru	  topdiv->set_next_page_number(n);
699114402Sru	if (got_arg || !topdiv->no_space_mode)
700114402Sru	  topdiv->begin_page();
701114402Sru      }
702114402Sru      else if (topdiv->no_space_mode && !got_arg)
703114402Sru	topdiv->begin_page();
704114402Sru      else {
705114402Sru	/* Given this
706114402Sru
707114402Sru         .wh 0 x
708114402Sru	 .de x
709114402Sru	 .tm \\n%
710114402Sru	 ..
711114402Sru	 .bp 3
712114402Sru
713114402Sru	 troff prints
714114402Sru
715114402Sru	 1
716114402Sru	 3
717114402Sru
718114402Sru	 This code makes groff do the same. */
719114402Sru
720114402Sru	push_page_ejector();
721114402Sru	topdiv->begin_page();
722114402Sru	if (got_arg)
723114402Sru	  topdiv->set_next_page_number(n);
724114402Sru	topdiv->set_ejecting();
725114402Sru      }
726114402Sru    }
727114402Sru    else {
728114402Sru      push_page_ejector();
729114402Sru      if (break_flag)
730114402Sru	curenv->do_break();
731114402Sru      if (got_arg)
732114402Sru	topdiv->set_next_page_number(n);
733114402Sru      if (!(topdiv->no_space_mode && !got_arg))
734114402Sru	topdiv->set_ejecting();
735114402Sru    }
736114402Sru  }
737114402Sru  tok.next();
738114402Sru}
739114402Sru
740114402Sruvoid no_space()
741114402Sru{
742114402Sru  curdiv->no_space_mode = 1;
743114402Sru  skip_line();
744114402Sru}
745114402Sru
746114402Sruvoid restore_spacing()
747114402Sru{
748114402Sru  curdiv->no_space_mode = 0;
749114402Sru  skip_line();
750114402Sru}
751114402Sru
752151497Sru/* It is necessary to generate a break before reading the argument,
753151497Srubecause otherwise arguments using | will be wrong.  But if we just
754114402Srugenerate a break as usual, then the line forced out may spring a trap
755114402Sruand thus push a macro onto the input stack before we have had a chance
756151497Sruto read the argument to the sp request.  We resolve this dilemma by
757114402Srusetting, before generating the break, a flag which will postpone the
758114402Sruactual pushing of the macro associated with the trap sprung by the
759114402Sruoutputting of the line forced out by the break till after we have read
760114402Sruthe argument to the request.  If the break did cause a trap to be
761114402Srusprung, then we don't actually do the space. */
762114402Sru
763114402Sruvoid space_request()
764114402Sru{
765114402Sru  postpone_traps();
766114402Sru  if (break_flag)
767114402Sru    curenv->do_break();
768114402Sru  vunits n;
769114402Sru  if (!has_arg() || !get_vunits(&n, 'v'))
770114402Sru    n = curenv->get_vertical_spacing();
771114402Sru  while (!tok.newline() && !tok.eof())
772114402Sru    tok.next();
773114402Sru  if (!unpostpone_traps() && !curdiv->no_space_mode)
774114402Sru    curdiv->space(n);
775114402Sru  else
776114402Sru    // The line might have had line spacing that was truncated.
777114402Sru    truncated_space += n;
778151497Sru
779114402Sru  tok.next();
780114402Sru}
781114402Sru
782114402Sruvoid blank_line()
783114402Sru{
784114402Sru  curenv->do_break();
785151497Sru  if (!trap_sprung_flag && !curdiv->no_space_mode)
786114402Sru    curdiv->space(curenv->get_vertical_spacing());
787114402Sru  else
788114402Sru    truncated_space += curenv->get_vertical_spacing();
789114402Sru}
790114402Sru
791114402Sru/* need_space might spring a trap and so we must be careful that the
792114402SruBEGIN_TRAP token is not skipped over. */
793114402Sru
794114402Sruvoid need_space()
795114402Sru{
796114402Sru  vunits n;
797114402Sru  if (!has_arg() || !get_vunits(&n, 'v'))
798114402Sru    n = curenv->get_vertical_spacing();
799114402Sru  while (!tok.newline() && !tok.eof())
800114402Sru    tok.next();
801114402Sru  curdiv->need(n);
802114402Sru  tok.next();
803114402Sru}
804114402Sru
805114402Sruvoid page_number()
806114402Sru{
807114402Sru  int n;
808114402Sru
809114402Sru  // the ps4html register is set if we are using -Tps
810114402Sru  // to generate images for html
811114402Sru  reg *r = (reg *)number_reg_dictionary.lookup("ps4html");
812114402Sru  if (r == NULL)
813114402Sru    if (has_arg() && get_integer(&n, topdiv->get_page_number()))
814114402Sru      topdiv->set_next_page_number(n);
815114402Sru  skip_line();
816114402Sru}
817114402Sru
818114402Sruvunits saved_space;
819114402Sru
820114402Sruvoid save_vertical_space()
821114402Sru{
822114402Sru  vunits x;
823114402Sru  if (!has_arg() || !get_vunits(&x, 'v'))
824114402Sru    x = curenv->get_vertical_spacing();
825114402Sru  if (curdiv->distance_to_next_trap() > x)
826114402Sru    curdiv->space(x, 1);
827114402Sru  else
828114402Sru    saved_space = x;
829114402Sru  skip_line();
830114402Sru}
831114402Sru
832114402Sruvoid output_saved_vertical_space()
833114402Sru{
834114402Sru  while (!tok.newline() && !tok.eof())
835114402Sru    tok.next();
836114402Sru  if (saved_space > V0)
837114402Sru    curdiv->space(saved_space, 1);
838114402Sru  saved_space = V0;
839114402Sru  tok.next();
840114402Sru}
841114402Sru
842114402Sruvoid flush_output()
843114402Sru{
844114402Sru  while (!tok.newline() && !tok.eof())
845114402Sru    tok.next();
846114402Sru  if (break_flag)
847114402Sru    curenv->do_break();
848114402Sru  if (the_output)
849114402Sru    the_output->flush();
850114402Sru  tok.next();
851114402Sru}
852114402Sru
853114402Sruvoid macro_diversion::set_diversion_trap(symbol s, vunits n)
854114402Sru{
855114402Sru  diversion_trap = s;
856114402Sru  diversion_trap_pos = n;
857114402Sru}
858114402Sru
859114402Sruvoid macro_diversion::clear_diversion_trap()
860114402Sru{
861114402Sru  diversion_trap = NULL_SYMBOL;
862114402Sru}
863114402Sru
864114402Sruvoid top_level_diversion::set_diversion_trap(symbol, vunits)
865114402Sru{
866114402Sru  error("can't set diversion trap when no current diversion");
867114402Sru}
868114402Sru
869114402Sruvoid top_level_diversion::clear_diversion_trap()
870114402Sru{
871114402Sru  error("can't set diversion trap when no current diversion");
872114402Sru}
873114402Sru
874114402Sruvoid diversion_trap()
875114402Sru{
876114402Sru  vunits n;
877114402Sru  if (has_arg() && get_vunits(&n, 'v')) {
878114402Sru    symbol s = get_name();
879114402Sru    if (!s.is_null())
880114402Sru      curdiv->set_diversion_trap(s, n);
881114402Sru    else
882114402Sru      curdiv->clear_diversion_trap();
883114402Sru  }
884114402Sru  else
885114402Sru    curdiv->clear_diversion_trap();
886114402Sru  skip_line();
887114402Sru}
888114402Sru
889114402Sruvoid change_trap()
890114402Sru{
891114402Sru  symbol s = get_name(1);
892114402Sru  if (!s.is_null()) {
893114402Sru    vunits x;
894114402Sru    if (has_arg() && get_vunits(&x, 'v'))
895114402Sru      topdiv->change_trap(s, x);
896114402Sru    else
897114402Sru      topdiv->remove_trap(s);
898114402Sru  }
899114402Sru  skip_line();
900114402Sru}
901114402Sru
902114402Sruvoid print_traps()
903114402Sru{
904114402Sru  topdiv->print_traps();
905114402Sru  skip_line();
906114402Sru}
907114402Sru
908114402Sruvoid mark()
909114402Sru{
910114402Sru  symbol s = get_name();
911114402Sru  if (s.is_null())
912114402Sru    curdiv->marked_place = curdiv->get_vertical_position();
913114402Sru  else if (curdiv == topdiv)
914114402Sru    set_number_reg(s, nl_reg_contents);
915114402Sru  else
916114402Sru    set_number_reg(s, curdiv->get_vertical_position().to_units());
917114402Sru  skip_line();
918114402Sru}
919114402Sru
920114402Sru// This is truly bizarre.  It is documented in the SQ manual.
921114402Sru
922114402Sruvoid return_request()
923114402Sru{
924114402Sru  vunits dist = curdiv->marked_place - curdiv->get_vertical_position();
925114402Sru  if (has_arg()) {
926114402Sru    if (tok.ch() == '-') {
927114402Sru      tok.next();
928114402Sru      vunits x;
929114402Sru      if (get_vunits(&x, 'v'))
930114402Sru	dist = -x;
931114402Sru    }
932114402Sru    else {
933114402Sru      vunits x;
934114402Sru      if (get_vunits(&x, 'v'))
935114402Sru	dist = x >= V0 ? x - curdiv->get_vertical_position() : V0;
936114402Sru    }
937114402Sru  }
938114402Sru  if (dist < V0)
939114402Sru    curdiv->space(dist);
940114402Sru  skip_line();
941114402Sru}
942114402Sru
943114402Sruvoid vertical_position_traps()
944114402Sru{
945114402Sru  int n;
946114402Sru  if (has_arg() && get_integer(&n))
947114402Sru    vertical_position_traps_flag = (n != 0);
948114402Sru  else
949114402Sru    vertical_position_traps_flag = 1;
950114402Sru  skip_line();
951114402Sru}
952114402Sru
953114402Sruclass page_offset_reg : public reg {
954114402Srupublic:
955114402Sru  int get_value(units *);
956114402Sru  const char *get_string();
957114402Sru};
958114402Sru
959114402Sruint page_offset_reg::get_value(units *res)
960114402Sru{
961114402Sru  *res = topdiv->get_page_offset().to_units();
962114402Sru  return 1;
963114402Sru}
964114402Sru
965114402Sruconst char *page_offset_reg::get_string()
966114402Sru{
967114402Sru  return i_to_a(topdiv->get_page_offset().to_units());
968114402Sru}
969114402Sru
970114402Sruclass page_length_reg : public reg {
971114402Srupublic:
972114402Sru  int get_value(units *);
973114402Sru  const char *get_string();
974114402Sru};
975114402Sru
976114402Sruint page_length_reg::get_value(units *res)
977114402Sru{
978114402Sru  *res = topdiv->get_page_length().to_units();
979114402Sru  return 1;
980114402Sru}
981114402Sru
982114402Sruconst char *page_length_reg::get_string()
983114402Sru{
984114402Sru  return i_to_a(topdiv->get_page_length().to_units());
985114402Sru}
986114402Sru
987114402Sruclass vertical_position_reg : public reg {
988114402Srupublic:
989114402Sru  int get_value(units *);
990114402Sru  const char *get_string();
991114402Sru};
992114402Sru
993114402Sruint vertical_position_reg::get_value(units *res)
994114402Sru{
995114402Sru  if (curdiv == topdiv && topdiv->before_first_page)
996114402Sru    *res = -1;
997114402Sru  else
998114402Sru    *res = curdiv->get_vertical_position().to_units();
999114402Sru  return 1;
1000114402Sru}
1001114402Sru
1002114402Sruconst char *vertical_position_reg::get_string()
1003114402Sru{
1004114402Sru  if (curdiv == topdiv && topdiv->before_first_page)
1005114402Sru    return "-1";
1006114402Sru  else
1007114402Sru    return i_to_a(curdiv->get_vertical_position().to_units());
1008114402Sru}
1009114402Sru
1010114402Sruclass high_water_mark_reg : public reg {
1011114402Srupublic:
1012114402Sru  int get_value(units *);
1013114402Sru  const char *get_string();
1014114402Sru};
1015114402Sru
1016114402Sruint high_water_mark_reg::get_value(units *res)
1017114402Sru{
1018114402Sru  *res = curdiv->get_high_water_mark().to_units();
1019114402Sru  return 1;
1020114402Sru}
1021114402Sru
1022114402Sruconst char *high_water_mark_reg::get_string()
1023114402Sru{
1024114402Sru  return i_to_a(curdiv->get_high_water_mark().to_units());
1025114402Sru}
1026114402Sru
1027114402Sruclass distance_to_next_trap_reg : public reg {
1028114402Srupublic:
1029114402Sru  int get_value(units *);
1030114402Sru  const char *get_string();
1031114402Sru};
1032114402Sru
1033114402Sruint distance_to_next_trap_reg::get_value(units *res)
1034114402Sru{
1035114402Sru  *res = curdiv->distance_to_next_trap().to_units();
1036114402Sru  return 1;
1037114402Sru}
1038114402Sru
1039114402Sruconst char *distance_to_next_trap_reg::get_string()
1040114402Sru{
1041114402Sru  return i_to_a(curdiv->distance_to_next_trap().to_units());
1042114402Sru}
1043114402Sru
1044114402Sruclass diversion_name_reg : public reg {
1045114402Srupublic:
1046114402Sru  const char *get_string();
1047114402Sru};
1048114402Sru
1049114402Sruconst char *diversion_name_reg::get_string()
1050114402Sru{
1051114402Sru  return curdiv->get_diversion_name();
1052114402Sru}
1053114402Sru
1054114402Sruclass page_number_reg : public general_reg {
1055114402Srupublic:
1056114402Sru  page_number_reg();
1057114402Sru  int get_value(units *);
1058114402Sru  void set_value(units);
1059114402Sru};
1060114402Sru
1061114402Srupage_number_reg::page_number_reg()
1062114402Sru{
1063114402Sru}
1064114402Sru
1065114402Sruvoid page_number_reg::set_value(units n)
1066114402Sru{
1067114402Sru  topdiv->set_page_number(n);
1068114402Sru}
1069114402Sru
1070114402Sruint page_number_reg::get_value(units *res)
1071114402Sru{
1072114402Sru  *res = topdiv->get_page_number();
1073114402Sru  return 1;
1074114402Sru}
1075114402Sru
1076114402Sruclass next_page_number_reg : public reg {
1077114402Srupublic:
1078114402Sru  const char *get_string();
1079114402Sru};
1080114402Sru
1081114402Sruconst char *next_page_number_reg::get_string()
1082114402Sru{
1083114402Sru  return i_to_a(topdiv->get_next_page_number());
1084114402Sru}
1085114402Sru
1086114402Sruclass page_ejecting_reg : public reg {
1087114402Srupublic:
1088114402Sru  const char *get_string();
1089114402Sru};
1090114402Sru
1091114402Sruconst char *page_ejecting_reg::get_string()
1092114402Sru{
1093114402Sru  return i_to_a(topdiv->get_ejecting());
1094114402Sru}
1095114402Sru
1096114402Sruclass constant_vunits_reg : public reg {
1097114402Sru  vunits *p;
1098114402Srupublic:
1099114402Sru  constant_vunits_reg(vunits *);
1100114402Sru  const char *get_string();
1101114402Sru};
1102114402Sru
1103114402Sruconstant_vunits_reg::constant_vunits_reg(vunits *q) : p(q)
1104114402Sru{
1105114402Sru}
1106114402Sru
1107114402Sruconst char *constant_vunits_reg::get_string()
1108114402Sru{
1109114402Sru  return i_to_a(p->to_units());
1110114402Sru}
1111114402Sru
1112114402Sruclass nl_reg : public variable_reg {
1113114402Srupublic:
1114114402Sru  nl_reg();
1115114402Sru  void set_value(units);
1116114402Sru};
1117114402Sru
1118114402Srunl_reg::nl_reg() : variable_reg(&nl_reg_contents)
1119114402Sru{
1120114402Sru}
1121114402Sru
1122114402Sruvoid nl_reg::set_value(units n)
1123114402Sru{
1124114402Sru  variable_reg::set_value(n);
1125114402Sru  // Setting nl to a negative value when the vertical position in
1126114402Sru  // the top-level diversion is 0 undoes the top of page transition,
1127114402Sru  // so that the header macro will be called as if the top of page
1128114402Sru  // transition hasn't happened.  This is used by Larry Wall's
1129114402Sru  // wrapman program.  Setting before_first_page to 2 rather than 1,
1130114402Sru  // tells top_level_diversion::begin_page not to call
1131114402Sru  // output_file::begin_page again.
1132114402Sru  if (n < 0 && topdiv->get_vertical_position() == V0)
1133114402Sru    topdiv->before_first_page = 2;
1134114402Sru}
1135114402Sru
1136114402Sruclass no_space_mode_reg : public reg {
1137114402Srupublic:
1138114402Sru  int get_value(units *);
1139114402Sru  const char *get_string();
1140114402Sru};
1141114402Sru
1142114402Sruint no_space_mode_reg::get_value(units *val)
1143114402Sru{
1144114402Sru  *val = curdiv->no_space_mode;
1145114402Sru  return 1;
1146114402Sru}
1147114402Sru
1148114402Sruconst char *no_space_mode_reg::get_string()
1149114402Sru{
1150114402Sru  return curdiv->no_space_mode ? "1" : "0";
1151114402Sru}
1152114402Sru
1153114402Sruvoid init_div_requests()
1154114402Sru{
1155114402Sru  init_request("box", box);
1156114402Sru  init_request("boxa", box_append);
1157114402Sru  init_request("bp", begin_page);
1158114402Sru  init_request("ch", change_trap);
1159114402Sru  init_request("da", divert_append);
1160114402Sru  init_request("di", divert);
1161114402Sru  init_request("dt", diversion_trap);
1162114402Sru  init_request("fl", flush_output);
1163114402Sru  init_request("mk", mark);
1164114402Sru  init_request("ne", need_space);
1165114402Sru  init_request("ns", no_space);
1166114402Sru  init_request("os", output_saved_vertical_space);
1167114402Sru  init_request("pl", page_length);
1168114402Sru  init_request("pn", page_number);
1169114402Sru  init_request("po", page_offset);
1170114402Sru  init_request("ptr", print_traps);
1171114402Sru  init_request("rs", restore_spacing);
1172114402Sru  init_request("rt", return_request);
1173114402Sru  init_request("sp", space_request);
1174114402Sru  init_request("sv", save_vertical_space);
1175114402Sru  init_request("vpt", vertical_position_traps);
1176114402Sru  init_request("wh", when_request);
1177114402Sru  number_reg_dictionary.define(".a",
1178114402Sru		       new constant_int_reg(&last_post_line_extra_space));
1179114402Sru  number_reg_dictionary.define(".d", new vertical_position_reg);
1180114402Sru  number_reg_dictionary.define(".h", new high_water_mark_reg);
1181114402Sru  number_reg_dictionary.define(".ne",
1182114402Sru			       new constant_vunits_reg(&needed_space));
1183114402Sru  number_reg_dictionary.define(".ns", new no_space_mode_reg);
1184114402Sru  number_reg_dictionary.define(".o", new page_offset_reg);
1185114402Sru  number_reg_dictionary.define(".p", new page_length_reg);
1186114402Sru  number_reg_dictionary.define(".pe", new page_ejecting_reg);
1187114402Sru  number_reg_dictionary.define(".pn", new next_page_number_reg);
1188114402Sru  number_reg_dictionary.define(".t", new distance_to_next_trap_reg);
1189114402Sru  number_reg_dictionary.define(".trunc",
1190114402Sru			       new constant_vunits_reg(&truncated_space));
1191114402Sru  number_reg_dictionary.define(".vpt",
1192114402Sru		       new constant_int_reg(&vertical_position_traps_flag));
1193114402Sru  number_reg_dictionary.define(".z", new diversion_name_reg);
1194114402Sru  number_reg_dictionary.define("dl", new variable_reg(&dl_reg_contents));
1195114402Sru  number_reg_dictionary.define("dn", new variable_reg(&dn_reg_contents));
1196114402Sru  number_reg_dictionary.define("nl", new nl_reg);
1197114402Sru  number_reg_dictionary.define("%", new page_number_reg);
1198114402Sru}
1199