2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff 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 groff 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. */
25 #include "dictionary.h"
33 #include "stringclass.h"
35 void output_file::vjustify(vunits
, symbol
)
40 struct justification_spec
;
43 class column
: public output_file
{
49 void add_output_line(output_line
*);
50 void begin_page(int pageno
, vunits page_length
);
52 void print_line(hunits
, vunits
, node
*, vunits
, vunits
);
53 void vjustify(vunits
, symbol
);
54 void transparent_char(unsigned char c
);
55 void copy_file(hunits
, vunits
, const char *);
63 void justify(const justification_spec
&);
67 vunits
get_last_extra_space();
68 int is_active() { return out
!= 0; }
71 column
*the_column
= 0;
73 struct transparent_output_line
;
74 struct vjustify_output_line
;
80 virtual ~output_line();
81 virtual void output(output_file
*, vunits
);
82 virtual transparent_output_line
*as_transparent_output_line();
83 virtual vjustify_output_line
*as_vjustify_output_line();
84 virtual vunits
distance();
85 virtual vunits
height();
87 virtual vunits
extra_space(); // post line
89 friend class justification_spec
;
92 class position_output_line
: public output_line
{
95 position_output_line(vunits
);
99 class node_output_line
: public position_output_line
{
105 node_output_line(vunits
, node
*, hunits
, vunits
, vunits
);
107 void output(output_file
*, vunits
);
109 vunits
extra_space();
112 class vjustify_output_line
: public position_output_line
{
116 vjustify_output_line(vunits dist
, symbol
);
118 vjustify_output_line
*as_vjustify_output_line();
119 void vary(vunits amount
);
124 inline symbol
vjustify_output_line::type()
129 class copy_file_output_line
: public position_output_line
{
133 copy_file_output_line(vunits
, const char *, hunits
);
134 void output(output_file
*, vunits
);
137 class transparent_output_line
: public output_line
{
140 transparent_output_line();
141 void output(output_file
*, vunits
);
142 void append_char(unsigned char c
);
143 transparent_output_line
*as_transparent_output_line();
146 output_line::output_line() : next(0)
150 output_line::~output_line()
154 void output_line::reset()
158 transparent_output_line
*output_line::as_transparent_output_line()
163 vjustify_output_line
*output_line::as_vjustify_output_line()
168 void output_line::output(output_file
*, vunits
)
172 vunits
output_line::distance()
177 vunits
output_line::height()
182 vunits
output_line::extra_space()
187 position_output_line::position_output_line(vunits d
)
192 vunits
position_output_line::distance()
197 node_output_line::node_output_line(vunits d
, node
*n
, hunits po
, vunits b
, vunits a
)
198 : position_output_line(d
), nd(n
), page_offset(po
), before(b
), after(a
)
202 node_output_line::~node_output_line()
204 delete_node_list(nd
);
207 void node_output_line::output(output_file
*out
, vunits pos
)
209 out
->print_line(page_offset
, pos
, nd
, before
, after
);
213 vunits
node_output_line::height()
218 vunits
node_output_line::extra_space()
223 vjustify_output_line::vjustify_output_line(vunits d
, symbol t
)
224 : position_output_line(d
), typ(t
)
228 void vjustify_output_line::reset()
233 vunits
vjustify_output_line::height()
238 vjustify_output_line
*vjustify_output_line::as_vjustify_output_line()
243 inline void vjustify_output_line::vary(vunits amount
)
248 transparent_output_line::transparent_output_line()
252 transparent_output_line
*transparent_output_line::as_transparent_output_line()
257 void transparent_output_line::append_char(unsigned char c
)
263 void transparent_output_line::output(output_file
*out
, vunits
)
265 int len
= buf
.length();
266 for (int i
= 0; i
< len
; i
++)
267 out
->transparent_char(buf
[i
]);
270 copy_file_output_line::copy_file_output_line(vunits d
, const char *f
, hunits h
)
271 : position_output_line(d
), hpos(h
), filename(f
)
275 void copy_file_output_line::output(output_file
*out
, vunits pos
)
277 out
->copy_file(hpos
, pos
, filename
.contents());
281 : bottom(V0
), col(0), tail(&col
), out(0)
288 error("automatically outputting column before exiting");
298 assert(the_output
!= 0);
303 void column::begin_page(int pageno
, vunits page_length
)
307 error("automatically outputting column before beginning next page");
309 the_output
->begin_page(pageno
, page_length
);
312 out
->begin_page(pageno
, page_length
);
322 int column::is_printing()
325 return out
->is_printing();
328 vunits
column::get_bottom()
333 void column::add_output_line(output_line
*ln
)
336 bottom
+= ln
->distance();
337 bottom
+= ln
->height();
339 tail
= &(*tail
)->next
;
342 void column::print_line(hunits page_offset
, vunits pos
, node
*nd
,
343 vunits before
, vunits after
)
346 add_output_line(new node_output_line(pos
- bottom
, nd
, page_offset
, before
, after
));
349 void column::vjustify(vunits pos
, symbol typ
)
352 add_output_line(new vjustify_output_line(pos
- bottom
, typ
));
355 void column::transparent_char(unsigned char c
)
358 transparent_output_line
*tl
= 0;
360 tl
= (*tail
)->as_transparent_output_line();
362 tl
= new transparent_output_line
;
368 void column::copy_file(hunits page_offset
, vunits pos
, const char *filename
)
371 add_output_line(new copy_file_output_line(pos
- bottom
, filename
, page_offset
));
376 output_line
**spp
= 0;
377 for (output_line
**pp
= &col
; *pp
; pp
= &(*pp
)->next
)
378 if ((*pp
)->as_vjustify_output_line() == 0)
383 output_line
*ln
= *spp
;
387 output_line
*tem
= ln
->next
;
388 bottom
-= ln
->distance();
389 bottom
-= ln
->height();
399 for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
400 bottom
+= ln
->distance();
402 bottom
+= ln
->height();
406 void column::check_bottom()
409 for (output_line
*ln
= col
; ln
; ln
= ln
->next
) {
416 void column::output()
420 output_line
*ln
= col
;
422 vpos
+= ln
->distance();
423 ln
->output(out
, vpos
);
424 vpos
+= ln
->height();
425 output_line
*tem
= ln
->next
;
436 vunits
column::get_last_extra_space()
440 for (output_line
*p
= col
; p
->next
; p
= p
->next
)
442 return p
->extra_space();
445 class justification_spec
{
452 justification_spec(vunits
);
453 ~justification_spec();
454 void append(symbol t
, vunits v
);
455 void justify(output_line
*, vunits
*bottomp
) const;
458 justification_spec::justification_spec(vunits h
)
459 : height(h
), n(0), maxn(10)
461 type
= new symbol
[maxn
];
462 amount
= new vunits
[maxn
];
465 justification_spec::~justification_spec()
471 void justification_spec::append(symbol t
, vunits v
)
476 "maximum space for vertical justification must not be negative");
479 "maximum space for vertical justification must not be zero");
484 symbol
*old_type
= type
;
485 type
= new symbol
[maxn
];
487 for (i
= 0; i
< n
; i
++)
488 type
[i
] = old_type
[i
];
490 vunits
*old_amount
= amount
;
491 amount
= new vunits
[maxn
];
492 for (i
= 0; i
< n
; i
++)
493 amount
[i
] = old_amount
[i
];
502 void justification_spec::justify(output_line
*col
, vunits
*bottomp
) const
504 if (*bottomp
>= height
)
508 for (p
= col
; p
; p
= p
->next
) {
509 vjustify_output_line
*sp
= p
->as_vjustify_output_line();
511 symbol t
= sp
->type();
512 for (int i
= 0; i
< n
; i
++) {
518 vunits gap
= height
- *bottomp
;
519 for (p
= col
; p
; p
= p
->next
) {
520 vjustify_output_line
*sp
= p
->as_vjustify_output_line();
522 symbol t
= sp
->type();
523 for (int i
= 0; i
< n
; i
++) {
531 vunits v
= scale(amount
[i
], gap
, total
);
541 *bottomp
= height
- gap
;
544 void column::justify(const justification_spec
&js
)
547 js
.justify(col
, &bottom
);
551 void column_justify()
554 if (!the_column
->is_active())
555 error("can't justify column - column not active");
556 else if (get_vunits(&height
, 'v')) {
557 justification_spec
js(height
);
558 symbol nm
= get_long_name(1);
561 if (get_vunits(&v
, 'v')) {
565 nm
= get_long_name(1);
570 if (!get_vunits(&v
, 'v')) {
577 the_column
->justify(js
);
586 if (the_column
->is_active())
587 error("can't start column - column already active");
595 if (!the_column
->is_active())
596 error("can't output column - column not active");
598 the_column
->output();
604 if (!the_column
->is_active())
605 error("can't trim column - column not active");
613 if (!the_column
->is_active())
614 error("can't reset column - column not active");
620 class column_bottom_reg
: public reg
{
622 const char *get_string();
625 const char *column_bottom_reg::get_string()
627 return i_to_a(the_column
->get_bottom().to_units());
630 class column_extra_space_reg
: public reg
{
632 const char *get_string();
635 const char *column_extra_space_reg::get_string()
637 return i_to_a(the_column
->get_last_extra_space().to_units());
640 class column_active_reg
: public reg
{
642 const char *get_string();
645 const char *column_active_reg::get_string()
647 return the_column
->is_active() ? "1" : "0";
650 static int no_vjustify_mode
= 0;
652 class vjustify_node
: public node
{
655 vjustify_node(symbol
);
662 vjustify_node::vjustify_node(symbol t
)
667 node
*vjustify_node::copy()
669 return new vjustify_node(typ
, div_nest_level
);
672 const char *vjustify_node::type()
674 return "vjustify_node";
677 int vjustify_node::same(node
*nd
)
679 return typ
== ((vjustify_node
*)nd
)->typ
;
682 int vjustify_node::reread(int *bolp
)
684 curdiv
->vjustify(typ
);
689 void macro_diversion::vjustify(symbol type
)
691 if (!no_vjustify_mode
)
692 mac
->append(new vjustify_node(type
));
695 void top_level_diversion::vjustify(symbol type
)
697 if (no_space_mode
|| no_vjustify_mode
)
699 assert(first_page_begun
); // I'm not sure about this.
700 the_output
->vjustify(vertical_position
, type
);
706 no_vjustify_mode
= 1;
709 void restore_vjustify()
712 no_vjustify_mode
= 0;
715 void init_column_requests()
717 the_column
= new column
;
718 init_request("cols", column_start
);
719 init_request("colo", column_output
);
720 init_request("colj", column_justify
);
721 init_request("colr", column_reset
);
722 init_request("colt", column_trim
);
723 init_request("nvj", no_vjustify
);
724 init_request("rvj", restore_vjustify
);
725 number_reg_dictionary
.define(".colb", new column_bottom_reg
);
726 number_reg_dictionary
.define(".colx", new column_extra_space_reg
);
727 number_reg_dictionary
.define(".cola", new column_active_reg
);
728 number_reg_dictionary
.define(".nvj",
729 new constant_int_reg(&no_vjustify_mode
));