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));