2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
26 #include "dictionary.h"
35 int exit_started
= 0; // the exit process has started
36 int done_end_macro
= 0; // the end macro (if any) has finished
37 int seen_last_page_ejector
= 0; // seen the LAST_PAGE_EJECTOR cookie
38 static int began_page_in_end_macro
= 0; // a new page was begun during the end macro
40 static int last_post_line_extra_space
= 0; // needed for \n(.a
41 static int nl_reg_contents
= -1;
42 static int dl_reg_contents
= 0;
43 static int dn_reg_contents
= 0;
44 static int vertical_position_traps_flag
= 1;
45 static vunits truncated_space
;
46 static vunits needed_space
;
48 diversion::diversion(symbol s
)
49 : nm(s
), prev(0), vertical_position(V0
), marked_place(V0
), high_water_mark(V0
)
53 struct vertical_size
{
54 vunits pre_extra
, post_extra
, pre
, post
;
55 vertical_size(vunits vs
, int ls
);
58 vertical_size::vertical_size(vunits vs
, int ls
)
59 : pre_extra(V0
), post_extra(V0
), pre(vs
)
67 void node::set_vertical_size(vertical_size
*)
71 void extra_size_node::set_vertical_size(vertical_size
*v
)
74 if (-n
> v
->pre_extra
)
77 else if (n
> v
->post_extra
)
81 void vertical_size_node::set_vertical_size(vertical_size
*v
)
89 top_level_diversion
*topdiv
;
93 void do_divert(int append
)
96 symbol nm
= get_name();
99 diversion
*temp
= curdiv
;
100 curdiv
= curdiv
->prev
;
104 warning(WARN_DI
, "diversion stack underflow");
107 macro_diversion
*md
= new macro_diversion(nm
, append
);
124 void diversion::need(vunits n
)
126 vunits d
= distance_to_next_trap();
129 truncated_space
= -d
;
134 macro_diversion::macro_diversion(symbol s
, int append
)
135 : diversion(s
), max_width(H0
)
139 /* We don't allow recursive appends eg:
145 This causes an infinite loop in troff anyway.
146 This is because the user could do
150 in the diversion, and this would mess things up royally,
151 since there would be two things appending to the same
153 To make it work, we would have to copy the _contents_
154 of the macro into which we were diverting; this doesn't
155 strike me as worthwhile.
163 will work and will make `a' contain two copies of what it contained
164 before; in troff, `a' would contain nothing. */
166 = (request_or_macro
*)request_dictionary
.remove(s
);
167 if (!rm
|| (mac
= rm
->to_macro()) == 0)
173 // We can now catch the situation described above by comparing
174 // the length of the charlist in the macro_header with the length
175 // stored in the macro. When we detect this, we copy the contents.
179 = (request_or_macro
*)request_dictionary
.lookup(s
);
181 macro
*m
= rm
->to_macro();
188 macro_diversion::~macro_diversion()
190 request_or_macro
*rm
= (request_or_macro
*)request_dictionary
.lookup(nm
);
191 macro
*m
= rm
? rm
->to_macro() : 0;
197 request_dictionary
.define(nm
, mac
);
199 dl_reg_contents
= max_width
.to_units();
200 dn_reg_contents
= vertical_position
.to_units();
203 vunits
macro_diversion::distance_to_next_trap()
205 if (!diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
)
206 return diversion_trap_pos
- vertical_position
;
208 // Substract vresolution so that vunits::vunits does not overflow.
209 return vunits(INT_MAX
- vresolution
);
212 void macro_diversion::transparent_output(unsigned char c
)
217 void macro_diversion::transparent_output(node
*n
)
222 void macro_diversion::output(node
*nd
, int retain_size
,
223 vunits vs
, int ls
, hunits width
)
225 vertical_size
v(vs
, ls
);
227 nd
->set_vertical_size(&v
);
230 if (temp
->interpret(mac
)) {
235 temp
->freeze_space();
240 if (!v
.post_extra
.is_zero())
241 last_post_line_extra_space
= v
.post_extra
.to_units();
244 v
.post
= (ls
> 1) ? vs
*(ls
- 1) : V0
;
246 if (width
> max_width
)
248 vunits x
= v
.pre
+ v
.pre_extra
+ v
.post
+ v
.post_extra
;
249 if (vertical_position_traps_flag
250 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
251 && diversion_trap_pos
<= vertical_position
+ x
) {
252 vunits trunc
= vertical_position
+ x
- diversion_trap_pos
;
257 truncated_space
= trunc
;
258 spring_trap(diversion_trap
);
260 mac
->append(new vertical_size_node(-v
.pre
));
261 mac
->append(new vertical_size_node(v
.post
));
263 vertical_position
+= x
;
264 if (vertical_position
> high_water_mark
)
265 high_water_mark
= vertical_position
;
268 void macro_diversion::space(vunits n
, int)
270 if (vertical_position_traps_flag
271 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
272 && diversion_trap_pos
<= vertical_position
+ n
) {
273 truncated_space
= vertical_position
+ n
- diversion_trap_pos
;
274 n
= diversion_trap_pos
- vertical_position
;
275 spring_trap(diversion_trap
);
277 else if (n
+ vertical_position
< V0
)
278 n
= -vertical_position
;
279 mac
->append(new diverted_space_node(n
));
280 vertical_position
+= n
;
281 if (vertical_position
> high_water_mark
)
282 high_water_mark
= vertical_position
;
285 void macro_diversion::copy_file(const char *filename
)
287 mac
->append(new diverted_copy_file_node(filename
));
290 top_level_diversion::top_level_diversion()
291 : page_count(0), have_next_page_number(0), page_length(units_per_inch
*11),
292 page_offset(units_per_inch
), prev_page_offset(units_per_inch
),
293 ejecting_page(0), page_trap_list(0), first_page_begun(0), no_space_mode(0),
294 page_number(0), last_page_count(-1)
298 // find the next trap after pos
300 trap
*top_level_diversion::find_next_trap(vunits
*next_trap_pos
)
303 for (trap
*pt
= page_trap_list
; pt
!= 0; pt
= pt
->next
)
304 if (!pt
->nm
.is_null()) {
305 if (pt
->position
>= V0
) {
306 if (pt
->position
> vertical_position
307 && pt
->position
< page_length
308 && (next_trap
== 0 || pt
->position
< *next_trap_pos
)) {
310 *next_trap_pos
= pt
->position
;
314 vunits pos
= pt
->position
;
316 if (pos
> 0 && pos
> vertical_position
&& (next_trap
== 0 || pos
< *next_trap_pos
)) {
318 *next_trap_pos
= pos
;
325 vunits
top_level_diversion::distance_to_next_trap()
328 if (!find_next_trap(&d
))
329 return page_length
- vertical_position
;
331 return d
- vertical_position
;
334 void top_level_diversion::output(node
*nd
, int retain_size
,
335 vunits vs
, int ls
, hunits
/*width*/)
338 vunits next_trap_pos
;
339 trap
*next_trap
= find_next_trap(&next_trap_pos
);
340 if (!first_page_begun
&& begin_page())
341 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
342 vertical_size
v(vs
, ls
);
343 for (node
*tem
= nd
; tem
!= 0; tem
= tem
->next
)
344 tem
->set_vertical_size(&v
);
345 if (!v
.post_extra
.is_zero())
346 last_post_line_extra_space
= v
.post_extra
.to_units();
349 v
.post
= (ls
> 1) ? vs
*(ls
- 1) : V0
;
351 vertical_position
+= v
.pre
;
352 vertical_position
+= v
.pre_extra
;
353 the_output
->print_line(page_offset
, vertical_position
, nd
,
354 v
.pre
+ v
.pre_extra
, v
.post_extra
);
355 vertical_position
+= v
.post_extra
;
356 if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
358 else if (vertical_position_traps_flag
359 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
360 nl_reg_contents
= vertical_position
.to_units();
361 truncated_space
= v
.post
;
362 if (vertical_position
> high_water_mark
)
363 high_water_mark
= vertical_position
;
364 spring_trap(next_trap
->nm
);
366 else if (v
.post
> V0
) {
367 vertical_position
+= v
.post
;
368 if (vertical_position_traps_flag
369 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
370 truncated_space
= vertical_position
- next_trap_pos
;
371 vertical_position
= next_trap_pos
;
372 nl_reg_contents
= vertical_position
.to_units();
373 if (vertical_position
> high_water_mark
)
374 high_water_mark
= vertical_position
;
375 spring_trap(next_trap
->nm
);
377 else if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
380 nl_reg_contents
= vertical_position
.to_units();
381 if (vertical_position
> high_water_mark
)
382 high_water_mark
= vertical_position
;
386 nl_reg_contents
= vertical_position
.to_units();
387 if (vertical_position
> high_water_mark
)
388 high_water_mark
= vertical_position
;
392 void top_level_diversion::transparent_output(unsigned char c
)
394 if (!first_page_begun
&& begin_page())
395 // This can only happen with the transparent() request.
396 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
397 const char *s
= asciify(c
);
399 the_output
->transparent_char(*s
++);
402 void top_level_diversion::transparent_output(node
* /*n*/)
404 error("can't transparently output node at top level");
407 void top_level_diversion::copy_file(const char *filename
)
409 if (!first_page_begun
&& begin_page())
410 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
411 the_output
->copy_file(page_offset
, vertical_position
, filename
);
414 void top_level_diversion::space(vunits n
, int forced
)
422 if (!first_page_begun
) {
424 // This happens if there's a top of page trap, and the first-page
425 // transition is caused by `'sp'.
426 truncated_space
= n
> V0
? n
: V0
;
430 vunits next_trap_pos
;
431 trap
*next_trap
= find_next_trap(&next_trap_pos
);
432 vunits y
= vertical_position
+ n
;
433 if (vertical_position_traps_flag
&& next_trap
!= 0 && y
>= next_trap_pos
) {
434 vertical_position
= next_trap_pos
;
435 nl_reg_contents
= vertical_position
.to_units();
436 truncated_space
= y
- vertical_position
;
437 if (vertical_position
> high_water_mark
)
438 high_water_mark
= vertical_position
;
439 spring_trap(next_trap
->nm
);
442 vertical_position
= V0
;
443 nl_reg_contents
= vertical_position
.to_units();
445 else if (vertical_position_traps_flag
&& y
>= page_length
&& n
>= V0
)
448 vertical_position
= y
;
449 nl_reg_contents
= vertical_position
.to_units();
450 if (vertical_position
> high_water_mark
)
451 high_water_mark
= vertical_position
;
455 trap::trap(symbol s
, vunits n
, trap
*p
)
456 : nm(s
), next(p
), position(n
)
460 void top_level_diversion::add_trap(symbol nm
, vunits pos
)
462 trap
*first_free_slot
= 0;
463 for (trap
**p
= &page_trap_list
; *p
; p
= &(*p
)->next
) {
464 if ((*p
)->nm
.is_null()) {
465 if (first_free_slot
== 0)
466 first_free_slot
= *p
;
468 else if ((*p
)->position
== pos
) {
473 if (first_free_slot
) {
474 first_free_slot
->nm
= nm
;
475 first_free_slot
->position
= pos
;
478 *p
= new trap(nm
, pos
, 0);
481 void top_level_diversion::remove_trap(symbol nm
)
483 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
490 void top_level_diversion::remove_trap_at(vunits pos
)
492 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
493 if (p
->position
== pos
) {
499 void top_level_diversion::change_trap(symbol nm
, vunits pos
)
501 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
508 void top_level_diversion::print_traps()
510 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
512 fprintf(stderr
, " empty\n");
514 fprintf(stderr
, "%s\t%d\n", p
->nm
.contents(), p
->position
.to_units());
518 void end_diversions()
520 while (curdiv
!= topdiv
) {
521 error("automatically ending diversion `%1' on exit",
522 curdiv
->nm
.contents());
523 diversion
*tem
= curdiv
;
524 curdiv
= curdiv
->prev
;
529 NO_RETURN
void cleanup_and_exit(int exit_code
)
536 // returns non-zero if it sprung a top of page trap
538 int top_level_diversion::begin_page()
541 if (page_count
== last_page_count
543 : (done_end_macro
&& (seen_last_page_ejector
|| began_page_in_end_macro
)))
546 began_page_in_end_macro
= 1;
551 if (have_next_page_number
) {
552 page_number
= next_page_number
;
553 have_next_page_number
= 0;
555 else if (!first_page_begun
)
559 // spring the top of page trap if there is one
560 vunits next_trap_pos
;
561 vertical_position
= -vresolution
;
562 trap
*next_trap
= find_next_trap(&next_trap_pos
);
563 vertical_position
= V0
;
564 high_water_mark
= V0
;
565 first_page_begun
= 1;
567 the_output
->begin_page(page_number
, page_length
);
568 nl_reg_contents
= vertical_position
.to_units();
569 if (vertical_position_traps_flag
&& next_trap
!= 0 && next_trap_pos
== V0
) {
570 truncated_space
= V0
;
571 spring_trap(next_trap
->nm
);
578 void continue_page_eject()
580 if (topdiv
->get_ejecting()) {
581 if (curdiv
!= topdiv
)
582 error("can't continue page ejection because of current diversion");
583 else if (!vertical_position_traps_flag
)
584 error("can't continue page ejection because vertical position traps disabled");
587 topdiv
->space(topdiv
->get_page_length(), 1);
592 void top_level_diversion::set_next_page_number(int n
)
595 have_next_page_number
= 1;
598 int top_level_diversion::get_next_page_number()
600 return have_next_page_number
? next_page_number
: page_number
+ 1;
603 void top_level_diversion::set_page_length(vunits n
)
608 diversion::~diversion()
615 if (!has_arg() || !get_hunits(&n
, 'v', topdiv
->page_offset
))
616 n
= topdiv
->prev_page_offset
;
617 topdiv
->prev_page_offset
= topdiv
->page_offset
;
618 topdiv
->page_offset
= n
;
625 if (has_arg() && get_vunits(&n
, 'v', topdiv
->get_page_length()))
626 topdiv
->set_page_length(n
);
628 topdiv
->set_page_length(11*units_per_inch
);
635 if (get_vunits(&n
, 'v')) {
636 symbol s
= get_name();
638 topdiv
->remove_trap_at(n
);
640 topdiv
->add_trap(s
, n
);
649 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
651 while (!tok
.newline() && !tok
.eof())
653 if (curdiv
== topdiv
) {
654 if (!topdiv
->first_page_begun
) {
657 topdiv
->set_next_page_number(n
);
658 if (got_arg
|| !topdiv
->no_space_mode
)
659 topdiv
->begin_page();
661 else if (topdiv
->no_space_mode
&& !got_arg
)
662 topdiv
->begin_page();
677 This code makes groff do the same. */
680 topdiv
->begin_page();
682 topdiv
->set_next_page_number(n
);
683 topdiv
->set_ejecting();
691 topdiv
->set_next_page_number(n
);
692 if (!(topdiv
->no_space_mode
&& !got_arg
))
693 topdiv
->set_ejecting();
701 if (curdiv
== topdiv
)
702 topdiv
->no_space_mode
= 1;
706 void restore_spacing()
708 if (curdiv
== topdiv
)
709 topdiv
->no_space_mode
= 0;
713 /* It is necessary to generate a break before before reading the argument,
714 because otherwise arguments using | will be wrong. But if we just
715 generate a break as usual, then the line forced out may spring a trap
716 and thus push a macro onto the input stack before we have had a chance
717 to read the argument to the sp request. We resolve this dilemma by
718 setting, before generating the break, a flag which will postpone the
719 actual pushing of the macro associated with the trap sprung by the
720 outputting of the line forced out by the break till after we have read
721 the argument to the request. If the break did cause a trap to be
722 sprung, then we don't actually do the space. */
730 if (!has_arg() || !get_vunits(&n
, 'v'))
731 n
= curenv
->get_vertical_spacing();
732 while (!tok
.newline() && !tok
.eof())
734 if (!unpostpone_traps())
737 // The line might have had line spacing that was truncated.
738 truncated_space
+= n
;
745 if (!trap_sprung_flag
)
746 curdiv
->space(curenv
->get_vertical_spacing());
748 truncated_space
+= curenv
->get_vertical_spacing();
751 /* need_space might spring a trap and so we must be careful that the
752 BEGIN_TRAP token is not skipped over. */
757 if (!has_arg() || !get_vunits(&n
, 'v'))
758 n
= curenv
->get_vertical_spacing();
759 while (!tok
.newline() && !tok
.eof())
768 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
769 topdiv
->set_next_page_number(n
);
775 void save_vertical_space()
778 if (get_vunits(&x
, 'v')) {
779 if (curdiv
->distance_to_next_trap() > x
)
787 void output_saved_vertical_space()
789 while (!tok
.newline() && !tok
.eof())
791 if (saved_space
> V0
)
792 curdiv
->space(saved_space
, 1);
799 while (!tok
.newline() && !tok
.eof())
808 void macro_diversion::set_diversion_trap(symbol s
, vunits n
)
811 diversion_trap_pos
= n
;
814 void macro_diversion::clear_diversion_trap()
816 diversion_trap
= NULL_SYMBOL
;
819 void top_level_diversion::set_diversion_trap(symbol
, vunits
)
821 error("can't set diversion trap when no current diversion");
824 void top_level_diversion::clear_diversion_trap()
826 error("can't set diversion trap when no current diversion");
829 void diversion_trap()
832 if (has_arg() && get_vunits(&n
, 'v')) {
833 symbol s
= get_name();
835 curdiv
->set_diversion_trap(s
, n
);
837 curdiv
->clear_diversion_trap();
840 curdiv
->clear_diversion_trap();
846 symbol s
= get_name(1);
849 if (has_arg() && get_vunits(&x
, 'v'))
850 topdiv
->change_trap(s
, x
);
852 topdiv
->remove_trap(s
);
859 topdiv
->print_traps();
865 symbol s
= get_name();
867 curdiv
->marked_place
= curdiv
->get_vertical_position();
868 else if (curdiv
== topdiv
)
869 set_number_reg(s
, nl_reg_contents
);
871 set_number_reg(s
, curdiv
->get_vertical_position().to_units());
875 // This is truly bizarre. It is documented in the SQ manual.
877 void return_request()
879 vunits dist
= curdiv
->marked_place
- curdiv
->get_vertical_position();
881 if (tok
.ch() == '-') {
884 if (get_vunits(&x
, 'v'))
889 if (get_vunits(&x
, 'v'))
890 dist
= x
>= V0
? x
- curdiv
->get_vertical_position() : V0
;
898 void vertical_position_traps()
901 if (has_arg() && get_integer(&n
))
902 vertical_position_traps_flag
= (n
!= 0);
904 vertical_position_traps_flag
= 1;
908 class page_offset_reg
: public reg
{
910 int get_value(units
*);
911 const char *get_string();
914 int page_offset_reg::get_value(units
*res
)
916 *res
= topdiv
->get_page_offset().to_units();
920 const char *page_offset_reg::get_string()
922 return itoa(topdiv
->get_page_offset().to_units());
925 class page_length_reg
: public reg
{
927 int get_value(units
*);
928 const char *get_string();
931 int page_length_reg::get_value(units
*res
)
933 *res
= topdiv
->get_page_length().to_units();
937 const char *page_length_reg::get_string()
939 return itoa(topdiv
->get_page_length().to_units());
942 class vertical_position_reg
: public reg
{
944 int get_value(units
*);
945 const char *get_string();
948 int vertical_position_reg::get_value(units
*res
)
950 if (curdiv
== topdiv
&& !topdiv
->first_page_begun
)
953 *res
= curdiv
->get_vertical_position().to_units();
957 const char *vertical_position_reg::get_string()
959 if (curdiv
== topdiv
&& !topdiv
->first_page_begun
)
962 return itoa(curdiv
->get_vertical_position().to_units());
965 class high_water_mark_reg
: public reg
{
967 int get_value(units
*);
968 const char *get_string();
971 int high_water_mark_reg::get_value(units
*res
)
973 *res
= curdiv
->get_high_water_mark().to_units();
977 const char *high_water_mark_reg::get_string()
979 return itoa(curdiv
->get_high_water_mark().to_units());
982 class distance_to_next_trap_reg
: public reg
{
984 int get_value(units
*);
985 const char *get_string();
988 int distance_to_next_trap_reg::get_value(units
*res
)
990 *res
= curdiv
->distance_to_next_trap().to_units();
994 const char *distance_to_next_trap_reg::get_string()
996 return itoa(curdiv
->distance_to_next_trap().to_units());
999 class diversion_name_reg
: public reg
{
1001 const char *get_string();
1004 const char *diversion_name_reg::get_string()
1006 return curdiv
->get_diversion_name();
1009 class page_number_reg
: public general_reg
{
1012 int get_value(units
*);
1013 void set_value(units
);
1016 page_number_reg::page_number_reg()
1020 void page_number_reg::set_value(units n
)
1022 topdiv
->set_page_number(n
);
1025 int page_number_reg::get_value(units
*res
)
1027 *res
= topdiv
->get_page_number();
1031 class next_page_number_reg
: public reg
{
1033 const char *get_string();
1036 const char *next_page_number_reg::get_string()
1038 return itoa(topdiv
->get_next_page_number());
1041 class page_ejecting_reg
: public reg
{
1043 const char *get_string();
1046 const char *page_ejecting_reg::get_string()
1048 return itoa(topdiv
->get_ejecting());
1051 class constant_vunits_reg
: public reg
{
1054 constant_vunits_reg(vunits
*);
1055 const char *get_string();
1058 constant_vunits_reg::constant_vunits_reg(vunits
*q
) : p(q
)
1062 const char *constant_vunits_reg::get_string()
1064 return itoa(p
->to_units());
1067 void init_div_requests()
1069 init_request("wh", when_request
);
1070 init_request("ch", change_trap
);
1071 init_request("pl", page_length
);
1072 init_request("po", page_offset
);
1073 init_request("rs", restore_spacing
);
1074 init_request("ns", no_space
);
1075 init_request("sp", space_request
);
1076 init_request("di", divert
);
1077 init_request("da", divert_append
);
1078 init_request("bp", begin_page
);
1079 init_request("ne", need_space
);
1080 init_request("pn", page_number
);
1081 init_request("dt", diversion_trap
);
1082 init_request("rt", return_request
);
1083 init_request("mk", mark
);
1084 init_request("sv", save_vertical_space
);
1085 init_request("os", output_saved_vertical_space
);
1086 init_request("fl", flush_output
);
1087 init_request("vpt", vertical_position_traps
);
1088 init_request("ptr", print_traps
);
1089 number_reg_dictionary
.define(".a",
1090 new constant_int_reg(&last_post_line_extra_space
));
1091 number_reg_dictionary
.define(".z", new diversion_name_reg
);
1092 number_reg_dictionary
.define(".o", new page_offset_reg
);
1093 number_reg_dictionary
.define(".p", new page_length_reg
);
1094 number_reg_dictionary
.define(".d", new vertical_position_reg
);
1095 number_reg_dictionary
.define(".h", new high_water_mark_reg
);
1096 number_reg_dictionary
.define(".t", new distance_to_next_trap_reg
);
1097 number_reg_dictionary
.define("dl", new variable_reg(&dl_reg_contents
));
1098 number_reg_dictionary
.define("dn", new variable_reg(&dn_reg_contents
));
1099 number_reg_dictionary
.define("nl", new variable_reg(&nl_reg_contents
));
1100 number_reg_dictionary
.define(".vpt",
1101 new constant_int_reg(&vertical_position_traps_flag
));
1102 number_reg_dictionary
.define("%", new page_number_reg
);
1103 number_reg_dictionary
.define(".pn", new next_page_number_reg
);
1104 number_reg_dictionary
.define(".trunc",
1105 new constant_vunits_reg(&truncated_space
));
1106 number_reg_dictionary
.define(".ne",
1107 new constant_vunits_reg(&needed_space
));
1108 number_reg_dictionary
.define(".pe", new page_ejecting_reg
);