📄 env.cc
字号:
saved_indent = indent; target_text_length = line_length - saved_indent; } }}/*Do the break at the end of input after the end macro (if any).Unix troff behaves as follows: if the last line isfoo bar\cit will output foo on the current page, and bar on the next page;if the last line isfoo\corfoo bareverything will be output on the current page. This behaviour must beconsidered a bug.The problem is that some macro packages rely on this. For example,the ATK macros have an end macro that emits \c if it needs to print atable of contents but doesn't do a 'bp in the end macro; instead the'bp is done in the bottom of page trap. This works with Unix troff,provided that the current environment is not empty at the end of theinput file.The following will make macro packages that do that sort of thing workeven if the current environment is empty at the end of the input file.If the last input line used \c and this line occurred in the end macro,then we'll force everything out on the current page, but we'll makesure that the environment isn't empty so that we won't exit at thebottom of this page.*/void environment::final_break(){ if (prev_line_interrupted == 2) { do_break(); add_node(new transparent_dummy_node); } else do_break();}void environment::do_break(){ if (curdiv == topdiv && topdiv->before_first_page) { topdiv->begin_page(); return; } if (current_tab) wrap_up_tab(); if (line) { line = new space_node(H0, line); // this is so that hyphenation works space_total++; possibly_break_line(); } while (line != 0 && line->discardable()) { width_total -= line->width(); space_total -= line->nspaces(); node *tem = line; line = line->next; delete tem; } discarding = 0; input_line_start = H0; if (line != 0) { if (fill) { switch (adjust_mode) { case ADJUST_CENTER: saved_indent += (target_text_length - width_total)/2; break; case ADJUST_RIGHT: saved_indent += target_text_length - width_total; break; } } node *tem = line; line = 0; output_line(tem, width_total); hyphen_line_count = 0; } prev_line_interrupted = 0;#ifdef WIDOW_CONTROL mark_last_line(); output_pending_lines();#endif /* WIDOW_CONTROL */}int environment::is_empty(){ return !current_tab && line == 0 && pending_lines == 0;}void break_request(){ while (!tok.newline() && !tok.eof()) tok.next(); if (break_flag) curenv->do_break(); tok.next();}void title(){ if (curdiv == topdiv && topdiv->before_first_page) { handle_initial_title(); return; } node *part[3]; hunits part_width[3]; part[0] = part[1] = part[2] = 0; environment env(curenv); environment *oldenv = curenv; curenv = &env; read_title_parts(part, part_width); curenv = oldenv; curenv->size = env.size; curenv->prev_size = env.prev_size; curenv->requested_size = env.requested_size; curenv->prev_requested_size = env.prev_requested_size; curenv->char_height = env.char_height; curenv->char_slant = env.char_slant; curenv->fontno = env.fontno; curenv->prev_fontno = env.prev_fontno; node *n = 0; node *p = part[2]; while (p != 0) { node *tem = p; p = p->next; tem->next = n; n = tem; } hunits title_length(curenv->title_length); hunits f = title_length - part_width[1]; hunits f2 = f/2; n = new hmotion_node(f2 - part_width[2], n); p = part[1]; while (p != 0) { node *tem = p; p = p->next; tem->next = n; n = tem; } n = new hmotion_node(f - f2 - part_width[0], n); p = part[0]; while (p != 0) { node *tem = p; p = p->next; tem->next = n; n = tem; } curenv->output_title(n, !curenv->fill, curenv->vertical_spacing, curenv->line_spacing, title_length); curenv->hyphen_line_count = 0; tok.next();} void adjust(){ curenv->adjust_mode |= 1; if (has_arg()) { switch (tok.ch()) { case 'l': curenv->adjust_mode = ADJUST_LEFT; break; case 'r': curenv->adjust_mode = ADJUST_RIGHT; break; case 'c': curenv->adjust_mode = ADJUST_CENTER; break; case 'b': case 'n': curenv->adjust_mode = ADJUST_BOTH; break; default: int n; if (get_integer(&n)) { if (n < 0) warning(WARN_RANGE, "negative adjustment mode"); else if (n > 5) { curenv->adjust_mode = 5; warning(WARN_RANGE, "adjustment mode `%1' out of range", n); } else curenv->adjust_mode = n; } } } skip_line();}void no_adjust(){ curenv->adjust_mode &= ~1; skip_line();}void input_trap(){ curenv->input_trap_count = 0; int n; if (has_arg() && get_integer(&n)) { if (n <= 0) warning(WARN_RANGE, "number of lines for input trap must be greater than zero"); else { symbol s = get_name(1); if (!s.is_null()) { curenv->input_trap_count = n; curenv->input_trap = s; } } } skip_line();}/* tabs */// must not be R or C or L or a legitimate part of a number expressionconst char TAB_REPEAT_CHAR = 'T';struct tab { tab *next; hunits pos; tab_type type; tab(hunits, tab_type); enum { BLOCK = 1024 }; static tab *free_list; void *operator new(size_t); void operator delete(void *);};tab *tab::free_list = 0;void *tab::operator new(size_t n){ assert(n == sizeof(tab)); if (!free_list) { free_list = (tab *)new char[sizeof(tab)*BLOCK]; for (int i = 0; i < BLOCK - 1; i++) free_list[i].next = free_list + i + 1; free_list[BLOCK-1].next = 0; } tab *p = free_list; free_list = (tab *)(free_list->next); p->next = 0; return p;}#ifdef __GNUG__/* cfront can't cope with this. */inline#endifvoid tab::operator delete(void *p){ if (p) { ((tab *)p)->next = free_list; free_list = (tab *)p; }}tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t){}tab_stops::tab_stops(hunits distance, tab_type type) : initial_list(0){ repeated_list = new tab(distance, type);}tab_stops::~tab_stops(){ clear();}tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance){ hunits lastpos = 0; for (tab *tem = initial_list; tem && tem->pos <= curpos; tem = tem->next) lastpos = tem->pos; if (tem) { *distance = tem->pos - curpos; return tem->type; } if (repeated_list == 0) return TAB_NONE; hunits base = lastpos; for (;;) { for (tem = repeated_list; tem && tem->pos + base <= curpos; tem = tem->next) lastpos = tem->pos; if (tem) { *distance = tem->pos + base - curpos; return tem->type; } assert(lastpos > 0); base += lastpos; } return TAB_NONE;}const char *tab_stops::to_string(){ static char *buf = 0; static int buf_size = 0; // figure out a maximum on the amount of space we can need int count = 0; for (tab *p = initial_list; p; p = p->next) ++count; for (p = repeated_list; p; p = p->next) ++count; // (10 for digits + 1 for u + 1 for 'C' or 'R') + 2 for ' &' + 1 for '\0' int need = count*12 + 3; if (buf == 0 || need > buf_size) { if (buf) a_delete buf; buf_size = need; buf = new char[buf_size]; } char *ptr = buf; for (p = initial_list; p; p = p->next) { strcpy(ptr, itoa(p->pos.to_units())); ptr = strchr(ptr, '\0'); *ptr++ = 'u'; *ptr = '\0'; switch (p->type) { case TAB_LEFT: break; case TAB_RIGHT: *ptr++ = 'R'; break; case TAB_CENTER: *ptr++ = 'C'; break; case TAB_NONE: default: assert(0); } } if (repeated_list) *ptr++ = TAB_REPEAT_CHAR; for (p = repeated_list; p; p = p->next) { strcpy(ptr, itoa(p->pos.to_units())); ptr = strchr(ptr, '\0'); *ptr++ = 'u'; *ptr = '\0'; switch (p->type) { case TAB_LEFT: break; case TAB_RIGHT: *ptr++ = 'R'; break; case TAB_CENTER: *ptr++ = 'C'; break; case TAB_NONE: default: assert(0); } } *ptr++ = '\0'; return buf;}tab_stops::tab_stops() : initial_list(0), repeated_list(0){}tab_stops::tab_stops(const tab_stops &ts) : initial_list(0), repeated_list(0){ tab **p = &initial_list; tab *t = ts.initial_list; while (t) { *p = new tab(t->pos, t->type); t = t->next; p = &(*p)->next; } p = &repeated_list; t = ts.repeated_list; while (t) { *p = new tab(t->pos, t->type); t = t->next; p = &(*p)->next; }}void tab_stops::clear(){ while (initial_list) { tab *tem = initial_list; initial_list = initial_list->next; delete tem; } while (repeated_list) { tab *tem = repeated_list; repeated_list = repeated_list->next; delete tem; }}void tab_stops::add_tab(hunits pos, tab_type type, int repeated){ for (tab **p = repeated ? &repeated_list : &initial_list; *p; p = &(*p)->next) ; *p = new tab(pos, type);}void tab_stops::operator=(const tab_stops &ts){ clear(); tab **p = &initial_list; tab *t = ts.initial_list; while (t) { *p = new tab(t->pos, t->type); t = t->next; p = &(*p)->next; } p = &repeated_list; t = ts.repeated_list; while (t) { *p = new tab(t->pos, t->type); t = t->next; p = &(*p)->next; }} void set_tabs(){ hunits pos; hunits prev_pos = 0; int first = 1; int repeated = 0; tab_stops tabs; while (has_arg()) { if (tok.ch() == TAB_REPEAT_CHAR) { tok.next(); repeated = 1; prev_pos = 0; } if (!get_hunits(&pos, 'm', prev_pos)) break; tab_type type = TAB_LEFT; if (tok.ch() == 'C') { tok.next(); type = TAB_CENTER; } else if (tok.ch() == 'R') { tok.next(); type = TAB_RIGHT; } else if (tok.ch() == 'L') { tok.next(); } if (pos <= prev_pos && !first) warning(WARN_RANGE, "positions of tab stops must be strictly increasing"); else { tabs.add_tab(pos, type, repeated); prev_pos = pos; first = 0; } } curenv->tabs = tabs; skip_line();}const char *environment::get_tabs(){ return tabs.to_string();}#if 0tab_stops saved_tabs;void tabs_save(){ saved_tabs = curenv->tabs; skip_line();}void tabs_restore(){ curenv->tabs = saved_tabs; skip_line();}#endiftab_type environment::distance_to_next_tab(hunits *distance){ return curenv->tabs.distance_to_next_tab(get_input_line_position(), distance);}void field_characters(){ field_delimiter_char = get_optional_char(); if (field_delimiter_char) padding_indicator_char = get_optional_char(); else padding_indicator_char = 0; skip_line();}void environment::wrap_up_tab(){ if (!current_tab) return; if (line == 0) start_line(); hunits tab_amount; switch (current_tab) { case TAB_RIGHT: tab_amount = tab_distance - tab_width; line = make_tab_node(tab_amount, line); break; case TAB_CENTER: tab_amount = tab_distance - tab_width/2; line = make_tab_node(tab_amount, line); break; case TAB_NONE: case TAB_LEFT: default: assert(0); } width_total += tab_amount; width_total += tab_width; if (current_field) { if (tab_precedes_field) { pre_field_width += tab_amount; tab_precedes_field = 0; } field_distance -= tab_amount; field_spaces += tab_field_spaces; } if (tab_contents != 0) { for (node *tem = tab_contents; tem->next != 0; tem = tem->next) ; tem->next = line; line = tab_contents; } tab_field_spaces = 0; tab_contents = 0; tab_width = H0; tab_distance = H0; current_tab = TAB_NONE;}node *environment::make_tab_node(hunits d, node *next){ if (leader_node != 0 && d < 0) { error("motion generated by leader cannot be negative"); delete leader_node; leader_node = 0; } if (!leader_node) return new hmotion_node(d, next); node *n = new hline_node(d, leader_node, next); leader_node = 0; return n;}void environment::handle_tab(int is_leader){ hunits d; if (current_tab) wrap_up_tab(); charinfo *ci = is_leader ? leader_char : tab_char; delete leader_node; leader_node = ci ? make_char_node(ci) : 0; tab_type t = distance_to_next_tab(&d); switch (t) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -