📄 env.cc
字号:
// -*- C++ -*-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com)This file is part of groff.groff is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING. If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "troff.h"#include "symbol.h"#include "dictionary.h"#include "hvunits.h"#include "env.h"#include "request.h"#include "node.h"#include "token.h"#include "div.h"#include "reg.h"#include "charinfo.h"#include "searchpath.h"#include "macropath.h"#include <math.h>symbol default_family("T");enum { ADJUST_LEFT = 0, ADJUST_BOTH = 1, ADJUST_CENTER = 3, ADJUST_RIGHT = 5 };enum { HYPHEN_LAST_LINE = 2, HYPHEN_LAST_CHARS = 4, HYPHEN_FIRST_CHARS = 8 };struct env_list { environment *env; env_list *next; env_list(environment *e, env_list *p) : env(e), next(p) {}};env_list *env_stack;const int NENVIRONMENTS = 10;environment *env_table[NENVIRONMENTS];dictionary env_dictionary(10);environment *curenv;static int next_line_number = 0;charinfo *field_delimiter_char;charinfo *padding_indicator_char;int translate_space_to_dummy = 0;class pending_output_line { node *nd; int no_fill; vunits vs; int ls; hunits width;#ifdef WIDOW_CONTROL int last_line; // Is it the last line of the paragraph?#endif /* WIDOW_CONTROL */public: pending_output_line *next; pending_output_line(node *, int, vunits, int, hunits, pending_output_line * = 0); ~pending_output_line(); int output();#ifdef WIDOW_CONTROL friend void environment::mark_last_line(); friend void environment::output(node *, int, vunits, int, hunits);#endif /* WIDOW_CONTROL */};pending_output_line::pending_output_line(node *n, int nf, vunits v, int l, hunits w, pending_output_line *p): nd(n), no_fill(nf), vs(v), ls(l), width(w),#ifdef WIDOW_CONTROL last_line(0),#endif /* WIDOW_CONTROL */ next(p){}pending_output_line::~pending_output_line(){ delete_node_list(nd);}int pending_output_line::output(){ if (trap_sprung_flag) return 0;#ifdef WIDOW_CONTROL if (next && next->last_line && !no_fill) { curdiv->need(vs*ls + vunits(vresolution)); if (trap_sprung_flag) { next->last_line = 0; // Try to avoid infinite loops. return 0; } }#endif curdiv->output(nd, no_fill, vs, ls, width); nd = 0; return 1;}void environment::output(node *nd, int no_fill, vunits vs, int ls, hunits width){#ifdef WIDOW_CONTROL while (pending_lines) { if (widow_control && !pending_lines->no_fill && !pending_lines->next) break; if (!pending_lines->output()) break; pending_output_line *tem = pending_lines; pending_lines = pending_lines->next; delete tem; }#else /* WIDOW_CONTROL */ output_pending_lines();#endif /* WIDOW_CONTROL */ if (!trap_sprung_flag && !pending_lines#ifdef WIDOW_CONTROL && (!widow_control || no_fill)#endif /* WIDOW_CONTROL */ ) curdiv->output(nd, no_fill, vs, ls, width); else { for (pending_output_line **p = &pending_lines; *p; p = &(*p)->next) ; *p = new pending_output_line(nd, no_fill, vs, ls, width); }}// a line from .tl goes at the head of the queuevoid environment::output_title(node *nd, int no_fill, vunits vs, int ls, hunits width){ if (!trap_sprung_flag) curdiv->output(nd, no_fill, vs, ls, width); else pending_lines = new pending_output_line(nd, no_fill, vs, ls, width, pending_lines);}void environment::output_pending_lines(){ while (pending_lines && pending_lines->output()) { pending_output_line *tem = pending_lines; pending_lines = pending_lines->next; delete tem; }}#ifdef WIDOW_CONTROLvoid environment::mark_last_line(){ if (!widow_control || !pending_lines) return; for (pending_output_line *p = pending_lines; p->next; p = p->next) ; if (!p->no_fill) p->last_line = 1;}void widow_control_request(){ int n; if (has_arg() && get_integer(&n)) curenv->widow_control = n != 0; else curenv->widow_control = 1; skip_line();}#endif /* WIDOW_CONTROL *//* font_size functions */size_range *font_size::size_table = 0;int font_size::nranges = 0;extern "C" {static int compare_ranges(const void *p1, const void *p2){ return ((size_range *)p1)->min - ((size_range *)p2)->min;}}void font_size::init_size_table(int *sizes){ nranges = 0; while (sizes[nranges*2] != 0) nranges++; assert(nranges > 0); size_table = new size_range[nranges]; for (int i = 0; i < nranges; i++) { size_table[i].min = sizes[i*2]; size_table[i].max = sizes[i*2 + 1]; } qsort(size_table, nranges, sizeof(size_range), compare_ranges);}font_size::font_size(int sp){ for (int i = 0; i < nranges; i++) { if (sp < size_table[i].min) { if (i > 0 && size_table[i].min - sp >= sp - size_table[i - 1].max) p = size_table[i - 1].max; else p = size_table[i].min; return; } if (sp <= size_table[i].max) { p = sp; return; } } p = size_table[nranges - 1].max;}int font_size::to_units(){ return scale(p, units_per_inch, sizescale*72);}// we can't do this in a static constructor because various dictionaries// have to get initialized firstvoid init_environments(){ curenv = env_table[0] = new environment("0");}void tab_character(){ curenv->tab_char = get_optional_char(); skip_line();}void leader_character(){ curenv->leader_char = get_optional_char(); skip_line();}void environment::add_char(charinfo *ci){ if (interrupted) ; // don't allow fields in dummy environments else if (ci == field_delimiter_char && !dummy) { if (current_field) wrap_up_field(); else start_field(); } else if (current_field && ci == padding_indicator_char) add_padding(); else if (current_tab) { if (tab_contents == 0) tab_contents = new line_start_node; if (ci != hyphen_indicator_char) tab_contents = tab_contents->add_char(ci, this, &tab_width); else tab_contents = tab_contents->add_discretionary_hyphen(); } else { if (line == 0) start_line(); if (ci != hyphen_indicator_char) line = line->add_char(ci, this, &width_total); else line = line->add_discretionary_hyphen(); }}node *environment::make_char_node(charinfo *ci){ return make_node(ci, this);}void environment::add_node(node *n){ assert(n != 0); if (current_tab || current_field) n->freeze_space(); if (interrupted) { delete n; } else if (current_tab) { n->next = tab_contents; tab_contents = n; tab_width += n->width(); } else { if (line == 0) { if (discarding && n->discardable()) { // XXX possibly: input_line_start -= n->width(); delete n; return; } start_line(); } width_total += n->width(); space_total += n->nspaces(); n->next = line; line = n; }}void environment::add_hyphen_indicator(){ if (current_tab || interrupted || current_field || hyphen_indicator_char != 0) return; if (line == 0) start_line(); line = line->add_discretionary_hyphen();}int environment::get_hyphenation_flags(){ return hyphenation_flags;}int environment::get_hyphen_line_max(){ return hyphen_line_max;}int environment::get_hyphen_line_count(){ return hyphen_line_count;}int environment::get_center_lines(){ return center_lines;}int environment::get_right_justify_lines(){ return right_justify_lines;}void environment::add_italic_correction(){ if (current_tab) { if (tab_contents) tab_contents = tab_contents->add_italic_correction(&tab_width); } else if (line) line = line->add_italic_correction(&width_total);}void environment::space_newline(){ assert(!current_tab && !current_field); if (interrupted) return; hunits x = H0; if (!translate_space_to_dummy) { x = env_space_width(this); if (node_list_ends_sentence(line) == 1) x += env_sentence_space_width(this); } if (line != 0 && line->merge_space(x)) { width_total += x; return; } add_node(new word_space_node(x)); possibly_break_line(spread_flag); spread_flag = 0;}void environment::space(){ if (interrupted) return; if (current_field && padding_indicator_char == 0) { add_padding(); return; } hunits x = translate_space_to_dummy ? H0 : env_space_width(this); node *p = current_tab ? tab_contents : line; hunits *tp = current_tab ? &tab_width : &width_total; if (p && p->nspaces() == 1 && p->width() == x && node_list_ends_sentence(p->next) == 1) { hunits xx = translate_space_to_dummy ? H0 : env_sentence_space_width(this); if (p->merge_space(xx)) { *tp += xx; return; } } if (p && p->merge_space(x)) { *tp += x; return; } add_node(new word_space_node(x)); possibly_break_line(spread_flag); spread_flag = 0;}void environment::set_font(symbol nm){ if (interrupted) return; if (nm == symbol("P")) { if (family->make_definite(prev_fontno) < 0) return; int tem = fontno; fontno = prev_fontno; prev_fontno = tem; } else { int n = symbol_fontno(nm); if (n < 0) { n = next_available_font_position(); if (!mount_font(n, nm)) return; } if (family->make_definite(n) < 0) return; prev_fontno = fontno; fontno = n; }}void environment::set_font(int n){ if (interrupted) return; if (is_good_fontno(n)) { prev_fontno = fontno; fontno = n; } else error("bad font number");}void environment::set_family(symbol fam){ if (fam.is_null()) { if (prev_family->make_definite(fontno) < 0) return; font_family *tem = family; family = prev_family; prev_family = tem; } else { font_family *f = lookup_family(fam); if (f->make_definite(fontno) < 0) return; prev_family = family; family = f; }}void environment::set_size(int n){ if (interrupted) return; if (n == 0) { font_size temp = prev_size; prev_size = size; size = temp; int temp2 = prev_requested_size; prev_requested_size = requested_size; requested_size = temp2; } else { prev_size = size; size = font_size(n); prev_requested_size = requested_size; requested_size = n; }}void environment::set_char_height(int n){ if (interrupted) return; if (n == requested_size || n <= 0) char_height = 0; else char_height = n;}void environment::set_char_slant(int n){ if (interrupted) return; char_slant = n;}environment::environment(symbol nm): name(nm), prev_line_length((units_per_inch*13)/2), line_length((units_per_inch*13)/2), prev_title_length((units_per_inch*13)/2), title_length((units_per_inch*13)/2), prev_size(sizescale*10), size(sizescale*10), requested_size(sizescale*10), prev_requested_size(sizescale*10), char_height(0), char_slant(0), space_size(12), sentence_space_size(12), adjust_mode(ADJUST_BOTH), fill(1), interrupted(0), prev_line_interrupted(0), center_lines(0), right_justify_lines(0), prev_vertical_spacing(points_to_units(12)), vertical_spacing(points_to_units(12)), prev_line_spacing(1), line_spacing(1), prev_indent(0), indent(0), have_temporary_indent(0), temporary_indent(0), underline_lines(0), input_trap_count(0), prev_text_length(0), width_total(0), space_total(0), input_line_start(0), control_char('.'), no_break_control_char('\''), hyphen_indicator_char(0), spread_flag(0), line(0), pending_lines(0), discarding(0), tabs(units_per_inch/2, TAB_LEFT), current_tab(TAB_NONE), current_field(0), margin_character_flags(0), margin_character_node(0), margin_character_distance(points_to_units(10)), numbering_nodes(0), number_text_separation(1), line_number_multiple(1), line_number_indent(0), no_number_count(0), tab_char(0), leader_char(charset_table['.']), hyphenation_flags(1), dummy(0), leader_node(0),#ifdef WIDOW_CONTROL widow_control(0),#endif /* WIDOW_CONTROL */ hyphen_line_count(0), hyphen_line_max(-1), hyphenation_space(H0), hyphenation_margin(H0), composite(0){ prev_family = family = lookup_family(default_family); prev_fontno = fontno = 1; if (!is_good_fontno(1))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -