2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2000 Free Software Foundation, Inc.
5 * Written by James Clark (jjc@jclark.com)
7 * This 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 * This 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "troff-config.h"
26 #include "stringclass.h"
30 #include "dictionary.h"
39 void output_file::vjustify(vunits
, symbol
)
44 struct justification_spec
;
55 void add_output_line(output_line
*);
56 void begin_page(int pageno
, vunits page_length
);
58 void print_line(hunits
, vunits
, node
*, vunits
, vunits
);
59 void vjustify(vunits
, symbol
);
60 void transparent_char(unsigned char c
);
61 void copy_file(hunits
, vunits
, const char *);
70 void justify(const justification_spec
&);
74 vunits
get_last_extra_space();
75 int is_active() { return out
!= 0; }
78 column
*the_column
= 0;
80 struct transparent_output_line
;
81 struct vjustify_output_line
;
86 friend class justification_spec
;
92 virtual ~output_line();
93 virtual void output(output_file
*, vunits
);
94 virtual transparent_output_line
*as_transparent_output_line();
95 virtual vjustify_output_line
*as_vjustify_output_line();
96 virtual vunits
distance();
97 virtual vunits
height();
99 virtual vunits
extra_space(); // post line
102 class position_output_line
108 position_output_line(vunits
);
112 class node_output_line
113 : public position_output_line
121 node_output_line(vunits
, node
*, hunits
, vunits
, vunits
);
123 void output(output_file
*, vunits
);
125 vunits
extra_space();
128 class vjustify_output_line
129 : public position_output_line
135 vjustify_output_line(vunits dist
, symbol
);
137 vjustify_output_line
*as_vjustify_output_line();
138 void vary(vunits amount
);
143 inline symbol
vjustify_output_line::type()
148 class copy_file_output_line
149 : public position_output_line
155 copy_file_output_line(vunits
, const char *, hunits
);
156 void output(output_file
*, vunits
);
159 class transparent_output_line
165 transparent_output_line();
166 void output(output_file
*, vunits
);
167 void append_char(unsigned char c
);
168 transparent_output_line
*as_transparent_output_line();
171 output_line::output_line() : next(0)
175 output_line::~output_line()
179 void output_line::reset()
183 transparent_output_line
*output_line::as_transparent_output_line()
188 vjustify_output_line
*output_line::as_vjustify_output_line()
193 void output_line::output(output_file
*, vunits
)
197 vunits
output_line::distance()
202 vunits
output_line::height()
207 vunits
output_line::extra_space()
212 position_output_line::position_output_line(vunits d
)
217 vunits
position_output_line::distance()
222 node_output_line::node_output_line(vunits d
, node
*n
, hunits po
, vunits b
, vunits a
)
223 : position_output_line(d
), nd(n
), page_offset(po
), before(b
), after(a
)
227 node_output_line::~node_output_line()
229 delete_node_list(nd
);
232 void node_output_line::output(output_file
*out
, vunits pos
)
234 out
->print_line(page_offset
, pos
, nd
, before
, after
);
238 vunits
node_output_line::height()
243 vunits
node_output_line::extra_space()
248 vjustify_output_line::vjustify_output_line(vunits d
, symbol t
)
249 : position_output_line(d
), typ(t
)
253 void vjustify_output_line::reset()
258 vunits
vjustify_output_line::height()
263 vjustify_output_line
*vjustify_output_line::as_vjustify_output_line()
268 inline void vjustify_output_line::vary(vunits amount
)
273 transparent_output_line::transparent_output_line()
277 transparent_output_line
*transparent_output_line::as_transparent_output_line()
282 void transparent_output_line::append_char(unsigned char c
)
288 void transparent_output_line::output(output_file
*out
, vunits
)
290 int len
= buf
.length();
291 for (int i
= 0; i
< len
; i
++)
292 out
->transparent_char(buf
[i
]);
295 copy_file_output_line::copy_file_output_line(vunits d
, const char *f
, hunits h
)
296 : position_output_line(d
), hpos(h
), filename(f
)
300 void copy_file_output_line::output(output_file
*out
, vunits pos
)
302 out
->copy_file(hpos
, pos
, filename
.contents());
306 : bottom(V0
), col(0), tail(&col
), out(0)
313 error("automatically outputting column before exiting");
323 assert(the_output
!= 0);
328 void column::begin_page(int pageno
, vunits page_length
)
332 error("automatically outputting column before beginning next page");
334 the_output
->begin_page(pageno
, page_length
);
337 out
->begin_page(pageno
, page_length
);
347 int column::is_printing()
350 return out
->is_printing();
353 vunits
column::get_bottom()
358 void column::add_output_line(output_line
*ln
)
361 bottom
+= ln
->distance();
362 bottom
+= ln
->height();
364 tail
= &(*tail
)->next
;
367 void column::print_line(hunits page_offset
, vunits pos
, node
*nd
,
368 vunits before
, vunits after
)
371 add_output_line(new node_output_line(pos
- bottom
, nd
, page_offset
, before
, after
));
374 void column::vjustify(vunits pos
, symbol typ
)
377 add_output_line(new vjustify_output_line(pos
- bottom
, typ
));
380 void column::transparent_char(unsigned char c
)
383 transparent_output_line
*tl
= 0;
385 tl
= (*tail
)->as_transparent_output_line();
387 tl
= new transparent_output_line
;
393 void column::copy_file(hunits page_offset
, vunits pos
, const char *filename
)
396 add_output_line(new copy_file_output_line(pos
- bottom
, filename
, page_offset
));
401 output_line
**spp
= 0;
402 for (output_line
**pp
= &col
; *pp
; pp
= &(*pp
)->next
)
403 if ((*pp
)->as_vjustify_output_line() == 0)
408 output_line
*ln
= *spp
;
412 output_line
*tem
= ln
->next
;
413 bottom
-= ln
->distance();
414 bottom
-= ln
->height();
424 for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
425 bottom
+= ln
->distance();
427 bottom
+= ln
->height();
431 void column::check_bottom()
434 for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
441 void column::output()
445 output_line
*ln
= col
;
447 vpos
+= ln
->distance();
448 ln
->output(out
, vpos
);
449 vpos
+= ln
->height();
450 output_line
*tem
= ln
->next
;
461 vunits
column::get_last_extra_space()
465 for (output_line
*p
= col
; p
->next
; p
= p
->next
)
467 return p
->extra_space();
470 class justification_spec
479 justification_spec(vunits
);
480 ~justification_spec();
481 void append(symbol t
, vunits v
);
482 void justify(output_line
*, vunits
*bottomp
) const;
485 justification_spec::justification_spec(vunits h
)
486 : height(h
), n(0), maxn(10)
488 type
= new symbol
[maxn
];
489 amount
= new vunits
[maxn
];
492 justification_spec::~justification_spec()
498 void justification_spec::append(symbol t
, vunits v
)
503 "maximum space for vertical justification must not be negative");
506 "maximum space for vertical justification must not be zero");
511 symbol
*old_type
= type
;
512 type
= new symbol
[maxn
];
514 for (i
= 0; i
< n
; i
++)
515 type
[i
] = old_type
[i
];
517 vunits
*old_amount
= amount
;
518 amount
= new vunits
[maxn
];
519 for (i
= 0; i
< n
; i
++)
520 amount
[i
] = old_amount
[i
];
529 void justification_spec::justify(output_line
*col
, vunits
*bottomp
) const
531 if (*bottomp
>= height
)
535 for (p
= col
; p
; p
= p
->next
) {
536 vjustify_output_line
*sp
= p
->as_vjustify_output_line();
538 symbol t
= sp
->type();
539 for (int i
= 0; i
< n
; i
++) {
545 vunits gap
= height
- *bottomp
;
546 for (p
= col
; p
; p
= p
->next
) {
547 vjustify_output_line
*sp
= p
->as_vjustify_output_line();
549 symbol t
= sp
->type();
550 for (int i
= 0; i
< n
; i
++) {
558 vunits v
= scale(amount
[i
], gap
, total
);
568 *bottomp
= height
- gap
;
571 void column::justify(const justification_spec
&js
)
574 js
.justify(col
, &bottom
);
578 void column_justify()
581 if (!the_column
->is_active())
582 error("can't justify column - column not active");
583 else if (get_vunits(&height
, 'v')) {
584 justification_spec
js(height
);
585 symbol nm
= get_long_name(1);
588 if (get_vunits(&v
, 'v')) {
592 nm
= get_long_name(1);
597 if (!get_vunits(&v
, 'v')) {
604 the_column
->justify(js
);
613 if (the_column
->is_active())
614 error("can't start column - column already active");
622 if (!the_column
->is_active())
623 error("can't output column - column not active");
625 the_column
->output();
631 if (!the_column
->is_active())
632 error("can't trim column - column not active");
640 if (!the_column
->is_active())
641 error("can't reset column - column not active");
647 class column_bottom_reg
651 const char *get_string();
654 const char *column_bottom_reg::get_string()
656 return i_to_a(the_column
->get_bottom().to_units());
659 class column_extra_space_reg
663 const char *get_string();
666 const char *column_extra_space_reg::get_string()
668 return i_to_a(the_column
->get_last_extra_space().to_units());
671 class column_active_reg
675 const char *get_string();
678 const char *column_active_reg::get_string()
680 return the_column
->is_active() ? "1" : "0";
683 static int no_vjustify_mode
= 0;
691 vjustify_node(symbol
);
698 vjustify_node::vjustify_node(symbol t
)
703 node
*vjustify_node::copy()
705 return new vjustify_node(typ
, div_nest_level
);
708 const char *vjustify_node::type()
710 return "vjustify_node";
713 int vjustify_node::same(node
*nd
)
715 return typ
== ((vjustify_node
*)nd
)->typ
;
718 int vjustify_node::reread(int *bolp
)
720 curdiv
->vjustify(typ
);
725 void macro_diversion::vjustify(symbol type
)
727 if (!no_vjustify_mode
)
728 mac
->append(new vjustify_node(type
));
731 void top_level_diversion::vjustify(symbol type
)
733 if (no_space_mode
|| no_vjustify_mode
)
735 assert(first_page_begun
); // I'm not sure about this.
736 the_output
->vjustify(vertical_position
, type
);
742 no_vjustify_mode
= 1;
745 void restore_vjustify()
748 no_vjustify_mode
= 0;
751 void init_column_requests()
753 the_column
= new column
;
754 init_request("cols", column_start
);
755 init_request("colo", column_output
);
756 init_request("colj", column_justify
);
757 init_request("colr", column_reset
);
758 init_request("colt", column_trim
);
759 init_request("nvj", no_vjustify
);
760 init_request("rvj", restore_vjustify
);
761 number_reg_dictionary
.define(".colb", new column_bottom_reg
);
762 number_reg_dictionary
.define(".colx", new column_extra_space_reg
);
763 number_reg_dictionary
.define(".cola", new column_active_reg
);
764 number_reg_dictionary
.define(".nvj",
765 new constant_int_reg(&no_vjustify_mode
));