2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #include "dictionary.h"
36 int exit_started
= 0; // the exit process has started
37 int done_end_macro
= 0; // the end macro (if any) has finished
38 int seen_last_page_ejector
= 0; // seen the LAST_PAGE_EJECTOR cookie
39 int last_page_number
= 0; // if > 0, the number of the last page
41 static int began_page_in_end_macro
= 0; // a new page was begun during the end macro
43 static int last_post_line_extra_space
= 0; // needed for \n(.a
44 static int nl_reg_contents
= -1;
45 static int dl_reg_contents
= 0;
46 static int dn_reg_contents
= 0;
47 static int vertical_position_traps_flag
= 1;
48 static vunits truncated_space
;
49 static vunits needed_space
;
51 diversion::diversion(symbol s
)
52 : prev(0), nm(s
), vertical_position(V0
), high_water_mark(V0
),
53 no_space_mode(0), marked_place(V0
)
57 struct vertical_size
{
58 vunits pre_extra
, post_extra
, pre
, post
;
59 vertical_size(vunits vs
, vunits post_vs
);
62 vertical_size::vertical_size(vunits vs
, vunits post_vs
)
63 : pre_extra(V0
), post_extra(V0
), pre(vs
), post(post_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
, int boxing
)
96 symbol nm
= get_name();
100 curenv
->line
= curdiv
->saved_line
;
101 curenv
->width_total
= curdiv
->saved_width_total
;
102 curenv
->space_total
= curdiv
->saved_space_total
;
103 curenv
->saved_indent
= curdiv
->saved_saved_indent
;
104 curenv
->target_text_length
= curdiv
->saved_target_text_length
;
105 curenv
->prev_line_interrupted
= curdiv
->saved_prev_line_interrupted
;
107 diversion
*temp
= curdiv
;
108 curdiv
= curdiv
->prev
;
112 warning(WARN_DI
, "diversion stack underflow");
115 macro_diversion
*md
= new macro_diversion(nm
, append
);
119 curdiv
->saved_line
= curenv
->line
;
120 curdiv
->saved_width_total
= curenv
->width_total
;
121 curdiv
->saved_space_total
= curenv
->space_total
;
122 curdiv
->saved_saved_indent
= curenv
->saved_indent
;
123 curdiv
->saved_target_text_length
= curenv
->target_text_length
;
124 curdiv
->saved_prev_line_interrupted
= curenv
->prev_line_interrupted
;
126 curenv
->start_line();
152 void diversion::need(vunits n
)
154 vunits d
= distance_to_next_trap();
156 truncated_space
= -d
;
162 macro_diversion::macro_diversion(symbol s
, int append
)
163 : diversion(s
), max_width(H0
)
167 /* We don't allow recursive appends eg:
173 This causes an infinite loop in troff anyway.
174 This is because the user could do
178 in the diversion, and this would mess things up royally,
179 since there would be two things appending to the same
181 To make it work, we would have to copy the _contents_
182 of the macro into which we were diverting; this doesn't
183 strike me as worthwhile.
191 will work and will make `a' contain two copies of what it contained
192 before; in troff, `a' would contain nothing. */
194 = (request_or_macro
*)request_dictionary
.remove(s
);
195 if (!rm
|| (mac
= rm
->to_macro()) == 0)
201 // We can now catch the situation described above by comparing
202 // the length of the charlist in the macro_header with the length
203 // stored in the macro. When we detect this, we copy the contents.
207 = (request_or_macro
*)request_dictionary
.lookup(s
);
209 macro
*m
= rm
->to_macro();
216 macro_diversion::~macro_diversion()
218 request_or_macro
*rm
= (request_or_macro
*)request_dictionary
.lookup(nm
);
219 macro
*m
= rm
? rm
->to_macro() : 0;
225 request_dictionary
.define(nm
, mac
);
227 dl_reg_contents
= max_width
.to_units();
228 dn_reg_contents
= vertical_position
.to_units();
231 vunits
macro_diversion::distance_to_next_trap()
233 if (!diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
)
234 return diversion_trap_pos
- vertical_position
;
236 // Substract vresolution so that vunits::vunits does not overflow.
237 return vunits(INT_MAX
- vresolution
);
240 void macro_diversion::transparent_output(unsigned char c
)
245 void macro_diversion::transparent_output(node
*n
)
250 void macro_diversion::output(node
*nd
, int retain_size
,
251 vunits vs
, vunits post_vs
, hunits width
)
254 vertical_size
v(vs
, post_vs
);
256 nd
->set_vertical_size(&v
);
259 if (temp
->interpret(mac
)) {
264 temp
->freeze_space();
269 last_post_line_extra_space
= v
.post_extra
.to_units();
274 if (width
> max_width
)
276 vunits x
= v
.pre
+ v
.pre_extra
+ v
.post
+ v
.post_extra
;
277 if (vertical_position_traps_flag
278 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
279 && diversion_trap_pos
<= vertical_position
+ x
) {
280 vunits trunc
= vertical_position
+ x
- diversion_trap_pos
;
285 truncated_space
= trunc
;
286 spring_trap(diversion_trap
);
288 mac
->append(new vertical_size_node(-v
.pre
));
289 mac
->append(new vertical_size_node(v
.post
));
291 vertical_position
+= x
;
292 if (vertical_position
- v
.post
> high_water_mark
)
293 high_water_mark
= vertical_position
- v
.post
;
296 void macro_diversion::space(vunits n
, int)
298 if (vertical_position_traps_flag
299 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
300 && diversion_trap_pos
<= vertical_position
+ n
) {
301 truncated_space
= vertical_position
+ n
- diversion_trap_pos
;
302 n
= diversion_trap_pos
- vertical_position
;
303 spring_trap(diversion_trap
);
305 else if (n
+ vertical_position
< V0
)
306 n
= -vertical_position
;
307 mac
->append(new diverted_space_node(n
));
308 vertical_position
+= n
;
311 void macro_diversion::copy_file(const char *filename
)
313 mac
->append(new diverted_copy_file_node(filename
));
316 top_level_diversion::top_level_diversion()
317 : page_number(0), page_count(0), last_page_count(-1),
318 page_length(units_per_inch
*11),
319 prev_page_offset(units_per_inch
), page_offset(units_per_inch
),
320 page_trap_list(0), have_next_page_number(0),
321 ejecting_page(0), before_first_page(1)
325 // find the next trap after pos
327 trap
*top_level_diversion::find_next_trap(vunits
*next_trap_pos
)
330 for (trap
*pt
= page_trap_list
; pt
!= 0; pt
= pt
->next
)
331 if (!pt
->nm
.is_null()) {
332 if (pt
->position
>= V0
) {
333 if (pt
->position
> vertical_position
334 && pt
->position
< page_length
335 && (next_trap
== 0 || pt
->position
< *next_trap_pos
)) {
337 *next_trap_pos
= pt
->position
;
341 vunits pos
= pt
->position
;
343 if (pos
> 0 && pos
> vertical_position
&& (next_trap
== 0 || pos
< *next_trap_pos
)) {
345 *next_trap_pos
= pos
;
352 vunits
top_level_diversion::distance_to_next_trap()
355 if (!find_next_trap(&d
))
356 return page_length
- vertical_position
;
358 return d
- vertical_position
;
361 void top_level_diversion::output(node
*nd
, int retain_size
,
362 vunits vs
, vunits post_vs
, hunits width
)
365 vunits next_trap_pos
;
366 trap
*next_trap
= find_next_trap(&next_trap_pos
);
367 if (before_first_page
&& begin_page())
368 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
369 vertical_size
v(vs
, post_vs
);
370 for (node
*tem
= nd
; tem
!= 0; tem
= tem
->next
)
371 tem
->set_vertical_size(&v
);
372 last_post_line_extra_space
= v
.post_extra
.to_units();
377 vertical_position
+= v
.pre
;
378 vertical_position
+= v
.pre_extra
;
379 the_output
->print_line(page_offset
, vertical_position
, nd
,
380 v
.pre
+ v
.pre_extra
, v
.post_extra
, width
);
381 vertical_position
+= v
.post_extra
;
382 if (vertical_position
> high_water_mark
)
383 high_water_mark
= vertical_position
;
384 if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
386 else if (vertical_position_traps_flag
387 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
388 nl_reg_contents
= vertical_position
.to_units();
389 truncated_space
= v
.post
;
390 spring_trap(next_trap
->nm
);
392 else if (v
.post
> V0
) {
393 vertical_position
+= v
.post
;
394 if (vertical_position_traps_flag
395 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
396 truncated_space
= vertical_position
- next_trap_pos
;
397 vertical_position
= next_trap_pos
;
398 nl_reg_contents
= vertical_position
.to_units();
399 spring_trap(next_trap
->nm
);
401 else if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
404 nl_reg_contents
= vertical_position
.to_units();
407 nl_reg_contents
= vertical_position
.to_units();
410 void top_level_diversion::transparent_output(unsigned char c
)
412 if (before_first_page
&& begin_page())
413 // This can only happen with the .output request.
414 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
415 const char *s
= asciify(c
);
417 the_output
->transparent_char(*s
++);
420 void top_level_diversion::transparent_output(node
* /*n*/)
422 error("can't transparently output node at top level");
425 void top_level_diversion::copy_file(const char *filename
)
427 if (before_first_page
&& begin_page())
428 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
429 the_output
->copy_file(page_offset
, vertical_position
, filename
);
432 void top_level_diversion::space(vunits n
, int forced
)
440 if (before_first_page
) {
444 vunits next_trap_pos
;
445 trap
*next_trap
= find_next_trap(&next_trap_pos
);
446 vunits y
= vertical_position
+ n
;
447 if (vertical_position_traps_flag
&& next_trap
!= 0 && y
>= next_trap_pos
) {
448 vertical_position
= next_trap_pos
;
449 nl_reg_contents
= vertical_position
.to_units();
450 truncated_space
= y
- vertical_position
;
451 spring_trap(next_trap
->nm
);
454 vertical_position
= V0
;
455 nl_reg_contents
= vertical_position
.to_units();
457 else if (vertical_position_traps_flag
&& y
>= page_length
&& n
>= V0
)
458 begin_page(y
- page_length
);
460 vertical_position
= y
;
461 nl_reg_contents
= vertical_position
.to_units();
465 trap::trap(symbol s
, vunits n
, trap
*p
)
466 : next(p
), position(n
), nm(s
)
470 void top_level_diversion::add_trap(symbol nm
, vunits pos
)
472 trap
*first_free_slot
= 0;
474 for (p
= &page_trap_list
; *p
; p
= &(*p
)->next
) {
475 if ((*p
)->nm
.is_null()) {
476 if (first_free_slot
== 0)
477 first_free_slot
= *p
;
479 else if ((*p
)->position
== pos
) {
484 if (first_free_slot
) {
485 first_free_slot
->nm
= nm
;
486 first_free_slot
->position
= pos
;
489 *p
= new trap(nm
, pos
, 0);
492 void top_level_diversion::remove_trap(symbol nm
)
494 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
501 void top_level_diversion::remove_trap_at(vunits pos
)
503 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
504 if (p
->position
== pos
) {
510 void top_level_diversion::change_trap(symbol nm
, vunits pos
)
512 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
519 void top_level_diversion::print_traps()
521 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
523 fprintf(stderr
, " empty\n");
525 fprintf(stderr
, "%s\t%d\n", p
->nm
.contents(), p
->position
.to_units());
529 void end_diversions()
531 while (curdiv
!= topdiv
) {
532 error("automatically ending diversion `%1' on exit",
533 curdiv
->nm
.contents());
534 diversion
*tem
= curdiv
;
535 curdiv
= curdiv
->prev
;
540 void cleanup_and_exit(int exit_code
)
543 the_output
->trailer(topdiv
->get_page_length());
549 // Returns non-zero if it sprung a top-of-page trap.
550 // The optional parameter is for the .trunc register.
551 int top_level_diversion::begin_page(vunits n
)
554 if (page_count
== last_page_count
556 : (done_end_macro
&& (seen_last_page_ejector
|| began_page_in_end_macro
)))
559 began_page_in_end_macro
= 1;
561 if (last_page_number
> 0 && page_number
== last_page_number
)
566 if (have_next_page_number
) {
567 page_number
= next_page_number
;
568 have_next_page_number
= 0;
570 else if (before_first_page
== 1)
574 // spring the top of page trap if there is one
575 vunits next_trap_pos
;
576 vertical_position
= -vresolution
;
577 trap
*next_trap
= find_next_trap(&next_trap_pos
);
578 vertical_position
= V0
;
579 high_water_mark
= V0
;
581 // If before_first_page was 2, then the top of page transition was undone
582 // using eg .nr nl 0-1. See nl_reg::set_value.
583 if (before_first_page
!= 2)
584 the_output
->begin_page(page_number
, page_length
);
585 before_first_page
= 0;
586 nl_reg_contents
= vertical_position
.to_units();
587 if (vertical_position_traps_flag
&& next_trap
!= 0 && next_trap_pos
== V0
) {
589 spring_trap(next_trap
->nm
);
596 void continue_page_eject()
598 if (topdiv
->get_ejecting()) {
599 if (curdiv
!= topdiv
)
600 error("can't continue page ejection because of current diversion");
601 else if (!vertical_position_traps_flag
)
602 error("can't continue page ejection because vertical position traps disabled");
605 topdiv
->space(topdiv
->get_page_length(), 1);
610 void top_level_diversion::set_next_page_number(int n
)
613 have_next_page_number
= 1;
616 int top_level_diversion::get_next_page_number()
618 return have_next_page_number
? next_page_number
: page_number
+ 1;
621 void top_level_diversion::set_page_length(vunits n
)
626 diversion::~diversion()
633 // The troff manual says that the default scaling indicator is v,
634 // but it is in fact m: v wouldn't make sense for a horizontally
636 if (!has_arg() || !get_hunits(&n
, 'm', topdiv
->page_offset
))
637 n
= topdiv
->prev_page_offset
;
638 topdiv
->prev_page_offset
= topdiv
->page_offset
;
639 topdiv
->page_offset
= n
;
640 curenv
->add_html_tag(0, ".po", n
.to_units());
647 if (has_arg() && get_vunits(&n
, 'v', topdiv
->get_page_length()))
648 topdiv
->set_page_length(n
);
650 topdiv
->set_page_length(11*units_per_inch
);
657 if (get_vunits(&n
, 'v')) {
658 symbol s
= get_name();
660 topdiv
->remove_trap_at(n
);
662 topdiv
->add_trap(s
, n
);
671 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
673 while (!tok
.newline() && !tok
.eof())
675 if (curdiv
== topdiv
) {
676 if (topdiv
->before_first_page
) {
679 topdiv
->set_next_page_number(n
);
680 if (got_arg
|| !topdiv
->no_space_mode
)
681 topdiv
->begin_page();
683 else if (topdiv
->no_space_mode
&& !got_arg
)
684 topdiv
->begin_page();
699 This code makes groff do the same. */
702 topdiv
->begin_page();
704 topdiv
->set_next_page_number(n
);
705 topdiv
->set_ejecting();
713 topdiv
->set_next_page_number(n
);
714 if (!(topdiv
->no_space_mode
&& !got_arg
))
715 topdiv
->set_ejecting();
723 curdiv
->no_space_mode
= 1;
727 void restore_spacing()
729 curdiv
->no_space_mode
= 0;
733 /* It is necessary to generate a break before before reading the argument,
734 because otherwise arguments using | will be wrong. But if we just
735 generate a break as usual, then the line forced out may spring a trap
736 and thus push a macro onto the input stack before we have had a chance
737 to read the argument to the sp request. We resolve this dilemma by
738 setting, before generating the break, a flag which will postpone the
739 actual pushing of the macro associated with the trap sprung by the
740 outputting of the line forced out by the break till after we have read
741 the argument to the request. If the break did cause a trap to be
742 sprung, then we don't actually do the space. */
750 if (!has_arg() || !get_vunits(&n
, 'v'))
751 n
= curenv
->get_vertical_spacing();
752 while (!tok
.newline() && !tok
.eof())
754 if (!unpostpone_traps() && !curdiv
->no_space_mode
)
757 // The line might have had line spacing that was truncated.
758 truncated_space
+= n
;
759 curenv
->add_html_tag(1, ".sp", n
.to_units());
766 if (!trap_sprung_flag
&& !curdiv
->no_space_mode
) {
767 curdiv
->space(curenv
->get_vertical_spacing());
768 curenv
->add_html_tag(1, ".sp", 1);
771 truncated_space
+= curenv
->get_vertical_spacing();
774 /* need_space might spring a trap and so we must be careful that the
775 BEGIN_TRAP token is not skipped over. */
780 if (!has_arg() || !get_vunits(&n
, 'v'))
781 n
= curenv
->get_vertical_spacing();
782 while (!tok
.newline() && !tok
.eof())
792 // the ps4html register is set if we are using -Tps
793 // to generate images for html
794 reg
*r
= (reg
*)number_reg_dictionary
.lookup("ps4html");
796 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
797 topdiv
->set_next_page_number(n
);
803 void save_vertical_space()
806 if (!has_arg() || !get_vunits(&x
, 'v'))
807 x
= curenv
->get_vertical_spacing();
808 if (curdiv
->distance_to_next_trap() > x
)
815 void output_saved_vertical_space()
817 while (!tok
.newline() && !tok
.eof())
819 if (saved_space
> V0
)
820 curdiv
->space(saved_space
, 1);
827 while (!tok
.newline() && !tok
.eof())
833 curenv
->add_html_tag(1, ".fl");
837 void macro_diversion::set_diversion_trap(symbol s
, vunits n
)
840 diversion_trap_pos
= n
;
843 void macro_diversion::clear_diversion_trap()
845 diversion_trap
= NULL_SYMBOL
;
848 void top_level_diversion::set_diversion_trap(symbol
, vunits
)
850 error("can't set diversion trap when no current diversion");
853 void top_level_diversion::clear_diversion_trap()
855 error("can't set diversion trap when no current diversion");
858 void diversion_trap()
861 if (has_arg() && get_vunits(&n
, 'v')) {
862 symbol s
= get_name();
864 curdiv
->set_diversion_trap(s
, n
);
866 curdiv
->clear_diversion_trap();
869 curdiv
->clear_diversion_trap();
875 symbol s
= get_name(1);
878 if (has_arg() && get_vunits(&x
, 'v'))
879 topdiv
->change_trap(s
, x
);
881 topdiv
->remove_trap(s
);
888 topdiv
->print_traps();
894 symbol s
= get_name();
896 curdiv
->marked_place
= curdiv
->get_vertical_position();
897 else if (curdiv
== topdiv
)
898 set_number_reg(s
, nl_reg_contents
);
900 set_number_reg(s
, curdiv
->get_vertical_position().to_units());
904 // This is truly bizarre. It is documented in the SQ manual.
906 void return_request()
908 vunits dist
= curdiv
->marked_place
- curdiv
->get_vertical_position();
910 if (tok
.ch() == '-') {
913 if (get_vunits(&x
, 'v'))
918 if (get_vunits(&x
, 'v'))
919 dist
= x
>= V0
? x
- curdiv
->get_vertical_position() : V0
;
927 void vertical_position_traps()
930 if (has_arg() && get_integer(&n
))
931 vertical_position_traps_flag
= (n
!= 0);
933 vertical_position_traps_flag
= 1;
937 class page_offset_reg
: public reg
{
939 int get_value(units
*);
940 const char *get_string();
943 int page_offset_reg::get_value(units
*res
)
945 *res
= topdiv
->get_page_offset().to_units();
949 const char *page_offset_reg::get_string()
951 return i_to_a(topdiv
->get_page_offset().to_units());
954 class page_length_reg
: public reg
{
956 int get_value(units
*);
957 const char *get_string();
960 int page_length_reg::get_value(units
*res
)
962 *res
= topdiv
->get_page_length().to_units();
966 const char *page_length_reg::get_string()
968 return i_to_a(topdiv
->get_page_length().to_units());
971 class vertical_position_reg
: public reg
{
973 int get_value(units
*);
974 const char *get_string();
977 int vertical_position_reg::get_value(units
*res
)
979 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
982 *res
= curdiv
->get_vertical_position().to_units();
986 const char *vertical_position_reg::get_string()
988 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
991 return i_to_a(curdiv
->get_vertical_position().to_units());
994 class high_water_mark_reg
: public reg
{
996 int get_value(units
*);
997 const char *get_string();
1000 int high_water_mark_reg::get_value(units
*res
)
1002 *res
= curdiv
->get_high_water_mark().to_units();
1006 const char *high_water_mark_reg::get_string()
1008 return i_to_a(curdiv
->get_high_water_mark().to_units());
1011 class distance_to_next_trap_reg
: public reg
{
1013 int get_value(units
*);
1014 const char *get_string();
1017 int distance_to_next_trap_reg::get_value(units
*res
)
1019 *res
= curdiv
->distance_to_next_trap().to_units();
1023 const char *distance_to_next_trap_reg::get_string()
1025 return i_to_a(curdiv
->distance_to_next_trap().to_units());
1028 class diversion_name_reg
: public reg
{
1030 const char *get_string();
1033 const char *diversion_name_reg::get_string()
1035 return curdiv
->get_diversion_name();
1038 class page_number_reg
: public general_reg
{
1041 int get_value(units
*);
1042 void set_value(units
);
1045 page_number_reg::page_number_reg()
1049 void page_number_reg::set_value(units n
)
1051 topdiv
->set_page_number(n
);
1054 int page_number_reg::get_value(units
*res
)
1056 *res
= topdiv
->get_page_number();
1060 class next_page_number_reg
: public reg
{
1062 const char *get_string();
1065 const char *next_page_number_reg::get_string()
1067 return i_to_a(topdiv
->get_next_page_number());
1070 class page_ejecting_reg
: public reg
{
1072 const char *get_string();
1075 const char *page_ejecting_reg::get_string()
1077 return i_to_a(topdiv
->get_ejecting());
1080 class constant_vunits_reg
: public reg
{
1083 constant_vunits_reg(vunits
*);
1084 const char *get_string();
1087 constant_vunits_reg::constant_vunits_reg(vunits
*q
) : p(q
)
1091 const char *constant_vunits_reg::get_string()
1093 return i_to_a(p
->to_units());
1096 class nl_reg
: public variable_reg
{
1099 void set_value(units
);
1102 nl_reg::nl_reg() : variable_reg(&nl_reg_contents
)
1106 void nl_reg::set_value(units n
)
1108 variable_reg::set_value(n
);
1109 // Setting nl to a negative value when the vertical position in
1110 // the top-level diversion is 0 undoes the top of page transition,
1111 // so that the header macro will be called as if the top of page
1112 // transition hasn't happened. This is used by Larry Wall's
1113 // wrapman program. Setting before_first_page to 2 rather than 1,
1114 // tells top_level_diversion::begin_page not to call
1115 // output_file::begin_page again.
1116 if (n
< 0 && topdiv
->get_vertical_position() == V0
)
1117 topdiv
->before_first_page
= 2;
1120 class no_space_mode_reg
: public reg
{
1122 int get_value(units
*);
1123 const char *get_string();
1126 int no_space_mode_reg::get_value(units
*val
)
1128 *val
= curdiv
->no_space_mode
;
1132 const char *no_space_mode_reg::get_string()
1134 return curdiv
->no_space_mode
? "1" : "0";
1137 void init_div_requests()
1139 init_request("wh", when_request
);
1140 init_request("ch", change_trap
);
1141 init_request("pl", page_length
);
1142 init_request("po", page_offset
);
1143 init_request("rs", restore_spacing
);
1144 init_request("ns", no_space
);
1145 init_request("sp", space_request
);
1146 init_request("di", divert
);
1147 init_request("da", divert_append
);
1148 init_request("box", box
);
1149 init_request("boxa", box_append
);
1150 init_request("bp", begin_page
);
1151 init_request("ne", need_space
);
1152 init_request("pn", page_number
);
1153 init_request("dt", diversion_trap
);
1154 init_request("rt", return_request
);
1155 init_request("mk", mark
);
1156 init_request("sv", save_vertical_space
);
1157 init_request("os", output_saved_vertical_space
);
1158 init_request("fl", flush_output
);
1159 init_request("vpt", vertical_position_traps
);
1160 init_request("ptr", print_traps
);
1161 number_reg_dictionary
.define(".a",
1162 new constant_int_reg(&last_post_line_extra_space
));
1163 number_reg_dictionary
.define(".z", new diversion_name_reg
);
1164 number_reg_dictionary
.define(".o", new page_offset_reg
);
1165 number_reg_dictionary
.define(".p", new page_length_reg
);
1166 number_reg_dictionary
.define(".ns", new no_space_mode_reg
);
1167 number_reg_dictionary
.define(".d", new vertical_position_reg
);
1168 number_reg_dictionary
.define(".h", new high_water_mark_reg
);
1169 number_reg_dictionary
.define(".t", new distance_to_next_trap_reg
);
1170 number_reg_dictionary
.define("dl", new variable_reg(&dl_reg_contents
));
1171 number_reg_dictionary
.define("dn", new variable_reg(&dn_reg_contents
));
1172 number_reg_dictionary
.define("nl", new nl_reg
);
1173 number_reg_dictionary
.define(".vpt",
1174 new constant_int_reg(&vertical_position_traps_flag
));
1175 number_reg_dictionary
.define("%", new page_number_reg
);
1176 number_reg_dictionary
.define(".pn", new next_page_number_reg
);
1177 number_reg_dictionary
.define(".trunc",
1178 new constant_vunits_reg(&truncated_space
));
1179 number_reg_dictionary
.define(".ne",
1180 new constant_vunits_reg(&needed_space
));
1181 number_reg_dictionary
.define(".pe", new page_ejecting_reg
);