3 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
5 * Copyright (C) 1989 - 1992, 2000 - 2002, 2004
6 * Free Software Foundation, Inc.
7 * Written by James Clark (jjc@jclark.com)
9 * This is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2, or (at your option) any later
14 * This is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * You should have received a copy of the GNU General Public License along
20 * with groff; see the file COPYING. If not, write to the Free Software
21 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "troff-config.h"
28 #include "stringclass.h"
30 #include "dictionary.h"
41 int exit_started
= 0; // the exit process has started
42 int done_end_macro
= 0; // the end macro (if any) has finished
43 int seen_last_page_ejector
= 0; // seen the LAST_PAGE_EJECTOR cookie
44 int last_page_number
= 0; // if > 0, the number of the last page
46 static int began_page_in_end_macro
= 0; // a new page was begun during the end macro
48 static int last_post_line_extra_space
= 0; // needed for \n(.a
49 static int nl_reg_contents
= -1;
50 static int dl_reg_contents
= 0;
51 static int dn_reg_contents
= 0;
52 static int vertical_position_traps_flag
= 1;
53 static vunits truncated_space
;
54 static vunits needed_space
;
56 diversion::diversion(symbol s
)
57 : prev(0), nm(s
), vertical_position(V0
), high_water_mark(V0
),
58 any_chars_added(0), no_space_mode(0), needs_push(0), saved_seen_break(0),
59 saved_seen_space(0), saved_seen_eol(0), saved_suppress_next_eol(0),
64 struct vertical_size
{
65 vunits pre_extra
, post_extra
, pre
, post
;
66 vertical_size(vunits vs
, vunits post_vs
);
69 vertical_size::vertical_size(vunits vs
, vunits post_vs
)
70 : pre_extra(V0
), post_extra(V0
), pre(vs
), post(post_vs
)
74 void node::set_vertical_size(vertical_size
*)
78 void extra_size_node::set_vertical_size(vertical_size
*v
)
81 if (-n
> v
->pre_extra
)
84 else if (n
> v
->post_extra
)
88 void vertical_size_node::set_vertical_size(vertical_size
*v
)
96 top_level_diversion
*topdiv
;
100 void do_divert(int append
, int boxing
)
103 symbol nm
= get_name();
106 curenv
->seen_break
= curdiv
->saved_seen_break
;
107 curenv
->seen_space
= curdiv
->saved_seen_space
;
108 curenv
->seen_eol
= curdiv
->saved_seen_eol
;
109 curenv
->suppress_next_eol
= curdiv
->saved_suppress_next_eol
;
111 curenv
->line
= curdiv
->saved_line
;
112 curenv
->width_total
= curdiv
->saved_width_total
;
113 curenv
->space_total
= curdiv
->saved_space_total
;
114 curenv
->saved_indent
= curdiv
->saved_saved_indent
;
115 curenv
->target_text_length
= curdiv
->saved_target_text_length
;
116 curenv
->prev_line_interrupted
= curdiv
->saved_prev_line_interrupted
;
118 diversion
*temp
= curdiv
;
119 curdiv
= curdiv
->prev
;
123 warning(WARN_DI
, "diversion stack underflow");
126 macro_diversion
*md
= new macro_diversion(nm
, append
);
129 curdiv
->saved_seen_break
= curenv
->seen_break
;
130 curdiv
->saved_seen_space
= curenv
->seen_space
;
131 curdiv
->saved_seen_eol
= curenv
->seen_eol
;
132 curdiv
->saved_suppress_next_eol
= curenv
->suppress_next_eol
;
133 curenv
->seen_break
= 0;
134 curenv
->seen_space
= 0;
135 curenv
->seen_eol
= 0;
137 curdiv
->saved_line
= curenv
->line
;
138 curdiv
->saved_width_total
= curenv
->width_total
;
139 curdiv
->saved_space_total
= curenv
->space_total
;
140 curdiv
->saved_saved_indent
= curenv
->saved_indent
;
141 curdiv
->saved_target_text_length
= curenv
->target_text_length
;
142 curdiv
->saved_prev_line_interrupted
= curenv
->prev_line_interrupted
;
144 curenv
->start_line();
170 void diversion::need(vunits n
)
172 vunits d
= distance_to_next_trap();
174 truncated_space
= -d
;
180 macro_diversion::macro_diversion(symbol s
, int append
)
181 : diversion(s
), max_width(H0
)
185 /* We don't allow recursive appends eg:
191 This causes an infinite loop in troff anyway.
192 This is because the user could do
196 in the diversion, and this would mess things up royally,
197 since there would be two things appending to the same
199 To make it work, we would have to copy the _contents_
200 of the macro into which we were diverting; this doesn't
201 strike me as worthwhile.
209 will work and will make `a' contain two copies of what it contained
210 before; in troff, `a' would contain nothing. */
212 = (request_or_macro
*)request_dictionary
.remove(s
);
213 if (!rm
|| (mac
= rm
->to_macro()) == 0)
219 // We can now catch the situation described above by comparing
220 // the length of the charlist in the macro_header with the length
221 // stored in the macro. When we detect this, we copy the contents.
225 = (request_or_macro
*)request_dictionary
.lookup(s
);
227 macro
*m
= rm
->to_macro();
234 macro_diversion::~macro_diversion()
236 request_or_macro
*rm
= (request_or_macro
*)request_dictionary
.lookup(nm
);
237 macro
*m
= rm
? rm
->to_macro() : 0;
243 request_dictionary
.define(nm
, mac
);
245 dl_reg_contents
= max_width
.to_units();
246 dn_reg_contents
= vertical_position
.to_units();
249 vunits
macro_diversion::distance_to_next_trap()
251 if (!diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
)
252 return diversion_trap_pos
- vertical_position
;
254 // Substract vresolution so that vunits::vunits does not overflow.
255 return vunits(INT_MAX
- vresolution
);
258 void macro_diversion::transparent_output(unsigned char c
)
263 void macro_diversion::transparent_output(node
*n
)
268 void macro_diversion::output(node
*nd
, int retain_size
,
269 vunits vs
, vunits post_vs
, hunits width
)
272 vertical_size
v(vs
, post_vs
);
274 nd
->set_vertical_size(&v
);
277 if (temp
->interpret(mac
))
281 temp
->freeze_space();
286 last_post_line_extra_space
= v
.post_extra
.to_units();
291 if (width
> max_width
)
293 vunits x
= v
.pre
+ v
.pre_extra
+ v
.post
+ v
.post_extra
;
294 if (vertical_position_traps_flag
295 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
296 && diversion_trap_pos
<= vertical_position
+ x
) {
297 vunits trunc
= vertical_position
+ x
- diversion_trap_pos
;
302 truncated_space
= trunc
;
303 spring_trap(diversion_trap
);
305 mac
->append(new vertical_size_node(-v
.pre
));
306 mac
->append(new vertical_size_node(v
.post
));
308 vertical_position
+= x
;
309 if (vertical_position
- v
.post
> high_water_mark
)
310 high_water_mark
= vertical_position
- v
.post
;
313 void macro_diversion::space(vunits n
, int)
315 if (vertical_position_traps_flag
316 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
317 && diversion_trap_pos
<= vertical_position
+ n
) {
318 truncated_space
= vertical_position
+ n
- diversion_trap_pos
;
319 n
= diversion_trap_pos
- vertical_position
;
320 spring_trap(diversion_trap
);
322 else if (n
+ vertical_position
< V0
)
323 n
= -vertical_position
;
324 mac
->append(new diverted_space_node(n
));
325 vertical_position
+= n
;
328 void macro_diversion::copy_file(const char *filename
)
330 mac
->append(new diverted_copy_file_node(filename
));
333 top_level_diversion::top_level_diversion()
334 : page_number(0), page_count(0), last_page_count(-1),
335 page_length(units_per_inch
*11),
336 prev_page_offset(units_per_inch
), page_offset(units_per_inch
),
337 page_trap_list(0), have_next_page_number(0),
338 ejecting_page(0), before_first_page(1)
342 // find the next trap after pos
344 trap
*top_level_diversion::find_next_trap(vunits
*next_trap_pos
)
347 for (trap
*pt
= page_trap_list
; pt
!= 0; pt
= pt
->next
)
348 if (!pt
->nm
.is_null()) {
349 if (pt
->position
>= V0
) {
350 if (pt
->position
> vertical_position
351 && pt
->position
< page_length
352 && (next_trap
== 0 || pt
->position
< *next_trap_pos
)) {
354 *next_trap_pos
= pt
->position
;
358 vunits pos
= pt
->position
;
361 && pos
> vertical_position
362 && (next_trap
== 0 || pos
< *next_trap_pos
)) {
364 *next_trap_pos
= pos
;
371 vunits
top_level_diversion::distance_to_next_trap()
374 if (!find_next_trap(&d
))
375 return page_length
- vertical_position
;
377 return d
- vertical_position
;
380 void top_level_diversion::output(node
*nd
, int retain_size
,
381 vunits vs
, vunits post_vs
, hunits width
)
384 vunits next_trap_pos
;
385 trap
*next_trap
= find_next_trap(&next_trap_pos
);
386 if (before_first_page
&& begin_page())
387 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
388 vertical_size
v(vs
, post_vs
);
389 for (node
*tem
= nd
; tem
!= 0; tem
= tem
->next
)
390 tem
->set_vertical_size(&v
);
391 last_post_line_extra_space
= v
.post_extra
.to_units();
396 vertical_position
+= v
.pre
;
397 vertical_position
+= v
.pre_extra
;
398 the_output
->print_line(page_offset
, vertical_position
, nd
,
399 v
.pre
+ v
.pre_extra
, v
.post_extra
, width
);
400 vertical_position
+= v
.post_extra
;
401 if (vertical_position
> high_water_mark
)
402 high_water_mark
= vertical_position
;
403 if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
405 else if (vertical_position_traps_flag
406 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
407 nl_reg_contents
= vertical_position
.to_units();
408 truncated_space
= v
.post
;
409 spring_trap(next_trap
->nm
);
411 else if (v
.post
> V0
) {
412 vertical_position
+= v
.post
;
413 if (vertical_position_traps_flag
414 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
415 truncated_space
= vertical_position
- next_trap_pos
;
416 vertical_position
= next_trap_pos
;
417 nl_reg_contents
= vertical_position
.to_units();
418 spring_trap(next_trap
->nm
);
420 else if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
423 nl_reg_contents
= vertical_position
.to_units();
426 nl_reg_contents
= vertical_position
.to_units();
429 void top_level_diversion::transparent_output(unsigned char c
)
431 if (before_first_page
&& begin_page())
432 // This can only happen with the .output request.
433 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
434 const char *s
= asciify(c
);
436 the_output
->transparent_char(*s
++);
439 void top_level_diversion::transparent_output(node
* /*n*/)
441 error("can't transparently output node at top level");
444 void top_level_diversion::copy_file(const char *filename
)
446 if (before_first_page
&& begin_page())
447 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
448 the_output
->copy_file(page_offset
, vertical_position
, filename
);
451 void top_level_diversion::space(vunits n
, int forced
)
459 if (before_first_page
) {
463 vunits next_trap_pos
;
464 trap
*next_trap
= find_next_trap(&next_trap_pos
);
465 vunits y
= vertical_position
+ n
;
466 if (curenv
->get_vertical_spacing().to_units())
467 curenv
->seen_space
+= n
.to_units()
468 / curenv
->get_vertical_spacing().to_units();
469 if (vertical_position_traps_flag
&& next_trap
!= 0 && y
>= next_trap_pos
) {
470 vertical_position
= next_trap_pos
;
471 nl_reg_contents
= vertical_position
.to_units();
472 truncated_space
= y
- vertical_position
;
473 spring_trap(next_trap
->nm
);
476 vertical_position
= V0
;
477 nl_reg_contents
= vertical_position
.to_units();
479 else if (vertical_position_traps_flag
&& y
>= page_length
&& n
>= V0
)
480 begin_page(y
- page_length
);
482 vertical_position
= y
;
483 nl_reg_contents
= vertical_position
.to_units();
487 trap::trap(symbol s
, vunits n
, trap
*p
)
488 : next(p
), position(n
), nm(s
)
492 void top_level_diversion::add_trap(symbol nam
, vunits pos
)
494 trap
*first_free_slot
= 0;
496 for (p
= &page_trap_list
; *p
; p
= &(*p
)->next
) {
497 if ((*p
)->nm
.is_null()) {
498 if (first_free_slot
== 0)
499 first_free_slot
= *p
;
501 else if ((*p
)->position
== pos
) {
506 if (first_free_slot
) {
507 first_free_slot
->nm
= nam
;
508 first_free_slot
->position
= pos
;
511 *p
= new trap(nam
, pos
, 0);
514 void top_level_diversion::remove_trap(symbol nam
)
516 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
523 void top_level_diversion::remove_trap_at(vunits pos
)
525 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
526 if (p
->position
== pos
) {
532 void top_level_diversion::change_trap(symbol nam
, vunits pos
)
534 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
541 void top_level_diversion::print_traps()
543 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
545 fprintf(stderr
, " empty\n");
547 fprintf(stderr
, "%s\t%d\n", p
->nm
.contents(), p
->position
.to_units());
551 void end_diversions()
553 while (curdiv
!= topdiv
) {
554 error("automatically ending diversion `%1' on exit",
555 curdiv
->nm
.contents());
556 diversion
*tem
= curdiv
;
557 curdiv
= curdiv
->prev
;
562 void cleanup_and_exit(int exit_code
)
565 the_output
->trailer(topdiv
->get_page_length());
568 FLUSH_INPUT_PIPE(STDIN_FILENO
);
572 // Returns non-zero if it sprung a top-of-page trap.
573 // The optional parameter is for the .trunc register.
574 int top_level_diversion::begin_page(vunits n
)
577 if (page_count
== last_page_count
579 : (done_end_macro
&& (seen_last_page_ejector
|| began_page_in_end_macro
)))
582 began_page_in_end_macro
= 1;
584 if (last_page_number
> 0 && page_number
== last_page_number
)
589 if (have_next_page_number
) {
590 page_number
= next_page_number
;
591 have_next_page_number
= 0;
593 else if (before_first_page
== 1)
597 // spring the top of page trap if there is one
598 vunits next_trap_pos
;
599 vertical_position
= -vresolution
;
600 trap
*next_trap
= find_next_trap(&next_trap_pos
);
601 vertical_position
= V0
;
602 high_water_mark
= V0
;
604 // If before_first_page was 2, then the top of page transition was undone
605 // using eg .nr nl 0-1. See nl_reg::set_value.
606 if (before_first_page
!= 2)
607 the_output
->begin_page(page_number
, page_length
);
608 before_first_page
= 0;
609 nl_reg_contents
= vertical_position
.to_units();
610 if (vertical_position_traps_flag
&& next_trap
!= 0 && next_trap_pos
== V0
) {
612 spring_trap(next_trap
->nm
);
619 void continue_page_eject()
621 if (topdiv
->get_ejecting()) {
622 if (curdiv
!= topdiv
)
623 error("can't continue page ejection because of current diversion");
624 else if (!vertical_position_traps_flag
)
625 error("can't continue page ejection because vertical position traps disabled");
628 topdiv
->space(topdiv
->get_page_length(), 1);
633 void top_level_diversion::set_next_page_number(int n
)
636 have_next_page_number
= 1;
639 int top_level_diversion::get_next_page_number()
641 return have_next_page_number
? next_page_number
: page_number
+ 1;
644 void top_level_diversion::set_page_length(vunits n
)
649 diversion::~diversion()
656 // The troff manual says that the default scaling indicator is v,
657 // but it is in fact m: v wouldn't make sense for a horizontally
659 if (!has_arg() || !get_hunits(&n
, 'm', topdiv
->page_offset
))
660 n
= topdiv
->prev_page_offset
;
661 topdiv
->prev_page_offset
= topdiv
->page_offset
;
662 topdiv
->page_offset
= n
;
663 topdiv
->modified_tag
.incl(MTSM_PO
);
670 if (has_arg() && get_vunits(&n
, 'v', topdiv
->get_page_length()))
671 topdiv
->set_page_length(n
);
673 topdiv
->set_page_length(11*units_per_inch
);
680 if (get_vunits(&n
, 'v')) {
681 symbol s
= get_name();
683 topdiv
->remove_trap_at(n
);
685 topdiv
->add_trap(s
, n
);
693 int n
= 0; /* pacify compiler */
694 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
696 while (!tok
.newline() && !tok
.eof())
698 if (curdiv
== topdiv
) {
699 if (topdiv
->before_first_page
) {
702 topdiv
->set_next_page_number(n
);
703 if (got_arg
|| !topdiv
->no_space_mode
)
704 topdiv
->begin_page();
706 else if (topdiv
->no_space_mode
&& !got_arg
)
707 topdiv
->begin_page();
722 This code makes groff do the same. */
725 topdiv
->begin_page();
727 topdiv
->set_next_page_number(n
);
728 topdiv
->set_ejecting();
736 topdiv
->set_next_page_number(n
);
737 if (!(topdiv
->no_space_mode
&& !got_arg
))
738 topdiv
->set_ejecting();
746 curdiv
->no_space_mode
= 1;
750 void restore_spacing()
752 curdiv
->no_space_mode
= 0;
756 /* It is necessary to generate a break before reading the argument,
757 because otherwise arguments using | will be wrong. But if we just
758 generate a break as usual, then the line forced out may spring a trap
759 and thus push a macro onto the input stack before we have had a chance
760 to read the argument to the sp request. We resolve this dilemma by
761 setting, before generating the break, a flag which will postpone the
762 actual pushing of the macro associated with the trap sprung by the
763 outputting of the line forced out by the break till after we have read
764 the argument to the request. If the break did cause a trap to be
765 sprung, then we don't actually do the space. */
773 if (!has_arg() || !get_vunits(&n
, 'v'))
774 n
= curenv
->get_vertical_spacing();
775 while (!tok
.newline() && !tok
.eof())
777 if (!unpostpone_traps() && !curdiv
->no_space_mode
)
780 // The line might have had line spacing that was truncated.
781 truncated_space
+= n
;
789 if (!trap_sprung_flag
&& !curdiv
->no_space_mode
)
790 curdiv
->space(curenv
->get_vertical_spacing());
792 truncated_space
+= curenv
->get_vertical_spacing();
795 /* need_space might spring a trap and so we must be careful that the
796 BEGIN_TRAP token is not skipped over. */
801 if (!has_arg() || !get_vunits(&n
, 'v'))
802 n
= curenv
->get_vertical_spacing();
803 while (!tok
.newline() && !tok
.eof())
813 // the ps4html register is set if we are using -Tps
814 // to generate images for html
815 reg
*r
= (reg
*)number_reg_dictionary
.lookup("ps4html");
817 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
818 topdiv
->set_next_page_number(n
);
824 void save_vertical_space()
827 if (!has_arg() || !get_vunits(&x
, 'v'))
828 x
= curenv
->get_vertical_spacing();
829 if (curdiv
->distance_to_next_trap() > x
)
836 void output_saved_vertical_space()
838 while (!tok
.newline() && !tok
.eof())
840 if (saved_space
> V0
)
841 curdiv
->space(saved_space
, 1);
848 while (!tok
.newline() && !tok
.eof())
857 void macro_diversion::set_diversion_trap(symbol s
, vunits n
)
860 diversion_trap_pos
= n
;
863 void macro_diversion::clear_diversion_trap()
865 diversion_trap
= NULL_SYMBOL
;
868 void top_level_diversion::set_diversion_trap(symbol
, vunits
)
870 error("can't set diversion trap when no current diversion");
873 void top_level_diversion::clear_diversion_trap()
875 error("can't set diversion trap when no current diversion");
878 void diversion_trap()
881 if (has_arg() && get_vunits(&n
, 'v')) {
882 symbol s
= get_name();
884 curdiv
->set_diversion_trap(s
, n
);
886 curdiv
->clear_diversion_trap();
889 curdiv
->clear_diversion_trap();
895 symbol s
= get_name(1);
898 if (has_arg() && get_vunits(&x
, 'v'))
899 topdiv
->change_trap(s
, x
);
901 topdiv
->remove_trap(s
);
908 topdiv
->print_traps();
914 symbol s
= get_name();
916 curdiv
->marked_place
= curdiv
->get_vertical_position();
917 else if (curdiv
== topdiv
)
918 set_number_reg(s
, nl_reg_contents
);
920 set_number_reg(s
, curdiv
->get_vertical_position().to_units());
924 // This is truly bizarre. It is documented in the SQ manual.
926 void return_request()
928 vunits dist
= curdiv
->marked_place
- curdiv
->get_vertical_position();
930 if (tok
.ch() == '-') {
933 if (get_vunits(&x
, 'v'))
938 if (get_vunits(&x
, 'v'))
939 dist
= x
>= V0
? x
- curdiv
->get_vertical_position() : V0
;
947 void vertical_position_traps()
950 if (has_arg() && get_integer(&n
))
951 vertical_position_traps_flag
= (n
!= 0);
953 vertical_position_traps_flag
= 1;
957 class page_offset_reg
961 int get_value(units
*);
962 const char *get_string();
965 int page_offset_reg::get_value(units
*res
)
967 *res
= topdiv
->get_page_offset().to_units();
971 const char *page_offset_reg::get_string()
973 return i_to_a(topdiv
->get_page_offset().to_units());
976 class page_length_reg
980 int get_value(units
*);
981 const char *get_string();
984 int page_length_reg::get_value(units
*res
)
986 *res
= topdiv
->get_page_length().to_units();
990 const char *page_length_reg::get_string()
992 return i_to_a(topdiv
->get_page_length().to_units());
995 class vertical_position_reg
999 int get_value(units
*);
1000 const char *get_string();
1003 int vertical_position_reg::get_value(units
*res
)
1005 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
1008 *res
= curdiv
->get_vertical_position().to_units();
1012 const char *vertical_position_reg::get_string()
1014 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
1017 return i_to_a(curdiv
->get_vertical_position().to_units());
1020 class high_water_mark_reg
1024 int get_value(units
*);
1025 const char *get_string();
1028 int high_water_mark_reg::get_value(units
*res
)
1030 *res
= curdiv
->get_high_water_mark().to_units();
1034 const char *high_water_mark_reg::get_string()
1036 return i_to_a(curdiv
->get_high_water_mark().to_units());
1039 class distance_to_next_trap_reg
1043 int get_value(units
*);
1044 const char *get_string();
1047 int distance_to_next_trap_reg::get_value(units
*res
)
1049 *res
= curdiv
->distance_to_next_trap().to_units();
1053 const char *distance_to_next_trap_reg::get_string()
1055 return i_to_a(curdiv
->distance_to_next_trap().to_units());
1058 class diversion_name_reg
1062 const char *get_string();
1065 const char *diversion_name_reg::get_string()
1067 return curdiv
->get_diversion_name();
1070 class page_number_reg
1071 : public general_reg
1075 int get_value(units
*);
1076 void set_value(units
);
1079 page_number_reg::page_number_reg()
1083 void page_number_reg::set_value(units n
)
1085 topdiv
->set_page_number(n
);
1088 int page_number_reg::get_value(units
*res
)
1090 *res
= topdiv
->get_page_number();
1094 class next_page_number_reg
1098 const char *get_string();
1101 const char *next_page_number_reg::get_string()
1103 return i_to_a(topdiv
->get_next_page_number());
1106 class page_ejecting_reg
1110 const char *get_string();
1113 const char *page_ejecting_reg::get_string()
1115 return i_to_a(topdiv
->get_ejecting());
1118 class constant_vunits_reg
1124 constant_vunits_reg(vunits
*);
1125 const char *get_string();
1128 constant_vunits_reg::constant_vunits_reg(vunits
*q
) : p(q
)
1132 const char *constant_vunits_reg::get_string()
1134 return i_to_a(p
->to_units());
1138 : public variable_reg
1142 void set_value(units
);
1145 nl_reg::nl_reg() : variable_reg(&nl_reg_contents
)
1149 void nl_reg::set_value(units n
)
1151 variable_reg::set_value(n
);
1152 // Setting nl to a negative value when the vertical position in
1153 // the top-level diversion is 0 undoes the top of page transition,
1154 // so that the header macro will be called as if the top of page
1155 // transition hasn't happened. This is used by Larry Wall's
1156 // wrapman program. Setting before_first_page to 2 rather than 1,
1157 // tells top_level_diversion::begin_page not to call
1158 // output_file::begin_page again.
1159 if (n
< 0 && topdiv
->get_vertical_position() == V0
)
1160 topdiv
->before_first_page
= 2;
1163 class no_space_mode_reg
1167 int get_value(units
*);
1168 const char *get_string();
1171 int no_space_mode_reg::get_value(units
*val
)
1173 *val
= curdiv
->no_space_mode
;
1177 const char *no_space_mode_reg::get_string()
1179 return curdiv
->no_space_mode
? "1" : "0";
1182 void init_div_requests()
1184 init_request("box", box
);
1185 init_request("boxa", box_append
);
1186 init_request("bp", begin_page
);
1187 init_request("ch", change_trap
);
1188 init_request("da", divert_append
);
1189 init_request("di", divert
);
1190 init_request("dt", diversion_trap
);
1191 init_request("fl", flush_output
);
1192 init_request("mk", mark
);
1193 init_request("ne", need_space
);
1194 init_request("ns", no_space
);
1195 init_request("os", output_saved_vertical_space
);
1196 init_request("pl", page_length
);
1197 init_request("pn", page_number
);
1198 init_request("po", page_offset
);
1199 init_request("ptr", print_traps
);
1200 init_request("rs", restore_spacing
);
1201 init_request("rt", return_request
);
1202 init_request("sp", space_request
);
1203 init_request("sv", save_vertical_space
);
1204 init_request("vpt", vertical_position_traps
);
1205 init_request("wh", when_request
);
1206 number_reg_dictionary
.define(".a",
1207 new constant_int_reg(&last_post_line_extra_space
));
1208 number_reg_dictionary
.define(".d", new vertical_position_reg
);
1209 number_reg_dictionary
.define(".h", new high_water_mark_reg
);
1210 number_reg_dictionary
.define(".ne",
1211 new constant_vunits_reg(&needed_space
));
1212 number_reg_dictionary
.define(".ns", new no_space_mode_reg
);
1213 number_reg_dictionary
.define(".o", new page_offset_reg
);
1214 number_reg_dictionary
.define(".p", new page_length_reg
);
1215 number_reg_dictionary
.define(".pe", new page_ejecting_reg
);
1216 number_reg_dictionary
.define(".pn", new next_page_number_reg
);
1217 number_reg_dictionary
.define(".t", new distance_to_next_trap_reg
);
1218 number_reg_dictionary
.define(".trunc",
1219 new constant_vunits_reg(&truncated_space
));
1220 number_reg_dictionary
.define(".vpt",
1221 new constant_int_reg(&vertical_position_traps_flag
));
1222 number_reg_dictionary
.define(".z", new diversion_name_reg
);
1223 number_reg_dictionary
.define("dl", new variable_reg(&dl_reg_contents
));
1224 number_reg_dictionary
.define("dn", new variable_reg(&dn_reg_contents
));
1225 number_reg_dictionary
.define("nl", new nl_reg
);
1226 number_reg_dictionary
.define("%", new page_number_reg
);