2 /* Copyright (C) 1989-2014 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 3 of the License, or
10 (at your option) any later version.
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
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include "dictionary.h"
32 #include "stringclass.h"
34 void output_file::vjustify(vunits, symbol)
39 struct justification_spec;
42 class column : public output_file {
48 void add_output_line(output_line *);
49 void begin_page(int pageno, vunits page_length);
51 void print_line(hunits, vunits, node *, vunits, vunits);
52 void vjustify(vunits, symbol);
53 void transparent_char(unsigned char c);
54 void copy_file(hunits, vunits, const char *);
62 void justify(const justification_spec &);
66 vunits get_last_extra_space();
67 int is_active() { return out != 0; }
70 column *the_column = 0;
72 struct transparent_output_line;
73 struct vjustify_output_line;
79 virtual ~output_line();
80 virtual void output(output_file *, vunits);
81 virtual transparent_output_line *as_transparent_output_line();
82 virtual vjustify_output_line *as_vjustify_output_line();
83 virtual vunits distance();
84 virtual vunits height();
86 virtual vunits extra_space(); // post line
88 friend class justification_spec;
91 class position_output_line : public output_line {
94 position_output_line(vunits);
98 class node_output_line : public position_output_line {
104 node_output_line(vunits, node *, hunits, vunits, vunits);
106 void output(output_file *, vunits);
108 vunits extra_space();
111 class vjustify_output_line : public position_output_line {
115 vjustify_output_line(vunits dist, symbol);
117 vjustify_output_line *as_vjustify_output_line();
118 void vary(vunits amount);
123 inline symbol vjustify_output_line::type()
128 class copy_file_output_line : public position_output_line {
132 copy_file_output_line(vunits, const char *, hunits);
133 void output(output_file *, vunits);
136 class transparent_output_line : public output_line {
139 transparent_output_line();
140 void output(output_file *, vunits);
141 void append_char(unsigned char c);
142 transparent_output_line *as_transparent_output_line();
145 output_line::output_line() : next(0)
149 output_line::~output_line()
153 void output_line::reset()
157 transparent_output_line *output_line::as_transparent_output_line()
162 vjustify_output_line *output_line::as_vjustify_output_line()
167 void output_line::output(output_file *, vunits)
171 vunits output_line::distance()
176 vunits output_line::height()
181 vunits output_line::extra_space()
186 position_output_line::position_output_line(vunits d)
191 vunits position_output_line::distance()
196 node_output_line::node_output_line(vunits d, node *n, hunits po, vunits b, vunits a)
197 : position_output_line(d), nd(n), page_offset(po), before(b), after(a)
201 node_output_line::~node_output_line()
203 delete_node_list(nd);
206 void node_output_line::output(output_file *out, vunits pos)
208 out->print_line(page_offset, pos, nd, before, after);
212 vunits node_output_line::height()
217 vunits node_output_line::extra_space()
222 vjustify_output_line::vjustify_output_line(vunits d, symbol t)
223 : position_output_line(d), typ(t)
227 void vjustify_output_line::reset()
232 vunits vjustify_output_line::height()
237 vjustify_output_line *vjustify_output_line::as_vjustify_output_line()
242 inline void vjustify_output_line::vary(vunits amount)
247 transparent_output_line::transparent_output_line()
251 transparent_output_line *transparent_output_line::as_transparent_output_line()
256 void transparent_output_line::append_char(unsigned char c)
262 void transparent_output_line::output(output_file *out, vunits)
264 int len = buf.length();
265 for (int i = 0; i < len; i++)
266 out->transparent_char(buf[i]);
269 copy_file_output_line::copy_file_output_line(vunits d, const char *f, hunits h)
270 : position_output_line(d), hpos(h), filename(f)
274 void copy_file_output_line::output(output_file *out, vunits pos)
276 out->copy_file(hpos, pos, filename.contents());
280 : bottom(V0), col(0), tail(&col), out(0)
287 error("automatically outputting column before exiting");
297 assert(the_output != 0);
302 void column::begin_page(int pageno, vunits page_length)
306 error("automatically outputting column before beginning next page");
308 the_output->begin_page(pageno, page_length);
311 out->begin_page(pageno, page_length);
321 int column::is_printing()
324 return out->is_printing();
327 vunits column::get_bottom()
332 void column::add_output_line(output_line *ln)
335 bottom += ln->distance();
336 bottom += ln->height();
338 tail = &(*tail)->next;
341 void column::print_line(hunits page_offset, vunits pos, node *nd,
342 vunits before, vunits after)
345 add_output_line(new node_output_line(pos - bottom, nd, page_offset, before, after));
348 void column::vjustify(vunits pos, symbol typ)
351 add_output_line(new vjustify_output_line(pos - bottom, typ));
354 void column::transparent_char(unsigned char c)
357 transparent_output_line *tl = 0;
359 tl = (*tail)->as_transparent_output_line();
361 tl = new transparent_output_line;
367 void column::copy_file(hunits page_offset, vunits pos, const char *filename)
370 add_output_line(new copy_file_output_line(pos - bottom, filename, page_offset));
375 output_line **spp = 0;
376 for (output_line **pp = &col; *pp; pp = &(*pp)->next)
377 if ((*pp)->as_vjustify_output_line() == 0)
382 output_line *ln = *spp;
386 output_line *tem = ln->next;
387 bottom -= ln->distance();
388 bottom -= ln->height();
398 for (output_line *ln = col; ln; ln = ln->next) {
399 bottom += ln->distance();
401 bottom += ln->height();
405 void column::check_bottom()
408 for (output_line *ln = col; ln; ln = ln->next) {
415 void column::output()
419 output_line *ln = col;
421 vpos += ln->distance();
422 ln->output(out, vpos);
423 vpos += ln->height();
424 output_line *tem = ln->next;
435 vunits column::get_last_extra_space()
439 for (output_line *p = col; p->next; p = p->next)
441 return p->extra_space();
444 class justification_spec {
451 justification_spec(vunits);
452 ~justification_spec();
453 void append(symbol t, vunits v);
454 void justify(output_line *, vunits *bottomp) const;
457 justification_spec::justification_spec(vunits h)
458 : height(h), n(0), maxn(10)
460 type = new symbol[maxn];
461 amount = new vunits[maxn];
464 justification_spec::~justification_spec()
470 void justification_spec::append(symbol t, vunits v)
475 "maximum space for vertical justification must not be negative");
478 "maximum space for vertical justification must not be zero");
483 symbol *old_type = type;
484 type = new symbol[maxn];
486 for (i = 0; i < n; i++)
487 type[i] = old_type[i];
489 vunits *old_amount = amount;
490 amount = new vunits[maxn];
491 for (i = 0; i < n; i++)
492 amount[i] = old_amount[i];
501 void justification_spec::justify(output_line *col, vunits *bottomp) const
503 if (*bottomp >= height)
507 for (p = col; p; p = p->next) {
508 vjustify_output_line *sp = p->as_vjustify_output_line();
510 symbol t = sp->type();
511 for (int i = 0; i < n; i++) {
517 vunits gap = height - *bottomp;
518 for (p = col; p; p = p->next) {
519 vjustify_output_line *sp = p->as_vjustify_output_line();
521 symbol t = sp->type();
522 for (int i = 0; i < n; i++) {
530 vunits v = scale(amount[i], gap, total);
540 *bottomp = height - gap;
543 void column::justify(const justification_spec &js)
546 js.justify(col, &bottom);
550 void column_justify()
553 if (!the_column->is_active())
554 error("can't justify column - column not active");
555 else if (get_vunits(&height, 'v')) {
556 justification_spec js(height);
557 symbol nm = get_long_name(1);
560 if (get_vunits(&v, 'v')) {
564 nm = get_long_name(1);
569 if (!get_vunits(&v, 'v')) {
576 the_column->justify(js);
585 if (the_column->is_active())
586 error("can't start column - column already active");
594 if (!the_column->is_active())
595 error("can't output column - column not active");
597 the_column->output();
603 if (!the_column->is_active())
604 error("can't trim column - column not active");
612 if (!the_column->is_active())
613 error("can't reset column - column not active");
619 class column_bottom_reg : public reg {
621 const char *get_string();
624 const char *column_bottom_reg::get_string()
626 return i_to_a(the_column->get_bottom().to_units());
629 class column_extra_space_reg : public reg {
631 const char *get_string();
634 const char *column_extra_space_reg::get_string()
636 return i_to_a(the_column->get_last_extra_space().to_units());
639 class column_active_reg : public reg {
641 const char *get_string();
644 const char *column_active_reg::get_string()
646 return the_column->is_active() ? "1" : "0";
649 static int no_vjustify_mode = 0;
651 class vjustify_node : public node {
654 vjustify_node(symbol);
661 vjustify_node::vjustify_node(symbol t)
666 node *vjustify_node::copy()
668 return new vjustify_node(typ, div_nest_level);
671 const char *vjustify_node::type()
673 return "vjustify_node";
676 int vjustify_node::same(node *nd)
678 return typ == ((vjustify_node *)nd)->typ;
681 int vjustify_node::reread(int *bolp)
683 curdiv->vjustify(typ);
688 void macro_diversion::vjustify(symbol type)
690 if (!no_vjustify_mode)
691 mac->append(new vjustify_node(type));
694 void top_level_diversion::vjustify(symbol type)
696 if (no_space_mode || no_vjustify_mode)
698 assert(first_page_begun); // I'm not sure about this.
699 the_output->vjustify(vertical_position, type);
705 no_vjustify_mode = 1;
708 void restore_vjustify()
711 no_vjustify_mode = 0;
714 void init_column_requests()
716 the_column = new column;
717 init_request("cols", column_start);
718 init_request("colo", column_output);
719 init_request("colj", column_justify);
720 init_request("colr", column_reset);
721 init_request("colt", column_trim);
722 init_request("nvj", no_vjustify);
723 init_request("rvj", restore_vjustify);
724 number_reg_dictionary.define(".colb", new column_bottom_reg);
725 number_reg_dictionary.define(".colx", new column_extra_space_reg);
726 number_reg_dictionary.define(".cola", new column_active_reg);
727 number_reg_dictionary.define(".nvj",
728 new constant_int_reg(&no_vjustify_mode));