📄 table.cc
字号:
text_stuff::text_stuff(const string &s, int r, const char *fn, int ln): contents(s), stuff(r), filename(fn), lineno(ln){}text_stuff::~text_stuff(){}void text_stuff::print(table *){ printed = 1; prints(".cp \\n(" COMPATIBLE_REG "\n"); set_troff_location(filename, lineno); prints(contents); prints(".cp 0\n"); location_force_filename = 1; // it might have been a .lf command}struct single_hline_stuff : stuff { single_hline_stuff(int r); void print(table *); int is_single_line();};single_hline_stuff::single_hline_stuff(int r) : stuff(r){}void single_hline_stuff::print(table *tbl){ printed = 1; tbl->print_single_hline(row);}int single_hline_stuff::is_single_line(){ return 1;}struct double_hline_stuff : stuff { double_hline_stuff(int r); void print(table *); int is_double_line();};double_hline_stuff::double_hline_stuff(int r) : stuff(r){}void double_hline_stuff::print(table *tbl){ printed = 1; tbl->print_double_hline(row);}int double_hline_stuff::is_double_line(){ return 1;}struct vertical_rule { vertical_rule *next; short start_row; short end_row; short col; char is_double; string top_adjust; string bot_adjust; vertical_rule(int sr, int er, int c, int dbl, vertical_rule *); ~vertical_rule(); void contribute_to_bottom_macro(table *); void print();};vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p): start_row(sr), end_row(er), col(c), is_double(dbl), next(p){}vertical_rule::~vertical_rule(){}void vertical_rule::contribute_to_bottom_macro(table *tbl){ printfs(".if \\n[" CURRENT_ROW_REG "]>=%1", as_string(start_row)); if (end_row != tbl->get_nrows() - 1) printfs("&(\\n[" CURRENT_ROW_REG "]<%1)", as_string(end_row)); prints(" \\{"); printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n", as_string(start_row), row_top_reg(start_row)); const char *offset_table[3]; if (is_double) { offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; offset_table[2] = 0; } else { offset_table[0] = ""; offset_table[1] = 0; } for (const char **offsetp = offset_table; *offsetp; offsetp++) { prints(".sp -1\n" "\\v'" BODY_DEPTH); if (!bot_adjust.empty()) printfs("+%1", bot_adjust); prints("'"); printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v", column_divide_reg(col), row_top_reg(start_row), *offsetp); if (!bot_adjust.empty()) printfs("-(%1)", bot_adjust); // don't perform the top adjustment if the top is actually #T if (!top_adjust.empty()) printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))", top_adjust, as_string(start_row)); prints("'\\s0\n"); } prints(".\\}\n");}void vertical_rule::print(){ printfs("\\*[" TRANSPARENT_STRING_NAME "]" ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] " ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n", as_string(start_row), row_top_reg(start_row)); const char *offset_table[3]; if (is_double) { offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; offset_table[2] = 0; } else { offset_table[0] = ""; offset_table[1] = 0; } for (const char **offsetp = offset_table; *offsetp; offsetp++) { prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n" "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH); if (!bot_adjust.empty()) printfs("+%1", bot_adjust); prints("'"); printfs("\\h'\\n[%1]u%3'" "\\s[\\n[" LINESIZE_REG "]]" "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v", column_divide_reg(col), row_top_reg(start_row), *offsetp); if (!bot_adjust.empty()) printfs("-(%1)", bot_adjust); // don't perform the top adjustment if the top is actually #T if (!top_adjust.empty()) printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "]))", top_adjust, as_string(start_row)); prints("'" "\\s0\n"); }}table::table(int nc, unsigned f, int ls, char dpc): ncolumns(nc), flags(f), linesize(ls), decimal_point_char(dpc), nrows(0), allocated_rows(0), entry(0), entry_list(0), left_separation(0), right_separation(0), stuff_list(0), vline(0), vrule_list(0), row_is_all_lines(0), span_list(0){ minimum_width = new string[ncolumns]; column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; equal = new char[ncolumns]; int i; for (i = 0; i < ncolumns; i++) equal[i] = 0; for (i = 0; i < ncolumns-1; i++) column_separation[i] = DEFAULT_COLUMN_SEPARATION; delim[0] = delim[1] = '\0';}table::~table(){ for (int i = 0; i < nrows; i++) { a_delete entry[i]; a_delete vline[i]; } a_delete entry; a_delete vline; while (entry_list) { table_entry *tem = entry_list; entry_list = entry_list->next; delete tem; } ad_delete(ncolumns) minimum_width; a_delete column_separation; a_delete equal; while (stuff_list) { stuff *tem = stuff_list; stuff_list = stuff_list->next; delete tem; } while (vrule_list) { vertical_rule *tem = vrule_list; vrule_list = vrule_list->next; delete tem; } a_delete row_is_all_lines; while (span_list) { horizontal_span *tem = span_list; span_list = span_list->next; delete tem; }}void table::set_delim(char c1, char c2){ delim[0] = c1; delim[1] = c2;}void table::set_minimum_width(int c, const string &w){ assert(c >= 0 && c < ncolumns); minimum_width[c] = w;}void table::set_column_separation(int c, int n){ assert(c >= 0 && c < ncolumns - 1); column_separation[c] = n;}void table::set_equal_column(int c){ assert(c >= 0 && c < ncolumns); equal[c] = 1;}void table::add_stuff(stuff *p){ for (stuff **pp = &stuff_list; *pp; pp = &(*pp)->next) ; *pp = p;}void table::add_text_line(int r, const string &s, const char *filename, int lineno){ add_stuff(new text_stuff(s, r, filename, lineno));}void table::add_single_hline(int r){ add_stuff(new single_hline_stuff(r));}void table::add_double_hline(int r){ add_stuff(new double_hline_stuff(r));}void table::allocate(int r){ if (r >= nrows) { typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug if (r >= allocated_rows) { if (allocated_rows == 0) { allocated_rows = 16; if (allocated_rows <= r) allocated_rows = r + 1; entry = new PPtable_entry[allocated_rows]; vline = new char*[allocated_rows]; } else { table_entry ***old_entry = entry; int old_allocated_rows = allocated_rows; allocated_rows *= 2; if (allocated_rows <= r) allocated_rows = r + 1; entry = new PPtable_entry[allocated_rows]; memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows); a_delete old_entry; char **old_vline = vline; vline = new char*[allocated_rows]; memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows); a_delete old_vline; } } assert(allocated_rows > r); while (nrows <= r) { entry[nrows] = new table_entry*[ncolumns]; for (int i = 0; i < ncolumns; i++) entry[nrows][i] = 0; vline[nrows] = new char[ncolumns+1]; for (i = 0; i < ncolumns+1; i++) vline[nrows][i] = 0; nrows++; } }}void table::do_hspan(int r, int c){ assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); if (c == 0) { error("first column cannot be horizontally spanned"); return; } table_entry *e = entry[r][c]; if (e) { assert(e->start_row <= r && r <= e->end_row && e->start_col <= c && c <= e->end_col && e->end_row - e->start_row > 0 && e->end_col - e->start_col > 0); return; } e = entry[r][c-1]; // e can be 0 if we had an empty entry or an error if (e == 0) return; if (e->start_row != r) { /* l l ^ s */ error("impossible horizontal span at row %1, column %2", r + 1, c + 1); } else { e->end_col = c; entry[r][c] = e; }}void table::do_vspan(int r, int c){ assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); if (r == 0) { error("first row cannot be vertically spanned"); return; } table_entry *e = entry[r][c]; if (e) { assert(e->start_row <= r && r <= e->end_row && e->start_col <= c && c <= e->end_col && e->end_row - e->start_row > 0 && e->end_col - e->start_col > 0); return; } e = entry[r-1][c]; // e can be 0 if we had an empty entry or an error if (e == 0) return; if (e->start_col != c) { /* l s l ^ */ error("impossible vertical span at row %1, column %2", r + 1, c + 1); } else { for (int i = c; i <= e->end_col; i++) { assert(entry[r][i] == 0); entry[r][i] = e; } e->end_row = r; }}int find_decimal_point(const char *s, char decimal_point_char, const char *delim){ if (s == 0 || *s == '\0') return -1; const char *p; int in_delim = 0; // is p within eqn delimiters? // tbl recognises \& even within eqn delimiters; I don't for (p = s; *p; p++) if (in_delim) { if (*p == delim[1]) in_delim = 0; } else if (*p == delim[0]) in_delim = 1; else if (p[0] == '\\' && p[1] == '&') return p - s; int possible_pos = -1; in_delim = 0; for (p = s; *p; p++) if (in_delim) { if (*p == delim[1]) in_delim = 0; } else if (*p == delim[0]) in_delim = 1; else if (p[0] == decimal_point_char && csdigit(p[1])) possible_pos = p - s; if (possible_pos >= 0) return possible_pos; in_delim = 0; for (p = s; *p; p++) if (in_delim) { if (*p == delim[1]) in_delim = 0; } else if (*p == delim[0]) in_delim = 1; else if (csdigit(*p)) possible_pos = p + 1 - s; return possible_pos;}void table::add_entry(int r, int c, const string &str, const entry_format *f, const char *fn, int ln){ allocate(r); table_entry *e = 0; if (str == "\\_") { e = new short_line_entry(f); } else if (str == "\\=") { e = new short_double_line_entry(f); } else if (str == "_") { single_line_entry *lefte; if (c > 0 && entry[r][c-1] != 0 && (lefte = entry[r][c-1]->to_single_line_entry()) != 0 && lefte->start_row == r && lefte->mod->stagger == f->stagger) { lefte->end_col = c; entry[r][c] = lefte; } else e = new single_line_entry(f); } else if (str == "=") { double_line_entry *lefte; if (c > 0 && entry[r][c-1] != 0 && (lefte = entry[r][c-1]->to_double_line_entry()) != 0 && lefte->start_row == r && lefte->mod->stagger == f->stagger) { lefte->end_col = c; entry[r][c] = lefte; } else e = new double_line_entry(f); } else if (str == "\\^") { do_vspan(r, c); } else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') { if (str.search('\n') >= 0) error_with_file_and_line(fn, ln, "bad repeated character"); else { char *s = str.substring(2, str.length() - 2).extract(); e = new repeated_char_entry(s, f); } } else { int is_block = str.search('\n') >= 0; char *s; switch (f->type) { case FORMAT_SPAN: assert(str.empty()); do_hspan(r, c); break; case FORMAT_LEFT: if (!str.empty()) { s = str.extract(); if (is_block) e = new left_block_entry(s, f); else e = new left_text_entry(s, f); } else e = new empty_entry(f); break; case FORMAT_CENTER: if (!str.empty()) { s = str.extract(); if (is_block) e = new center_block_entry(s, f); else e = new center_text_entry(s, f); } else e = new empty_entry(f); break; case FORMAT_RIGHT: if (!str.empty()) { s = str.extract(); if (is_block) e = new right_block_entry(s, f); else e = new right_text_entry(s, f); } else e = new empty_entry(f); break; case FORMAT_NUMERIC: if (!str.empty()) { s = str.extract(); if (is_block) { error_with_file_and_line(fn, ln, "can't have numeric text block"); e = new left_block_entry(s, f); } else { int pos = find_decimal_point(s, decimal_point_char, delim); if (pos < 0) e = new center_text_entry(s, f); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -