/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
void output_file::vjustify(vunits
, symbol
)
struct justification_spec
;
class column
: public output_file
{
void add_output_line(output_line
*);
void begin_page(int pageno
, vunits page_length
);
void print_line(hunits
, vunits
, node
*, vunits
, vunits
);
void vjustify(vunits
, symbol
);
void transparent_char(unsigned char c
);
void copy_file(hunits
, vunits
, const char *);
void justify(const justification_spec
&);
vunits
get_last_extra_space();
int is_active() { return out
!= 0; }
struct transparent_output_line
;
struct vjustify_output_line
;
virtual void output(output_file
*, vunits
);
virtual transparent_output_line
*as_transparent_output_line();
virtual vjustify_output_line
*as_vjustify_output_line();
virtual vunits
distance();
virtual vunits
extra_space(); // post line
friend class justification_spec
;
class position_output_line
: public output_line
{
position_output_line(vunits
);
class node_output_line
: public position_output_line
{
node_output_line(vunits
, node
*, hunits
, vunits
, vunits
);
void output(output_file
*, vunits
);
class vjustify_output_line
: public position_output_line
{
vjustify_output_line(vunits dist
, symbol
);
vjustify_output_line
*as_vjustify_output_line();
void vary(vunits amount
);
inline symbol
vjustify_output_line::type()
class copy_file_output_line
: public position_output_line
{
copy_file_output_line(vunits
, const char *, hunits
);
void output(output_file
*, vunits
);
class transparent_output_line
: public output_line
{
transparent_output_line();
void output(output_file
*, vunits
);
void append_char(unsigned char c
);
transparent_output_line
*as_transparent_output_line();
output_line::output_line() : next(0)
output_line::~output_line()
void output_line::reset()
transparent_output_line
*output_line::as_transparent_output_line()
vjustify_output_line
*output_line::as_vjustify_output_line()
void output_line::output(output_file
*, vunits
)
vunits
output_line::distance()
vunits
output_line::height()
vunits
output_line::extra_space()
position_output_line::position_output_line(vunits d
)
vunits
position_output_line::distance()
node_output_line::node_output_line(vunits d
, node
*n
, hunits po
, vunits b
, vunits a
)
: position_output_line(d
), nd(n
), page_offset(po
), before(b
), after(a
)
node_output_line::~node_output_line()
void node_output_line::output(output_file
*out
, vunits pos
)
out
->print_line(page_offset
, pos
, nd
, before
, after
);
vunits
node_output_line::height()
vunits
node_output_line::extra_space()
vjustify_output_line::vjustify_output_line(vunits d
, symbol t
)
: position_output_line(d
), typ(t
)
void vjustify_output_line::reset()
vunits
vjustify_output_line::height()
vjustify_output_line
*vjustify_output_line::as_vjustify_output_line()
inline void vjustify_output_line::vary(vunits amount
)
transparent_output_line::transparent_output_line()
transparent_output_line
*transparent_output_line::as_transparent_output_line()
void transparent_output_line::append_char(unsigned char c
)
void transparent_output_line::output(output_file
*out
, vunits
)
for (int i
= 0; i
< len
; i
++)
out
->transparent_char(buf
[i
]);
copy_file_output_line::copy_file_output_line(vunits d
, const char *f
, hunits h
)
: position_output_line(d
), hpos(h
), filename(f
)
void copy_file_output_line::output(output_file
*out
, vunits pos
)
out
->copy_file(hpos
, pos
, filename
.contents());
: bottom(V0
), col(0), tail(&col
), out(0)
error("automatically outputting column before exiting");
void column::begin_page(int pageno
, vunits page_length
)
error("automatically outputting column before beginning next page");
the_output
->begin_page(pageno
, page_length
);
out
->begin_page(pageno
, page_length
);
int column::is_printing()
return out
->is_printing();
vunits
column::get_bottom()
void column::add_output_line(output_line
*ln
)
bottom
+= ln
->distance();
void column::print_line(hunits page_offset
, vunits pos
, node
*nd
,
vunits before
, vunits after
)
add_output_line(new node_output_line(pos
- bottom
, nd
, page_offset
, before
, after
));
void column::vjustify(vunits pos
, symbol typ
)
add_output_line(new vjustify_output_line(pos
- bottom
, typ
));
void column::transparent_char(unsigned char c
)
transparent_output_line
*tl
= 0;
tl
= (*tail
)->as_transparent_output_line();
tl
= new transparent_output_line
;
void column::copy_file(hunits page_offset
, vunits pos
, const char *filename
)
add_output_line(new copy_file_output_line(pos
- bottom
, filename
, page_offset
));
for (output_line
**pp
= &col
; *pp
; pp
= &(*pp
)->next
)
if ((*pp
)->as_vjustify_output_line() == 0)
output_line
*tem
= ln
->next
;
bottom
-= ln
->distance();
for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
bottom
+= ln
->distance();
void column::check_bottom()
for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
output_line
*tem
= ln
->next
;
vunits
column::get_last_extra_space()
for (output_line
*p
= col
; p
->next
; p
= p
->next
)
class justification_spec
{
justification_spec(vunits
);
void append(symbol t
, vunits v
);
void justify(output_line
*, vunits
*bottomp
) const;
justification_spec::justification_spec(vunits h
)
: height(h
), n(0), maxn(10)
amount
= new vunits
[maxn
];
justification_spec::~justification_spec()
void justification_spec::append(symbol t
, vunits v
)
"maximum space for vertical justification must not be negative");
"maximum space for vertical justification must not be zero");
vunits
*old_amount
= amount
;
amount
= new vunits
[maxn
];
amount
[i
] = old_amount
[i
];
void justification_spec::justify(output_line
*col
, vunits
*bottomp
) const
for (p
= col
; p
; p
= p
->next
) {
vjustify_output_line
*sp
= p
->as_vjustify_output_line();
for (int i
= 0; i
< n
; i
++) {
vunits gap
= height
- *bottomp
;
for (p
= col
; p
; p
= p
->next
) {
vjustify_output_line
*sp
= p
->as_vjustify_output_line();
for (int i
= 0; i
< n
; i
++) {
vunits v
= scale(amount
[i
], gap
, total
);
void column::justify(const justification_spec
&js
)
js
.justify(col
, &bottom
);
if (!the_column
->is_active())
error("can't justify column - column not active");
else if (get_vunits(&height
, 'v')) {
justification_spec
js(height
);
symbol nm
= get_long_name(1);
if (get_vunits(&v
, 'v')) {
if (!get_vunits(&v
, 'v')) {
if (the_column
->is_active())
error("can't start column - column already active");
if (!the_column
->is_active())
error("can't output column - column not active");
if (!the_column
->is_active())
error("can't trim column - column not active");
if (!the_column
->is_active())
error("can't reset column - column not active");
class column_bottom_reg
: public reg
{
const char *get_string();
const char *column_bottom_reg::get_string()
return itoa(the_column
->get_bottom().to_units());
class column_extra_space_reg
: public reg
{
const char *get_string();
const char *column_extra_space_reg::get_string()
return itoa(the_column
->get_last_extra_space().to_units());
class column_active_reg
: public reg
{
const char *get_string();
const char *column_active_reg::get_string()
return the_column
->is_active() ? "1" : "0";
static int no_vjustify_mode
= 0;
class vjustify_node
: public node
{
vjustify_node::vjustify_node(symbol t
)
node
*vjustify_node::copy()
return new vjustify_node(typ
);
const char *vjustify_node::type()
int vjustify_node::same(node
*nd
)
return typ
== ((vjustify_node
*)nd
)->typ
;
int vjustify_node::reread(int *bolp
)
void macro_diversion::vjustify(symbol type
)
mac
->append(new vjustify_node(type
));
void top_level_diversion::vjustify(symbol type
)
if (no_space_mode
|| no_vjustify_mode
)
assert(first_page_begun
); // I'm not sure about this.
the_output
->vjustify(vertical_position
, type
);
void init_column_requests()
init_request("cols", column_start
);
init_request("colo", column_output
);
init_request("colj", column_justify
);
init_request("colr", column_reset
);
init_request("colt", column_trim
);
init_request("nvj", no_vjustify
);
init_request("rvj", restore_vjustify
);
number_reg_dictionary
.define(".colb", new column_bottom_reg
);
number_reg_dictionary
.define(".colx", new column_extra_space_reg
);
number_reg_dictionary
.define(".cola", new column_active_reg
);
number_reg_dictionary
.define(".nvj",
new constant_int_reg(&no_vjustify_mode
));