summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwl <wl>2008-11-16 17:22:21 +0000
committerwl <wl>2008-11-16 17:22:21 +0000
commit53d40d589acd73b6f2a8d90d33e42819833abf5a (patch)
treeb6f919a37f3672298c111ec088d230b372060e0d
parent4653e270802862dccbe36bf7d56387290f94ac47 (diff)
downloadgroff-53d40d589acd73b6f2a8d90d33e42819833abf5a.tar.gz
Implement `x' specifier for expanded columns. Contrary to old DWB
tbl, more than a single `x' specifier can be used. At the same time, remove most of the code from change 2007-02-09 which collides with the new implementation. * src/preproc/tbl/main.cpp (format): Add `expand' array. (format::format, format::~format): Updated. (input_entry_format): Add `expand' field. (input_entry_format::input_entry_format): Updated. (input_entry_format::debug_print): Handle `expand'. (process_format): Handle `x' specifier. (process_data): Updated. * src/preproc/tbl/table.cpp (AVAILABLE_REG, COLCOUNT_REG): Remove. (EXPAND_REG): New macro. (table_entry::divert, block_entry::divert, alphabetic_block_entry::divert): Add parameter to control whether expanded columns shall be handled. (block_entry::do_width): Remove. (block_entry::do_divert): Add parameter to control whether expanded columns shall be handled. Treat expanded columns like columns with a minimum width. Remove `experimental' code. (table::table, table::~table, table::allocate): Updated. (table::set_expand_column): New function. (table::count_block_columns): Replace with... (table::count_expand_columns): This function. (table::divide_span): Handle expanded columns the same as equal columns. (table::sum_columns): Add parameter to control whether expanded columns shall be handled. (table::compute_available_block_width): Replace with... (table::compute_expand_width): This function. (table::compute_total_separation): New function, taking code from `compute_separation_factor'. (table::compute_separation_factor): Simpler code. The check for the `EXPAND' flag has been moved to the caller. (table::compute_widths): Add `top-level' changes to handle expanded blocks. * src/preproc/tbl/table.h (table): New field `total_separation'. Remove `blockflag' array. Add `expand' array. Update member function declarations. * src/preproc/tbl/tbl.man: Document `x' specifier. Expand documentation to cover all aspects of Lesk's tbl reference. * NEWS: Document `x' specifier.
-rw-r--r--ChangeLog63
-rw-r--r--NEWS12
-rw-r--r--src/preproc/tbl/main.cpp50
-rw-r--r--src/preproc/tbl/table.cpp217
-rw-r--r--src/preproc/tbl/table.h11
-rw-r--r--src/preproc/tbl/tbl.man327
6 files changed, 485 insertions, 195 deletions
diff --git a/ChangeLog b/ChangeLog
index 6ca15b31..1529f0a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,60 @@
+2008-11-12 Werner LEMBERG <wl@gnu.org>
+
+ Implement `x' specifier for expanded columns. Contrary to old DWB
+ tbl, more than a single `x' specifier can be used. At the same
+ time, remove most of the code from change 2007-02-09 which collides
+ with the new implementation.
+
+ * src/preproc/tbl/main.cpp (format): Add `expand' array.
+ (format::format, format::~format): Updated.
+ (input_entry_format): Add `expand' field.
+ (input_entry_format::input_entry_format): Updated.
+ (input_entry_format::debug_print): Handle `expand'.
+ (process_format): Handle `x' specifier.
+ (process_data): Updated.
+
+ * src/preproc/tbl/table.cpp (AVAILABLE_REG, COLCOUNT_REG): Remove.
+ (EXPAND_REG): New macro.
+ (table_entry::divert, block_entry::divert,
+ alphabetic_block_entry::divert): Add parameter to control whether
+ expanded columns shall be handled.
+ (block_entry::do_width): Remove.
+ (block_entry::do_divert): Add parameter to control whether expanded
+ columns shall be handled.
+ Treat expanded columns like columns with a minimum width.
+ Remove `experimental' code.
+ (table::table, table::~table, table::allocate): Updated.
+ (table::set_expand_column): New function.
+ (table::count_block_columns): Replace with...
+ (table::count_expand_columns): This function.
+ (table::divide_span): Handle expanded columns the same as equal
+ columns.
+ (table::sum_columns): Add parameter to control whether expanded
+ columns shall be handled.
+ (table::compute_available_block_width): Replace with...
+ (table::compute_expand_width): This function.
+ (table::compute_total_separation): New function, taking code from
+ `compute_separation_factor'.
+ (table::compute_separation_factor): Simpler code. The check for the
+ `EXPAND' flag has been moved to the caller.
+ (table::compute_widths): Add `top-level' changes to handle expanded
+ blocks.
+
+ * src/preproc/tbl/table.h (table): New field `total_separation'.
+ Remove `blockflag' array.
+ Add `expand' array.
+ Update member function declarations.
+
+ * src/preproc/tbl/tbl.man: Document `x' specifier.
+ Expand documentation to cover all aspects of Lesk's tbl reference.
+
+ * NEWS: Document `x' specifier.
+
+2008-11-08 Werner LEMBERG <wl@gnu.org>
+
+ * src/preproc/tbl/tbl.man: Restructuring.
+ Improve text block documentation.
+
2008-11-07 Werner LEMBERG <wl@gnu.org>
* src/preproc/tbl/table.cpp (table::compute_widths): Use default
@@ -542,7 +599,7 @@
* src/devices/grohtml/html-table.cpp: Add support for XHTML 1.1.
(html_table:: emit_colspan, html_table::emit_td): New methods.
- (html_table::emit_col): Use html_table::emit_td.
+ (html_table::emit_col): Use html_table::emit_td.
(html_table::emit_table_header): Use html_table::emit_colspan if
dialect xhtml is specified.
(html_table::finish_row): Updated.
@@ -616,7 +673,7 @@
* src/roff/groff/groff.cpp (possible_command): New method
`clear_name'.
- (main): Set eflag if -e is present on command line.
+ (main): Set eflag if -e is present on command line.
Set is_xhtml if -Txhtml is present.
Pass `-x x' to the HTML pre and post processors.
Pass `-e' to the HTML pre processor if required.
@@ -5293,7 +5350,7 @@ Version 1.19.1 released
(get_printcode, show_symset): New functions.
(main): Remove `debug_flag'.
(output_charset): Use `show_symset'.
- (dump_symbols): Use `show_symset'.
+ (dump_symbols): Use `show_symset'.
Print symsets for all glyphs.
(read_map): Actually call `unicode_to_ucode_make' but this time
correctly.
diff --git a/NEWS b/NEWS
index e7305f1d..8a2badbd 100644
--- a/NEWS
+++ b/NEWS
@@ -96,6 +96,16 @@ o Heinz-Jürgen Örtel contributed code for two new keywords, `xslanted' and
`yslanted', which can change the shape of boxes into arbitrary
parallelograms.
+Tbl
+---
+
+o Latest versions of DWB tbl introduced an `x' column specifier for a single
+ column expanded to the line width. GNU tbl has now been extended to
+ support even multiple `x' specifiers within a table.
+
+o To avoid collision with the new `x' specifier, a block formatting macro
+ must now be selected with specifier letter `m'.
+
Eqn
---
@@ -440,7 +450,7 @@ o Dashed and dotted ellipses have been implemented.
Tbl
---
-o New key character `x' to make tbl call a user-defined macro on a table
+o New specifier `x' to make tbl call a user-defined macro on a table
cell. Patch by Heinz-Jürgen Oertel <hj.oertel@surfeu.de>.
Grap2graph
diff --git a/src/preproc/tbl/main.cpp b/src/preproc/tbl/main.cpp
index 5a8f08ce..74d0356d 100644
--- a/src/preproc/tbl/main.cpp
+++ b/src/preproc/tbl/main.cpp
@@ -623,6 +623,7 @@ struct format {
int *separation;
string *width;
char *equal;
+ char *expand;
entry_format **entry;
char **vline;
@@ -639,8 +640,11 @@ format::format(int nr, int nc) : nrows(nr), ncolumns(nc)
separation[i] = -1;
width = new string[ncolumns];
equal = new char[ncolumns];
- for (i = 0; i < ncolumns; i++)
+ expand = new char[ncolumns];
+ for (i = 0; i < ncolumns; i++) {
equal[i] = 0;
+ expand[i] = 0;
+ }
entry = new entry_format *[nrows];
for (i = 0; i < nrows; i++)
entry[i] = new entry_format[ncolumns];
@@ -680,6 +684,7 @@ format::~format()
a_delete separation;
ad_delete(ncolumns) width;
a_delete equal;
+ a_delete expand;
for (int i = 0; i < nrows; i++) {
a_delete vline[i];
ad_delete(ncolumns) entry[i];
@@ -696,6 +701,7 @@ struct input_entry_format : public entry_format {
int pre_vline;
int last_column;
int equal;
+ int expand;
input_entry_format(format_type, input_entry_format * = 0);
~input_entry_format();
void debug_print();
@@ -709,6 +715,7 @@ input_entry_format::input_entry_format(format_type t, input_entry_format *p)
vline = 0;
pre_vline = 0;
equal = 0;
+ expand = 0;
}
input_entry_format::~input_entry_format()
@@ -738,6 +745,8 @@ void input_entry_format::debug_print()
}
if (equal)
putc('e', stderr);
+ if (expand)
+ putc('x', stderr);
if (separation >= 0)
fprintf(stderr, "%d", separation);
for (i = 0; i < vline; i++)
@@ -754,6 +763,7 @@ format *process_format(table_input &in, options *opt,
format *current_format = 0)
{
input_entry_format *list = 0;
+ int have_expand = 0;
int c = in.get();
for (;;) {
int pre_vline = 0;
@@ -873,7 +883,9 @@ format *process_format(table_input &in, options *opt,
case 'e':
case 'E':
c = in.get();
- list->equal++;
+ list->equal = 1;
+ // `e' and `x' are mutually exclusive
+ list->expand = 0;
break;
case 'f':
case 'F':
@@ -1047,6 +1059,17 @@ format *process_format(table_input &in, options *opt,
} while (c != EOF && csdigit(c));
}
}
+ // `w' and `x' are mutually exclusive
+ list->expand = 0;
+ break;
+ case 'x':
+ case 'X':
+ c = in.get();
+ list->expand = 1;
+ // `x' and `e' are mutually exclusive
+ list->equal = 0;
+ // `x' and `w' are mutually exclusive
+ list->width = "";
break;
case 'z':
case 'Z':
@@ -1143,7 +1166,7 @@ format *process_format(table_input &in, options *opt,
col = 0;
for (tem = list; tem; tem = tem->next) {
f->entry[row][col] = *tem;
- if (col < ncolumns-1) {
+ if (col < ncolumns - 1) {
// use the greatest separation
if (tem->separation > f->separation[col]) {
if (current_format)
@@ -1160,17 +1183,25 @@ format *process_format(table_input &in, options *opt,
else
f->equal[col] = 1;
}
+ if (tem->expand && !f->expand[col]) {
+ if (current_format)
+ error("cannot change which columns are expanded in continued format");
+ else {
+ f->expand[col] = 1;
+ have_expand = 1;
+ }
+ }
if (!tem->width.empty()) {
// use the last width
if (!f->width[col].empty() && f->width[col] != tem->width)
- error("multiple widths for column %1", col+1);
+ error("multiple widths for column %1", col + 1);
f->width[col] = tem->width;
}
if (tem->pre_vline) {
assert(col == 0);
f->vline[row][col] = tem->pre_vline;
}
- f->vline[row][col+1] = tem->vline;
+ f->vline[row][col + 1] = tem->vline;
if (tem->last_column) {
row++;
col = 0;
@@ -1180,7 +1211,7 @@ format *process_format(table_input &in, options *opt,
}
free_input_entry_format_list(list);
for (col = 0; col < ncolumns; col++) {
- entry_format *e = f->entry[f->nrows-1] + col;
+ entry_format *e = f->entry[f->nrows - 1] + col;
if (e->type != FORMAT_HLINE
&& e->type != FORMAT_DOUBLE_HLINE
&& e->type != FORMAT_SPAN)
@@ -1191,6 +1222,10 @@ format *process_format(table_input &in, options *opt,
delete f;
return 0;
}
+ if (have_expand && (opt->flags & table::EXPAND)) {
+ error("ignoring global `expand' option because of `x' specifiers");
+ opt->flags &= ~table::EXPAND;
+ }
return f;
}
@@ -1491,6 +1526,9 @@ table *process_data(table_input &in, format *f, options *opt)
for (i = 0; i < ncolumns; i++)
if (f->equal[i])
tbl->set_equal_column(i);
+ for (i = 0; i < ncolumns; i++)
+ if (f->expand[i])
+ tbl->set_expand_column(i);
return tbl;
}
diff --git a/src/preproc/tbl/table.cpp b/src/preproc/tbl/table.cpp
index 099b4a5e..1fd2c6ba 100644
--- a/src/preproc/tbl/table.cpp
+++ b/src/preproc/tbl/table.cpp
@@ -63,8 +63,7 @@ const int DEFAULT_COLUMN_SEPARATION = 3;
// this must be one character
#define COMPATIBLE_REG PREFIX "c"
-#define AVAILABLE_REG PREFIX "avail"
-#define COLCOUNT_REG PREFIX "ccount"
+#define EXPAND_REG PREFIX "expand"
#define LEADER_REG PREFIX LEADER
@@ -156,7 +155,7 @@ public:
void set_location();
table_entry(const table *, const entry_modifier *);
virtual ~table_entry();
- virtual int divert(int, const string *, int *);
+ virtual int divert(int, const string *, int *, int);
virtual void do_width();
virtual void do_depth();
virtual void print() = 0;
@@ -294,12 +293,11 @@ public:
class block_entry : public table_entry {
char *contents;
protected:
- void do_divert(int, int, const string *, int *);
+ void do_divert(int, int, const string *, int *, int);
public:
block_entry(const table *, const entry_modifier *, char *);
~block_entry();
- int divert(int, const string *, int *);
- void do_width();
+ int divert(int, const string *, int *, int);
void do_depth();
void position_vertically();
void print() = 0;
@@ -327,7 +325,7 @@ class alphabetic_block_entry : public block_entry {
public:
alphabetic_block_entry(const table *, const entry_modifier *, char *);
void print();
- int divert(int, const string *, int *);
+ int divert(int, const string *, int *, int);
};
table_entry::table_entry(const table *p, const entry_modifier *m)
@@ -340,7 +338,7 @@ table_entry::~table_entry()
{
}
-int table_entry::divert(int, const string *, int *)
+int table_entry::divert(int, const string *, int *, int)
{
return 0;
}
@@ -664,22 +662,33 @@ void block_entry::position_vertically()
prints(".sp -.5v\n");
}
-int block_entry::divert(int ncols, const string *mw, int *sep)
+int block_entry::divert(int ncols, const string *mw, int *sep, int do_expand)
{
- do_divert(0, ncols, mw, sep);
+ do_divert(0, ncols, mw, sep, do_expand);
return 1;
}
void block_entry::do_divert(int alphabetic, int ncols, const string *mw,
- int *sep)
+ int *sep, int do_expand)
{
+ int i;
+ for (i = start_col; i <= end_col; i++)
+ if (parent->expand[i])
+ break;
+ if (i > end_col) {
+ if (do_expand)
+ return;
+ }
+ else {
+ if (!do_expand)
+ return;
+ }
printfs(".di %1\n", block_diversion_name(start_row, start_col));
prints(".if \\n[" SAVED_FILL_REG "] .fi\n"
".in 0\n");
prints(".ll ");
- int i;
for (i = start_col; i <= end_col; i++)
- if (mw[i].empty())
+ if (mw[i].empty() && !parent->expand[i])
break;
if (i > end_col) {
// Every column spanned by this entry has a minimum width.
@@ -689,24 +698,20 @@ void block_entry::do_divert(int alphabetic, int ncols, const string *mw,
printfs("+%1n", as_string(sep[j - 1]));
prints('+');
}
- printfs("(n;%1)", mw[j]);
+ if (parent->expand[j])
+ prints("\\n[" EXPAND_REG "]u");
+ else
+ printfs("(n;%1)", mw[j]);
}
printfs(">?\\n[%1]u", span_width_reg(start_col, end_col));
}
else
- if (parent->flags & table::EXPERIMENTAL)
- // Each column containing a block entry gets 1/n of the remaining
- // available line width, where n is the number of columns with block
- // entries.
- printfs("(u;\\n[%1]+(\\n[" AVAILABLE_REG "]/\\n[" COLCOUNT_REG "]))",
- span_width_reg(start_col, end_col));
- else
- // Assign each column with a block entry 1/(n+1) of the line
- // width, where n is the column count.
- printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))",
- span_width_reg(start_col, end_col),
- as_string(end_col - start_col + 1),
- as_string(ncols + 1));
+ // Assign each column with a block entry 1/(n+1) of the line
+ // width, where n is the column count.
+ printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))",
+ span_width_reg(start_col, end_col),
+ as_string(end_col - start_col + 1),
+ as_string(ncols + 1));
if (alphabetic)
prints("-2n");
prints("\n");
@@ -735,12 +740,6 @@ void block_entry::do_divert(int alphabetic, int ncols, const string *mw,
location_force_filename = 1;
}
-void block_entry::do_width()
-{
- for (int i = start_col; i <= end_col; i++)
- parent->blockflag[i] = (char)1;
-}
-
void block_entry::do_depth()
{
printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n",
@@ -800,9 +799,10 @@ alphabetic_block_entry::alphabetic_block_entry(const table *p,
{
}
-int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep)
+int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep,
+ int do_expand)
{
- do_divert(1, ncols, mw, sep);
+ do_divert(1, ncols, mw, sep, do_expand);
return 1;
}
@@ -1231,15 +1231,18 @@ table::table(int nc, unsigned f, int ls, char dpc)
vrule_list(0), stuff_list(0), span_list(0),
entry_list(0), entry_list_tailp(&entry_list), entry(0),
vline(0), row_is_all_lines(0), left_separation(0), right_separation(0),
- allocated_rows(0), blockflag(0), flags(f)
+ total_separation(0), allocated_rows(0), flags(f)
{
minimum_width = new string[ncolumns];
column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0;
equal = new char[ncolumns];
+ expand = new char[ncolumns];
int i;
- for (i = 0; i < ncolumns; i++)
+ for (i = 0; i < ncolumns; i++) {
equal[i] = 0;
- for (i = 0; i < ncolumns-1; i++)
+ expand[i] = 0;
+ }
+ for (i = 0; i < ncolumns - 1; i++)
column_separation[i] = DEFAULT_COLUMN_SEPARATION;
delim[0] = delim[1] = '\0';
}
@@ -1252,7 +1255,6 @@ table::~table()
}
a_delete entry;
a_delete vline;
- a_delete blockflag;
while (entry_list) {
table_entry *tem = entry_list;
entry_list = entry_list->next;
@@ -1261,6 +1263,7 @@ table::~table()
ad_delete(ncolumns) minimum_width;
a_delete column_separation;
a_delete equal;
+ a_delete expand;
while (stuff_list) {
stuff *tem = stuff_list;
stuff_list = stuff_list->next;
@@ -1303,6 +1306,12 @@ void table::set_equal_column(int c)
equal[c] = 1;
}
+void table::set_expand_column(int c)
+{
+ assert(c >= 0 && c < ncolumns);
+ expand[c] = 1;
+}
+
void table::add_stuff(stuff *p)
{
stuff **pp;
@@ -1338,9 +1347,6 @@ void table::allocate(int r)
allocated_rows = r + 1;
entry = new PPtable_entry[allocated_rows];
vline = new char*[allocated_rows];
- blockflag = new char[allocated_rows];
- for (int i = 0; i < allocated_rows; i++)
- blockflag[i] = 0;
}
else {
table_entry ***old_entry = entry;
@@ -1355,12 +1361,6 @@ void table::allocate(int r)
vline = new char*[allocated_rows];
memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows);
a_delete old_vline;
- char *old_blockflag = blockflag;
- blockflag = new char[allocated_rows];
- memcpy(blockflag, old_blockflag, sizeof(char)*old_allocated_rows);
- for (int i = old_allocated_rows; i < allocated_rows; i++)
- blockflag[i] = 0;
- a_delete old_blockflag;
}
}
assert(allocated_rows > r);
@@ -1727,11 +1727,11 @@ void table::determine_row_type()
}
}
-int table::count_block_columns()
+int table::count_expand_columns()
{
int count = 0;
for (int i = 0; i < ncolumns; i++)
- if (blockflag[i])
+ if (expand[i])
count++;
return count;
}
@@ -1990,7 +1990,7 @@ void table::divide_span(int start_col, int end_col)
span_width_reg(i, i));
int equal_flag = 0;
for (i = start_col; i <= end_col && !equal_flag; i++)
- if (equal[i])
+ if (equal[i] || expand[i])
equal_flag = 1;
if (equal_flag) {
for (i = 0; i < ncolumns; i++)
@@ -2001,13 +2001,25 @@ void table::divide_span(int start_col, int end_col)
prints(".\\}\n");
}
-void table::sum_columns(int start_col, int end_col)
+void table::sum_columns(int start_col, int end_col, int do_expand)
{
assert(end_col > start_col);
+ int i;
+ for (i = start_col; i <= end_col; i++)
+ if (expand[i])
+ break;
+ if (i > end_col) {
+ if (do_expand)
+ return;
+ }
+ else {
+ if (!do_expand)
+ return;
+ }
printfs(".nr %1 \\n[%2]",
span_width_reg(start_col, end_col),
span_width_reg(start_col, start_col));
- for (int i = start_col + 1; i <= end_col; i++)
+ for (i = start_col + 1; i <= end_col; i++)
printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]",
as_string(column_separation[i - 1]),
span_width_reg(i, i));
@@ -2054,22 +2066,30 @@ void table::build_span_list()
}
}
-// Compute remaining length for block columns.
-
-void table::compute_available_block_width()
+void table::compute_expand_width()
{
- printfs(".nr " COLCOUNT_REG " %1\n", as_string(count_block_columns()));
- prints(".nr " AVAILABLE_REG " \\n[.l]-\\n[.i]");
- for (int i = 0; i < ncolumns; i++)
- printfs("-\\n[%1]", span_width_reg(i, i));
+ int i;
+ int colcount = count_expand_columns();
+ prints(".nr " EXPAND_REG " \\n[.l]-\\n[.i]");
+ for (i = 0; i < ncolumns; i++)
+ if (!expand[i])
+ printfs("-\\n[%1]", span_width_reg(i, i));
+ if (total_separation)
+ printfs("-%1n", as_string(total_separation));
prints("\n");
- prints(".if \\n[" AVAILABLE_REG "]<0 \\{"
+ prints(".if \\n[" EXPAND_REG "]<0 \\{"
".tm warning: page \\n%: table wider than line width\n"
- ".nr " AVAILABLE_REG " 0\n"
+ ".nr " EXPAND_REG " 0\n"
".\\}\n");
+ if (colcount > 1)
+ printfs(".nr " EXPAND_REG " \\n[" EXPAND_REG "]/%1\n",
+ as_string(colcount));
+ for (i = 0; i < ncolumns; i++)
+ if (expand[i])
+ printfs(".nr %1 \\n[%1]>?\\n[" EXPAND_REG "]\n", span_width_reg(i, i));
}
-void table::compute_separation_factor()
+void table::compute_total_separation()
{
if (flags & (ALLBOX | BOX | DOUBLEBOX))
left_separation = right_separation = 1;
@@ -2081,25 +2101,25 @@ void table::compute_separation_factor()
right_separation = 1;
}
}
- if (flags & EXPAND) {
- int total_sep = left_separation + right_separation;
- int i;
- for (i = 0; i < ncolumns - 1; i++)
- total_sep += column_separation[i];
- if (total_sep != 0) {
- // Don't let the separation factor be negative.
- prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]");
- for (i = 0; i < ncolumns; i++)
- printfs("-\\n[%1]", span_width_reg(i, i));
- printfs("/%1\n", as_string(total_sep));
- prints(".ie \\n[" SEPARATION_FACTOR_REG "]<=0 \\{"
- ".tm warning: page \\n%: column separation set to zero\n"
- ".nr " SEPARATION_FACTOR_REG " 0\n"
- ".\\}\n"
- ".el .if \\n[" SEPARATION_FACTOR_REG "]<1n "
- ".tm warning: page \\n%: table squeezed horizontally to fit line length\n");
- }
- }
+ total_separation = left_separation + right_separation;
+ int i;
+ for (i = 0; i < ncolumns - 1; i++)
+ total_separation += column_separation[i];
+}
+
+void table::compute_separation_factor()
+{
+ // Don't let the separation factor be negative.
+ prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]");
+ for (int i = 0; i < ncolumns; i++)
+ printfs("-\\n[%1]", span_width_reg(i, i));
+ printfs("/%1\n", as_string(total_separation));
+ prints(".ie \\n[" SEPARATION_FACTOR_REG "]<=0 \\{"
+ ".tm warning: page \\n%: column separation set to zero\n"
+ ".nr " SEPARATION_FACTOR_REG " 0\n"
+ ".\\}\n"
+ ".el .if \\n[" SEPARATION_FACTOR_REG "]<1n "
+ ".tm warning: page \\n%: table squeezed horizontally to fit line length\n");
}
void table::compute_column_positions()
@@ -2190,30 +2210,47 @@ void table::compute_widths()
// This function might increase the width of some columns, too.
for (p = span_list; p; p = p->next)
divide_span(p->start_col, p->end_col);
+ compute_total_separation();
for (p = span_list; p; p = p->next)
- sum_columns(p->start_col, p->end_col);
- // Now handle blocks.
- compute_available_block_width();
+ sum_columns(p->start_col, p->end_col, 0);
+ // Now handle unexpanded blocks.
int had_spanning_block = 0;
int had_equal_block = 0;
for (q = entry_list; q; q = q->next)
if (q->divert(ncolumns, minimum_width,
- (flags & EXPAND) ? column_separation : 0)) {
+ (flags & EXPAND) ? column_separation : 0, 0)) {
if (q->end_col > q->start_col)
had_spanning_block = 1;
for (i = q->start_col; i <= q->end_col && !had_equal_block; i++)
if (equal[i])
had_equal_block = 1;
}
- // Second pass.
+ // Adjust widths.
if (had_equal_block)
make_columns_equal();
if (had_spanning_block)
for (p = span_list; p; p = p->next)
divide_span(p->start_col, p->end_col);
- compute_separation_factor();
- for (p = span_list; p; p = p->next)
- sum_columns(p->start_col, p->end_col);
+ compute_expand_width();
+ if ((flags & EXPAND) && total_separation != 0) {
+ compute_separation_factor();
+ for (p = span_list; p; p = p->next)
+ sum_columns(p->start_col, p->end_col, 0);
+ }
+ else {
+ // Handle expanded blocks.
+ for (p = span_list; p; p = p->next)
+ sum_columns(p->start_col, p->end_col, 1);
+ for (q = entry_list; q; q = q->next)
+ if (q->divert(ncolumns, minimum_width, 0, 1)) {
+ if (q->end_col > q->start_col)
+ had_spanning_block = 1;
+ }
+ // Adjust widths again.
+ if (had_spanning_block)
+ for (p = span_list; p; p = p->next)
+ divide_span(p->start_col, p->end_col);
+ }
compute_column_positions();
}
diff --git a/src/preproc/tbl/table.h b/src/preproc/tbl/table.h
index 4989a4d8..03fbc215 100644
--- a/src/preproc/tbl/table.h
+++ b/src/preproc/tbl/table.h
@@ -102,15 +102,17 @@ class table {
char *equal;
int left_separation;
int right_separation;
+ int total_separation;
int allocated_rows;
void build_span_list();
- void compute_available_block_width();
+ void compute_expand_width();
void do_hspan(int r, int c);
void do_vspan(int r, int c);
void allocate(int r);
void compute_widths();
void divide_span(int, int);
- void sum_columns(int, int);
+ void sum_columns(int, int, int);
+ void compute_total_separation();
void compute_separation_factor();
void compute_column_positions();
void do_row(int);
@@ -129,9 +131,8 @@ class table {
void compute_vrule_top_adjust(int, int, string &);
void compute_vrule_bot_adjust(int, int, string &);
void determine_row_type();
- int count_block_columns();
+ int count_expand_columns();
public:
- char *blockflag;
unsigned flags;
enum {
CENTER = 0x00000001,
@@ -143,6 +144,7 @@ public:
NOSPACES = 0x00000040,
EXPERIMENTAL = 0x80000000 // undocumented; use as a hook for experiments
};
+ char *expand;
table(int nc, unsigned flags, int linesize, char decimal_point_char);
~table();
@@ -157,6 +159,7 @@ public:
void set_minimum_width(int c, const string &w);
void set_column_separation(int c, int n);
void set_equal_column(int c);
+ void set_expand_column(int c);
void set_delim(char c1, char c2);
void print_single_hline(int r);
void print_double_hline(int r);
diff --git a/src/preproc/tbl/tbl.man b/src/preproc/tbl/tbl.man
index fa0cc36f..4e6edc70 100644
--- a/src/preproc/tbl/tbl.man
+++ b/src/preproc/tbl/tbl.man
@@ -1,3 +1,4 @@
+'\" t
.ig
Copyright (C) 1989-1995, 2001, 2002, 2003, 2004, 2006, 2007, 2008
Free Software Foundation, Inc.
@@ -82,6 +83,9 @@ expects to find table descriptions wrapped in the
(table start) and
.B .TE
(table end) macros.
+.
+.
+.SS Global options
The line immediately following the
.B .TS
macro may contain any of the following global options (ignoring the case of
@@ -129,6 +133,9 @@ Same as doublebox (GNU tbl only).
.B expand
Make the table as wide as the current line length (providing a column
separation factor).
+Ignored if one or more `x' column specifiers are used (see below).
+.
+.IP
In case the sum of the column widths is larger than the current line length,
the column separation factor is set to zero; such tables extend into the
right margin, and there is no column separation at all.
@@ -150,7 +157,7 @@ type.
Don't use diversions to prevent page breaks (GNU tbl only).
Normally
.B tbl
-attempts to prevent undesirable breaks in the table by using diversions.
+attempts to prevent undesirable breaks in boxed tables by using diversions.
This can sometimes interact badly with macro packages' own use of
diversions, when footnotes, for example, are used.
.
@@ -168,16 +175,17 @@ instead of a tab to separate items in a line of input data.
The global options must end with a semicolon.
There might be whitespace between an option and its argument in parentheses.
.
-.LP
+.
+.SS Table format specification
After global options come lines describing the format of each line of
the table.
Each such format line describes one line of the table itself, except that
the last format line (which you must end with a period) describes all
remaining lines of the table.
-A single key character describes each column of each line of the table.
+A single-key character describes each column of each line of the table.
Key characters can be separated by spaces or tabs.
-You may run format specs for multiple lines together on the same line by
-separating them with commas.
+You may run format specifications for multiple lines together on the same
+line by separating them with commas.
.
.LP
You may follow each key character with specifiers that determine the font
@@ -198,6 +206,50 @@ The available key characters are:
.BR a , A
Center longest line in this column and then left-justifies all other lines
in this column with respect to that centered line.
+The idea is to use such alphabetic subcolumns (hence the name of the key
+character) in combination with\~
+.BR L ;
+they are called subcolumns because
+.BR A \~items
+are indented by\~1n relative to
+.BR L \~entries.
+Example:
+.RS
+.IP
+.EX
+\&.TS
+\&tab(;);
+\&ln,an.
+\&item one;1
+\&subitem two;2
+\&subitem three;3
+\&.T&
+\&ln,an.
+\&item eleven;11
+\&subitem twentytwo;22
+\&subitem thirtythree;33
+\&.TE
+.EE
+.RE
+.
+.IP
+Result:
+.
+.RS
+.IP
+.TS
+tab(;);
+ln,an.
+item one;1
+subitem two;2
+subitem three;3
+.T&
+ln,an.
+item eleven;11
+subitem twentytwo;22
+subitem thirtythree;33
+.TE
+.RE
.
.TP
.BR c , C
@@ -211,6 +263,80 @@ Left-justify item within the column.
.BR n , N
Numerically justify item in the column: Units positions of numbers are
aligned vertically.
+If there is one or more dots adjacent to a digit, use the rightmost one for
+vertical alignment.
+If there is no dot, use the rightmost digit for vertical alignment;
+otherwise, center the item within the column.
+Alignment can be forced to a certain position using `\[rs]&'; if there is
+one or more instances of this special (non-printing) character present
+within the data, use the leftmost one for alignment.
+Example:
+.RS
+.IP
+.EX
+\&.TS
+\&n.
+\&1
+\&1.5
+\&1.5.3
+\&abcde
+\&a\[rs]&bcde
+\&.TE
+.EE
+.RE
+.
+.IP
+Result:
+.
+.RS
+.IP
+.TS
+n.
+1
+1.5
+1.5.3
+abcde
+a\&bcde
+.TE
+.RE
+.
+.IP
+If numerical entries are combined with
+.B L
+or
+.BR R \~entries
+\[en] this can happen if the table format is changed with
+.B .T&
+\%\[en],
+center the widest
+.I number
+(of the data entered under the
+.BR N \~specifier
+regime) relative to the widest
+.B L
+or
+.BR R \~entry,
+preserving the alignment of all numerical entries.
+Contrary to
+.BR A \~type
+entries, there is no extra indentation.
+.
+.IP
+Using equations (to be processed with
+.BR eqn )
+within columns which use the
+.BR N \~specifier
+is problematic in most cases due to
+.BR tbl 's
+algorithm for finding the vertical alignment, as described above.
+Using the global
+.B delim
+option, however, it is possible to make
+.B tbl
+ignore the data within
+.B eqn
+delimiters for that purpose.
+.
.
.TP
.BR r , R
@@ -219,10 +345,12 @@ Right-justify item within the column.
.TP
.BR s , S
Span previous item on the left into this column.
+Not allowed for the first column.
.
.TP
.B ^
Span down entry from previous row in this column.
+Not allowed for the first row.
.
.TP
.BR _ , -
@@ -239,11 +367,22 @@ The corresponding column becomes a vertical rule (if two of these are
adjacent, a double vertical rule).
.
.LP
-A vertical bar to the left of the first key-letter or to the right of the
+A vertical bar to the left of the first key letter or to the right of the
last one produces a line at the edge of the table.
.
.LP
-Here are the specifiers that can appear in suffixes to column key letters:
+To change the data format within a table, use the
+.B .T&
+command (at the start of a line).
+It is followed by format and data lines (but no global options) similar to
+the
+.B .TS
+request.
+.
+.
+.SS Column specifiers
+Here are the specifiers that can appear in suffixes to column key letters
+(in any order):
.
.TP
.BR b , B
@@ -259,6 +398,7 @@ than vertically centering it (GNU tbl only).
.TP
.BR e , E
Make equally-spaced columns.
+All columns marked with this specifier get the same width.
.
.TP
.BR f , F
@@ -340,6 +480,17 @@ If used multiple times to specify the width for a particular column,
the last entry takes effect.
.
.TP
+.BR x , X
+An expanded column.
+After computing all column widths without an
+.BR x \~specifier,
+use the remaining line width for this column.
+If there is more than one expanded column, distribute the remaining
+horizontal space evenly among the affected columns (this is a GNU
+extension).
+This feature has the same effect as specifying a minimum column width.
+.
+.TP
.BR z , Z
Ignore the corresponding column for width-calculation purposes, this is,
don't use the fields but only the specifiers of this column to compute
@@ -353,6 +504,16 @@ option is on \[en] in case of overfull tables this might be zero).
Default separation is 3n.
.
.LP
+The column specifiers
+.BR e ,
+.BR w ,
+and
+.B x
+are mutually exclusive; if specified multiple times for a particular column,
+the last entry takes effect.
+.
+.
+.SS Table data
The format lines are followed by lines containing the actual data for the
table, followed finally by
.BR .TE .
@@ -370,44 +531,36 @@ computes the column widths line by line, applying \[rs]w on each entry
which isn't a text block.
As a consequence, constructions like
.IP
-.B .TS
-.br
-.B c,l.
-.br
-.B \[rs]s[20]MM
-.br
-.B MMMM
-.br
-.B .TE
-.br
+.EX
+\&.TS
+\&c,l.
+\&\[rs]s[20]MM
+\&MMMM
+\&.TE
+.EE
.
.LP
fail; you must either say
.IP
-.B .TS
-.br
-.B cp20,lp20.
-.br
-.B MM
-.br
-.B MMMM
-.br
-.B .TE
-.br
+.EX
+\&.TS
+\&cp20,lp20.
+\&MM
+\&MMMM
+\&.TE
+.EE
.
.LP
or
+.
.IP
-.B .TS
-.br
-.B c,l.
-.br
-.B \[rs]s[20]MM
-.br
-.B \[rs]s[20]MMMM
-.br
-.B .TE
-.br
+.EX
+\&.TS
+\&c,l.
+\&\[rs]s[20]MM
+\&\[rs]s[20]MMMM
+\&.TE
+.EE
.
.LP
A dot starting a line, followed by anything but a digit is handled as a
@@ -432,7 +585,8 @@ neighbours).
A data item consisting only of `\[rs]^' indicates that the field immediately
above spans downward over this row.
.
-.LP
+.
+.SS Text blocks
A text block can be used to enter data as a single entry which would be
too long as a simple string between tabs.
It is started with `T{' and closed with `T}'.
@@ -441,6 +595,8 @@ followed by other data columns (separated with tabs or the character given
with the
.B tab
global option).
+.
+.LP
By default, the text block is formatted with the settings which were
active before entering the table, possibly overridden by the
.BR m ,
@@ -455,25 +611,25 @@ right before the starting
(and
.B .ad
after the table).
-If `w' specifiers are not given for all columns of a text block span, the
-default length of the text block (to be more precise, the line length used
-to process the text block diversion) is computed as L\[tmu]C/(N+1), where
-`L' is the current line length, `C' the number of columns spanned by the
-text block, and `N' the total number of columns in the table.
-Note, however, that the actual diversion width as given in register
+.
+.LP
+If either `w' or `x' specifiers are not given for
+.I all
+columns of a text block span, the default length of the text block (to be
+more precise, the line length used to process the text block diversion) is
+computed as L\[tmu]C/(N+1), where `L' is the current line length, `C' the
+number of columns spanned by the text block, and `N' the total number of
+columns in the table.
+Note, however, that the actual diversion width as returned in register
.B \[rs]n[dl]
is used eventually as the text block width.
+If necessary, you can also control the text block width with a direct
+insertion of a
+.B .ll
+request right after `T{'.
.
-.LP
-To change the data format within a table, use the
-.B .T&
-command (at the start of a line).
-It is followed by format and data lines (but no global options) similar to
-the
-.B .TS
-request.
.
-.LP
+.SS Miscellaneous
The number register
.B \[rs]n[TW]
holds the table width; it can't be used within the table itself but is defined
@@ -540,29 +696,20 @@ defines its own macros (right before each table) it is necessary to use
an `end-of-macro' macro. Additionally, the escape character has to be switched
off. Here an example.
.IP
-.B .eo
-.br
-.B .de ATABLE ..
-.br
-.B .TS
-.br
-.B allbox tab(;);
-.br
-.B cl.
-.br
-.B \[rs]$1;\[rs]$2
-.br
-.B .TE
-.br
-.B ...
-.br
-.B .ec
-.br
-.B .ATABLE A table
-.br
-.B .ATABLE Another table
-.br
-.B .ATABLE And \[dq]another one\[dq]
+.EX
+\&.eo
+\&.de ATABLE ..
+\&.TS
+\&allbox tab(;);
+\&cl.
+\&\[rs]$1;\[rs]$2
+\&.TE
+\&...
+\&.ec
+\&.ATABLE A table
+\&.ATABLE Another table
+\&.ATABLE And \[dq]another one\[dq]
+.EE
.
.LP
Note, however, that not all features of
@@ -602,15 +749,14 @@ request cannot be used to force a page-break in a multi-page table.
Instead, define
.B BP
as follows
+.
.IP
-.B .de BP
-.br
-.B .ie '\[rs]\[rs]n(.z'' .bp \[rs]\[rs]$1
-.br
-.B .el \[rs]!.BP \[rs]\[rs]$1
-.br
-.B ..
-.br
+.EX
+\&.de BP
+\&. ie '\[rs]\[rs]n(.z'' .bp \[rs]\[rs]$1
+\&. el \[rs]!.BP \[rs]\[rs]$1
+\&..
+.EE
.
.LP
and use
@@ -626,17 +772,16 @@ This is correct behaviour: \[rs]a is an
leader.
To get leaders use a real leader, either by using a control A or like
this:
+.
.IP
-.nf
-.ft B
+.EX
\&.ds a \[rs]a
\&.TS
-tab(;);
-lw(1i) l.
-A\[rs]*a;B
+\&tab(;);
+\&lw(1i) l.
+\&A\[rs]*a;B
\&.TE
-.ft
-.fi
+.EE
.
.
.SH REFERENCE