2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2004
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. */
26 #include "dictionary.h"
37 int exit_started
= 0; // the exit process has started
38 int done_end_macro
= 0; // the end macro (if any) has finished
39 int seen_last_page_ejector
= 0; // seen the LAST_PAGE_EJECTOR cookie
40 int last_page_number
= 0; // if > 0, the number of the last page
42 static int began_page_in_end_macro
= 0; // a new page was begun during the end macro
44 static int last_post_line_extra_space
= 0; // needed for \n(.a
45 static int nl_reg_contents
= -1;
46 static int dl_reg_contents
= 0;
47 static int dn_reg_contents
= 0;
48 static int vertical_position_traps_flag
= 1;
49 static vunits truncated_space
;
50 static vunits needed_space
;
52 diversion::diversion(symbol s
)
53 : prev(0), nm(s
), vertical_position(V0
), high_water_mark(V0
),
54 no_space_mode(0), marked_place(V0
)
58 struct vertical_size
{
59 vunits pre_extra
, post_extra
, pre
, post
;
60 vertical_size(vunits vs
, vunits post_vs
);
63 vertical_size::vertical_size(vunits vs
, vunits post_vs
)
64 : pre_extra(V0
), post_extra(V0
), pre(vs
), post(post_vs
)
68 void node::set_vertical_size(vertical_size
*)
72 void extra_size_node::set_vertical_size(vertical_size
*v
)
75 if (-n
> v
->pre_extra
)
78 else if (n
> v
->post_extra
)
82 void vertical_size_node::set_vertical_size(vertical_size
*v
)
90 top_level_diversion
*topdiv
;
94 void do_divert(int append
, int boxing
)
97 symbol nm
= get_name();
101 curenv
->line
= curdiv
->saved_line
;
102 curenv
->width_total
= curdiv
->saved_width_total
;
103 curenv
->space_total
= curdiv
->saved_space_total
;
104 curenv
->saved_indent
= curdiv
->saved_saved_indent
;
105 curenv
->target_text_length
= curdiv
->saved_target_text_length
;
106 curenv
->prev_line_interrupted
= curdiv
->saved_prev_line_interrupted
;
108 diversion
*temp
= curdiv
;
109 curdiv
= curdiv
->prev
;
113 warning(WARN_DI
, "diversion stack underflow");
116 macro_diversion
*md
= new macro_diversion(nm
, append
);
120 curdiv
->saved_line
= curenv
->line
;
121 curdiv
->saved_width_total
= curenv
->width_total
;
122 curdiv
->saved_space_total
= curenv
->space_total
;
123 curdiv
->saved_saved_indent
= curenv
->saved_indent
;
124 curdiv
->saved_target_text_length
= curenv
->target_text_length
;
125 curdiv
->saved_prev_line_interrupted
= curenv
->prev_line_interrupted
;
127 curenv
->start_line();
153 void diversion::need(vunits n
)
155 vunits d
= distance_to_next_trap();
157 truncated_space
= -d
;
163 macro_diversion::macro_diversion(symbol s
, int append
)
164 : diversion(s
), max_width(H0
)
168 /* We don't allow recursive appends eg:
174 This causes an infinite loop in troff anyway.
175 This is because the user could do
179 in the diversion, and this would mess things up royally,
180 since there would be two things appending to the same
182 To make it work, we would have to copy the _contents_
183 of the macro into which we were diverting; this doesn't
184 strike me as worthwhile.
192 will work and will make `a' contain two copies of what it contained
193 before; in troff, `a' would contain nothing. */
195 = (request_or_macro
*)request_dictionary
.remove(s
);
196 if (!rm
|| (mac
= rm
->to_macro()) == 0)
202 // We can now catch the situation described above by comparing
203 // the length of the charlist in the macro_header with the length
204 // stored in the macro. When we detect this, we copy the contents.
208 = (request_or_macro
*)request_dictionary
.lookup(s
);
210 macro
*m
= rm
->to_macro();
217 macro_diversion::~macro_diversion()
219 request_or_macro
*rm
= (request_or_macro
*)request_dictionary
.lookup(nm
);
220 macro
*m
= rm
? rm
->to_macro() : 0;
226 request_dictionary
.define(nm
, mac
);
228 dl_reg_contents
= max_width
.to_units();
229 dn_reg_contents
= vertical_position
.to_units();
232 vunits
macro_diversion::distance_to_next_trap()
234 if (!diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
)
235 return diversion_trap_pos
- vertical_position
;
237 // Substract vresolution so that vunits::vunits does not overflow.
238 return vunits(INT_MAX
- vresolution
);
241 void macro_diversion::transparent_output(unsigned char c
)
246 void macro_diversion::transparent_output(node
*n
)
251 void macro_diversion::output(node
*nd
, int retain_size
,
252 vunits vs
, vunits post_vs
, hunits width
)
255 vertical_size
v(vs
, post_vs
);
257 nd
->set_vertical_size(&v
);
260 if (temp
->interpret(mac
)) {
265 temp
->freeze_space();
270 last_post_line_extra_space
= v
.post_extra
.to_units();
275 if (width
> max_width
)
277 vunits x
= v
.pre
+ v
.pre_extra
+ v
.post
+ v
.post_extra
;
278 if (vertical_position_traps_flag
279 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
280 && diversion_trap_pos
<= vertical_position
+ x
) {
281 vunits trunc
= vertical_position
+ x
- diversion_trap_pos
;
286 truncated_space
= trunc
;
287 spring_trap(diversion_trap
);
289 mac
->append(new vertical_size_node(-v
.pre
));
290 mac
->append(new vertical_size_node(v
.post
));
292 vertical_position
+= x
;
293 if (vertical_position
- v
.post
> high_water_mark
)
294 high_water_mark
= vertical_position
- v
.post
;
297 void macro_diversion::space(vunits n
, int)
299 if (vertical_position_traps_flag
300 && !diversion_trap
.is_null() && diversion_trap_pos
> vertical_position
301 && diversion_trap_pos
<= vertical_position
+ n
) {
302 truncated_space
= vertical_position
+ n
- diversion_trap_pos
;
303 n
= diversion_trap_pos
- vertical_position
;
304 spring_trap(diversion_trap
);
306 else if (n
+ vertical_position
< V0
)
307 n
= -vertical_position
;
308 mac
->append(new diverted_space_node(n
));
309 vertical_position
+= n
;
312 void macro_diversion::copy_file(const char *filename
)
314 mac
->append(new diverted_copy_file_node(filename
));
317 top_level_diversion::top_level_diversion()
318 : page_number(0), page_count(0), last_page_count(-1),
319 page_length(units_per_inch
*11),
320 prev_page_offset(units_per_inch
), page_offset(units_per_inch
),
321 page_trap_list(0), have_next_page_number(0),
322 ejecting_page(0), before_first_page(1)
326 // find the next trap after pos
328 trap
*top_level_diversion::find_next_trap(vunits
*next_trap_pos
)
331 for (trap
*pt
= page_trap_list
; pt
!= 0; pt
= pt
->next
)
332 if (!pt
->nm
.is_null()) {
333 if (pt
->position
>= V0
) {
334 if (pt
->position
> vertical_position
335 && pt
->position
< page_length
336 && (next_trap
== 0 || pt
->position
< *next_trap_pos
)) {
338 *next_trap_pos
= pt
->position
;
342 vunits pos
= pt
->position
;
344 if (pos
> 0 && pos
> vertical_position
&& (next_trap
== 0 || pos
< *next_trap_pos
)) {
346 *next_trap_pos
= pos
;
353 vunits
top_level_diversion::distance_to_next_trap()
356 if (!find_next_trap(&d
))
357 return page_length
- vertical_position
;
359 return d
- vertical_position
;
362 void top_level_diversion::output(node
*nd
, int retain_size
,
363 vunits vs
, vunits post_vs
, hunits width
)
366 vunits next_trap_pos
;
367 trap
*next_trap
= find_next_trap(&next_trap_pos
);
368 if (before_first_page
&& begin_page())
369 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
370 vertical_size
v(vs
, post_vs
);
371 for (node
*tem
= nd
; tem
!= 0; tem
= tem
->next
)
372 tem
->set_vertical_size(&v
);
373 last_post_line_extra_space
= v
.post_extra
.to_units();
378 vertical_position
+= v
.pre
;
379 vertical_position
+= v
.pre_extra
;
380 the_output
->print_line(page_offset
, vertical_position
, nd
,
381 v
.pre
+ v
.pre_extra
, v
.post_extra
, width
);
382 vertical_position
+= v
.post_extra
;
383 if (vertical_position
> high_water_mark
)
384 high_water_mark
= vertical_position
;
385 if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
387 else if (vertical_position_traps_flag
388 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
389 nl_reg_contents
= vertical_position
.to_units();
390 truncated_space
= v
.post
;
391 spring_trap(next_trap
->nm
);
393 else if (v
.post
> V0
) {
394 vertical_position
+= v
.post
;
395 if (vertical_position_traps_flag
396 && next_trap
!= 0 && vertical_position
>= next_trap_pos
) {
397 truncated_space
= vertical_position
- next_trap_pos
;
398 vertical_position
= next_trap_pos
;
399 nl_reg_contents
= vertical_position
.to_units();
400 spring_trap(next_trap
->nm
);
402 else if (vertical_position_traps_flag
&& vertical_position
>= page_length
)
405 nl_reg_contents
= vertical_position
.to_units();
408 nl_reg_contents
= vertical_position
.to_units();
411 void top_level_diversion::transparent_output(unsigned char c
)
413 if (before_first_page
&& begin_page())
414 // This can only happen with the .output request.
415 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
416 const char *s
= asciify(c
);
418 the_output
->transparent_char(*s
++);
421 void top_level_diversion::transparent_output(node
* /*n*/)
423 error("can't transparently output node at top level");
426 void top_level_diversion::copy_file(const char *filename
)
428 if (before_first_page
&& begin_page())
429 fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
430 the_output
->copy_file(page_offset
, vertical_position
, filename
);
433 void top_level_diversion::space(vunits n
, int forced
)
441 if (before_first_page
) {
445 vunits next_trap_pos
;
446 trap
*next_trap
= find_next_trap(&next_trap_pos
);
447 vunits y
= vertical_position
+ n
;
448 if (vertical_position_traps_flag
&& next_trap
!= 0 && y
>= next_trap_pos
) {
449 vertical_position
= next_trap_pos
;
450 nl_reg_contents
= vertical_position
.to_units();
451 truncated_space
= y
- vertical_position
;
452 spring_trap(next_trap
->nm
);
455 vertical_position
= V0
;
456 nl_reg_contents
= vertical_position
.to_units();
458 else if (vertical_position_traps_flag
&& y
>= page_length
&& n
>= V0
)
459 begin_page(y
- page_length
);
461 vertical_position
= y
;
462 nl_reg_contents
= vertical_position
.to_units();
466 trap::trap(symbol s
, vunits n
, trap
*p
)
467 : next(p
), position(n
), nm(s
)
471 void top_level_diversion::add_trap(symbol nm
, vunits pos
)
473 trap
*first_free_slot
= 0;
475 for (p
= &page_trap_list
; *p
; p
= &(*p
)->next
) {
476 if ((*p
)->nm
.is_null()) {
477 if (first_free_slot
== 0)
478 first_free_slot
= *p
;
480 else if ((*p
)->position
== pos
) {
485 if (first_free_slot
) {
486 first_free_slot
->nm
= nm
;
487 first_free_slot
->position
= pos
;
490 *p
= new trap(nm
, pos
, 0);
493 void top_level_diversion::remove_trap(symbol nm
)
495 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
502 void top_level_diversion::remove_trap_at(vunits pos
)
504 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
505 if (p
->position
== pos
) {
511 void top_level_diversion::change_trap(symbol nm
, vunits pos
)
513 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
520 void top_level_diversion::print_traps()
522 for (trap
*p
= page_trap_list
; p
; p
= p
->next
)
524 fprintf(stderr
, " empty\n");
526 fprintf(stderr
, "%s\t%d\n", p
->nm
.contents(), p
->position
.to_units());
530 void end_diversions()
532 while (curdiv
!= topdiv
) {
533 error("automatically ending diversion `%1' on exit",
534 curdiv
->nm
.contents());
535 diversion
*tem
= curdiv
;
536 curdiv
= curdiv
->prev
;
541 void cleanup_and_exit(int exit_code
)
544 the_output
->trailer(topdiv
->get_page_length());
547 FLUSH_INPUT_PIPE(STDIN_FILENO
);
551 // Returns non-zero if it sprung a top-of-page trap.
552 // The optional parameter is for the .trunc register.
553 int top_level_diversion::begin_page(vunits n
)
556 if (page_count
== last_page_count
558 : (done_end_macro
&& (seen_last_page_ejector
|| began_page_in_end_macro
)))
561 began_page_in_end_macro
= 1;
563 if (last_page_number
> 0 && page_number
== last_page_number
)
568 if (have_next_page_number
) {
569 page_number
= next_page_number
;
570 have_next_page_number
= 0;
572 else if (before_first_page
== 1)
576 // spring the top of page trap if there is one
577 vunits next_trap_pos
;
578 vertical_position
= -vresolution
;
579 trap
*next_trap
= find_next_trap(&next_trap_pos
);
580 vertical_position
= V0
;
581 high_water_mark
= V0
;
583 // If before_first_page was 2, then the top of page transition was undone
584 // using eg .nr nl 0-1. See nl_reg::set_value.
585 if (before_first_page
!= 2)
586 the_output
->begin_page(page_number
, page_length
);
587 before_first_page
= 0;
588 nl_reg_contents
= vertical_position
.to_units();
589 if (vertical_position_traps_flag
&& next_trap
!= 0 && next_trap_pos
== V0
) {
591 spring_trap(next_trap
->nm
);
598 void continue_page_eject()
600 if (topdiv
->get_ejecting()) {
601 if (curdiv
!= topdiv
)
602 error("can't continue page ejection because of current diversion");
603 else if (!vertical_position_traps_flag
)
604 error("can't continue page ejection because vertical position traps disabled");
607 topdiv
->space(topdiv
->get_page_length(), 1);
612 void top_level_diversion::set_next_page_number(int n
)
615 have_next_page_number
= 1;
618 int top_level_diversion::get_next_page_number()
620 return have_next_page_number
? next_page_number
: page_number
+ 1;
623 void top_level_diversion::set_page_length(vunits n
)
628 diversion::~diversion()
635 // The troff manual says that the default scaling indicator is v,
636 // but it is in fact m: v wouldn't make sense for a horizontally
638 if (!has_arg() || !get_hunits(&n
, 'm', topdiv
->page_offset
))
639 n
= topdiv
->prev_page_offset
;
640 topdiv
->prev_page_offset
= topdiv
->page_offset
;
641 topdiv
->page_offset
= n
;
642 curenv
->add_html_tag(0, ".po", n
.to_units());
649 if (has_arg() && get_vunits(&n
, 'v', topdiv
->get_page_length()))
650 topdiv
->set_page_length(n
);
652 topdiv
->set_page_length(11*units_per_inch
);
659 if (get_vunits(&n
, 'v')) {
660 symbol s
= get_name();
662 topdiv
->remove_trap_at(n
);
664 topdiv
->add_trap(s
, n
);
673 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
675 while (!tok
.newline() && !tok
.eof())
677 if (curdiv
== topdiv
) {
678 if (topdiv
->before_first_page
) {
681 topdiv
->set_next_page_number(n
);
682 if (got_arg
|| !topdiv
->no_space_mode
)
683 topdiv
->begin_page();
685 else if (topdiv
->no_space_mode
&& !got_arg
)
686 topdiv
->begin_page();
701 This code makes groff do the same. */
704 topdiv
->begin_page();
706 topdiv
->set_next_page_number(n
);
707 topdiv
->set_ejecting();
715 topdiv
->set_next_page_number(n
);
716 if (!(topdiv
->no_space_mode
&& !got_arg
))
717 topdiv
->set_ejecting();
725 curdiv
->no_space_mode
= 1;
729 void restore_spacing()
731 curdiv
->no_space_mode
= 0;
735 /* It is necessary to generate a break before before reading the argument,
736 because otherwise arguments using | will be wrong. But if we just
737 generate a break as usual, then the line forced out may spring a trap
738 and thus push a macro onto the input stack before we have had a chance
739 to read the argument to the sp request. We resolve this dilemma by
740 setting, before generating the break, a flag which will postpone the
741 actual pushing of the macro associated with the trap sprung by the
742 outputting of the line forced out by the break till after we have read
743 the argument to the request. If the break did cause a trap to be
744 sprung, then we don't actually do the space. */
752 if (!has_arg() || !get_vunits(&n
, 'v'))
753 n
= curenv
->get_vertical_spacing();
754 while (!tok
.newline() && !tok
.eof())
756 if (!unpostpone_traps() && !curdiv
->no_space_mode
)
759 // The line might have had line spacing that was truncated.
760 truncated_space
+= n
;
761 curenv
->add_html_tag(1, ".sp", n
.to_units());
768 if (!trap_sprung_flag
&& !curdiv
->no_space_mode
) {
769 curdiv
->space(curenv
->get_vertical_spacing());
770 curenv
->add_html_tag(1, ".sp", 1);
773 truncated_space
+= curenv
->get_vertical_spacing();
776 /* need_space might spring a trap and so we must be careful that the
777 BEGIN_TRAP token is not skipped over. */
782 if (!has_arg() || !get_vunits(&n
, 'v'))
783 n
= curenv
->get_vertical_spacing();
784 while (!tok
.newline() && !tok
.eof())
794 // the ps4html register is set if we are using -Tps
795 // to generate images for html
796 reg
*r
= (reg
*)number_reg_dictionary
.lookup("ps4html");
798 if (has_arg() && get_integer(&n
, topdiv
->get_page_number()))
799 topdiv
->set_next_page_number(n
);
805 void save_vertical_space()
808 if (!has_arg() || !get_vunits(&x
, 'v'))
809 x
= curenv
->get_vertical_spacing();
810 if (curdiv
->distance_to_next_trap() > x
)
817 void output_saved_vertical_space()
819 while (!tok
.newline() && !tok
.eof())
821 if (saved_space
> V0
)
822 curdiv
->space(saved_space
, 1);
829 while (!tok
.newline() && !tok
.eof())
835 curenv
->add_html_tag(1, ".fl");
839 void macro_diversion::set_diversion_trap(symbol s
, vunits n
)
842 diversion_trap_pos
= n
;
845 void macro_diversion::clear_diversion_trap()
847 diversion_trap
= NULL_SYMBOL
;
850 void top_level_diversion::set_diversion_trap(symbol
, vunits
)
852 error("can't set diversion trap when no current diversion");
855 void top_level_diversion::clear_diversion_trap()
857 error("can't set diversion trap when no current diversion");
860 void diversion_trap()
863 if (has_arg() && get_vunits(&n
, 'v')) {
864 symbol s
= get_name();
866 curdiv
->set_diversion_trap(s
, n
);
868 curdiv
->clear_diversion_trap();
871 curdiv
->clear_diversion_trap();
877 symbol s
= get_name(1);
880 if (has_arg() && get_vunits(&x
, 'v'))
881 topdiv
->change_trap(s
, x
);
883 topdiv
->remove_trap(s
);
890 topdiv
->print_traps();
896 symbol s
= get_name();
898 curdiv
->marked_place
= curdiv
->get_vertical_position();
899 else if (curdiv
== topdiv
)
900 set_number_reg(s
, nl_reg_contents
);
902 set_number_reg(s
, curdiv
->get_vertical_position().to_units());
906 // This is truly bizarre. It is documented in the SQ manual.
908 void return_request()
910 vunits dist
= curdiv
->marked_place
- curdiv
->get_vertical_position();
912 if (tok
.ch() == '-') {
915 if (get_vunits(&x
, 'v'))
920 if (get_vunits(&x
, 'v'))
921 dist
= x
>= V0
? x
- curdiv
->get_vertical_position() : V0
;
929 void vertical_position_traps()
932 if (has_arg() && get_integer(&n
))
933 vertical_position_traps_flag
= (n
!= 0);
935 vertical_position_traps_flag
= 1;
939 class page_offset_reg
: public reg
{
941 int get_value(units
*);
942 const char *get_string();
945 int page_offset_reg::get_value(units
*res
)
947 *res
= topdiv
->get_page_offset().to_units();
951 const char *page_offset_reg::get_string()
953 return i_to_a(topdiv
->get_page_offset().to_units());
956 class page_length_reg
: public reg
{
958 int get_value(units
*);
959 const char *get_string();
962 int page_length_reg::get_value(units
*res
)
964 *res
= topdiv
->get_page_length().to_units();
968 const char *page_length_reg::get_string()
970 return i_to_a(topdiv
->get_page_length().to_units());
973 class vertical_position_reg
: public reg
{
975 int get_value(units
*);
976 const char *get_string();
979 int vertical_position_reg::get_value(units
*res
)
981 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
984 *res
= curdiv
->get_vertical_position().to_units();
988 const char *vertical_position_reg::get_string()
990 if (curdiv
== topdiv
&& topdiv
->before_first_page
)
993 return i_to_a(curdiv
->get_vertical_position().to_units());
996 class high_water_mark_reg
: public reg
{
998 int get_value(units
*);
999 const char *get_string();
1002 int high_water_mark_reg::get_value(units
*res
)
1004 *res
= curdiv
->get_high_water_mark().to_units();
1008 const char *high_water_mark_reg::get_string()
1010 return i_to_a(curdiv
->get_high_water_mark().to_units());
1013 class distance_to_next_trap_reg
: public reg
{
1015 int get_value(units
*);
1016 const char *get_string();
1019 int distance_to_next_trap_reg::get_value(units
*res
)
1021 *res
= curdiv
->distance_to_next_trap().to_units();
1025 const char *distance_to_next_trap_reg::get_string()
1027 return i_to_a(curdiv
->distance_to_next_trap().to_units());
1030 class diversion_name_reg
: public reg
{
1032 const char *get_string();
1035 const char *diversion_name_reg::get_string()
1037 return curdiv
->get_diversion_name();
1040 class page_number_reg
: public general_reg
{
1043 int get_value(units
*);
1044 void set_value(units
);
1047 page_number_reg::page_number_reg()
1051 void page_number_reg::set_value(units n
)
1053 topdiv
->set_page_number(n
);
1056 int page_number_reg::get_value(units
*res
)
1058 *res
= topdiv
->get_page_number();
1062 class next_page_number_reg
: public reg
{
1064 const char *get_string();
1067 const char *next_page_number_reg::get_string()
1069 return i_to_a(topdiv
->get_next_page_number());
1072 class page_ejecting_reg
: public reg
{
1074 const char *get_string();
1077 const char *page_ejecting_reg::get_string()
1079 return i_to_a(topdiv
->get_ejecting());
1082 class constant_vunits_reg
: public reg
{
1085 constant_vunits_reg(vunits
*);
1086 const char *get_string();
1089 constant_vunits_reg::constant_vunits_reg(vunits
*q
) : p(q
)
1093 const char *constant_vunits_reg::get_string()
1095 return i_to_a(p
->to_units());
1098 class nl_reg
: public variable_reg
{
1101 void set_value(units
);
1104 nl_reg::nl_reg() : variable_reg(&nl_reg_contents
)
1108 void nl_reg::set_value(units n
)
1110 variable_reg::set_value(n
);
1111 // Setting nl to a negative value when the vertical position in
1112 // the top-level diversion is 0 undoes the top of page transition,
1113 // so that the header macro will be called as if the top of page
1114 // transition hasn't happened. This is used by Larry Wall's
1115 // wrapman program. Setting before_first_page to 2 rather than 1,
1116 // tells top_level_diversion::begin_page not to call
1117 // output_file::begin_page again.
1118 if (n
< 0 && topdiv
->get_vertical_position() == V0
)
1119 topdiv
->before_first_page
= 2;
1122 class no_space_mode_reg
: public reg
{
1124 int get_value(units
*);
1125 const char *get_string();
1128 int no_space_mode_reg::get_value(units
*val
)
1130 *val
= curdiv
->no_space_mode
;
1134 const char *no_space_mode_reg::get_string()
1136 return curdiv
->no_space_mode
? "1" : "0";
1139 void init_div_requests()
1141 init_request("box", box
);
1142 init_request("boxa", box_append
);
1143 init_request("bp", begin_page
);
1144 init_request("ch", change_trap
);
1145 init_request("da", divert_append
);
1146 init_request("di", divert
);
1147 init_request("dt", diversion_trap
);
1148 init_request("fl", flush_output
);
1149 init_request("mk", mark
);
1150 init_request("ne", need_space
);
1151 init_request("ns", no_space
);
1152 init_request("os", output_saved_vertical_space
);
1153 init_request("pl", page_length
);
1154 init_request("pn", page_number
);
1155 init_request("po", page_offset
);
1156 init_request("ptr", print_traps
);
1157 init_request("rs", restore_spacing
);
1158 init_request("rt", return_request
);
1159 init_request("sp", space_request
);
1160 init_request("sv", save_vertical_space
);
1161 init_request("vpt", vertical_position_traps
);
1162 init_request("wh", when_request
);
1163 number_reg_dictionary
.define(".a",
1164 new constant_int_reg(&last_post_line_extra_space
));
1165 number_reg_dictionary
.define(".d", new vertical_position_reg
);
1166 number_reg_dictionary
.define(".h", new high_water_mark_reg
);
1167 number_reg_dictionary
.define(".ne",
1168 new constant_vunits_reg(&needed_space
));
1169 number_reg_dictionary
.define(".ns", new no_space_mode_reg
);
1170 number_reg_dictionary
.define(".o", new page_offset_reg
);
1171 number_reg_dictionary
.define(".p", new page_length_reg
);
1172 number_reg_dictionary
.define(".pe", new page_ejecting_reg
);
1173 number_reg_dictionary
.define(".pn", new next_page_number_reg
);
1174 number_reg_dictionary
.define(".t", new distance_to_next_trap_reg
);
1175 number_reg_dictionary
.define(".trunc",
1176 new constant_vunits_reg(&truncated_space
));
1177 number_reg_dictionary
.define(".vpt",
1178 new constant_int_reg(&vertical_position_traps_flag
));
1179 number_reg_dictionary
.define(".z", new diversion_name_reg
);
1180 number_reg_dictionary
.define("dl", new variable_reg(&dl_reg_contents
));
1181 number_reg_dictionary
.define("dn", new variable_reg(&dn_reg_contents
));
1182 number_reg_dictionary
.define("nl", new nl_reg
);
1183 number_reg_dictionary
.define("%", new page_number_reg
);