| File: | src/gnu/usr.bin/texinfo/makeinfo/multi.c |
| Warning: | line 465, column 19 The left operand of '+' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* multi.c -- multiple-column tables (@multitable) for makeinfo. | |||
| 2 | $Id: multi.c,v 1.7 2006/07/17 16:12:36 espie Exp $ | |||
| 3 | ||||
| 4 | Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free Software | |||
| 5 | Foundation, Inc. | |||
| 6 | ||||
| 7 | This program is free software; you can redistribute it and/or modify | |||
| 8 | it under the terms of the GNU General Public License as published by | |||
| 9 | the Free Software Foundation; either version 2, or (at your option) | |||
| 10 | any later version. | |||
| 11 | ||||
| 12 | This program is distributed in the hope that it will be useful, | |||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 15 | GNU General Public License for more details. | |||
| 16 | ||||
| 17 | You should have received a copy of the GNU General Public License | |||
| 18 | along with this program; if not, write to the Free Software Foundation, | |||
| 19 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| 20 | ||||
| 21 | Originally written by phr@gnu.org (Paul Rubin). */ | |||
| 22 | ||||
| 23 | #include "system.h" | |||
| 24 | #include "cmds.h" | |||
| 25 | #include "insertion.h" | |||
| 26 | #include "makeinfo.h" | |||
| 27 | #include "multi.h" | |||
| 28 | #include "xml.h" | |||
| 29 | ||||
| 30 | #define MAXCOLS100 100 /* remove this limit later @@ */ | |||
| 31 | ||||
| 32 | ||||
| 33 | /* | |||
| 34 | * Output environments. This is a hack grafted onto existing | |||
| 35 | * structure. The "output environment" used to consist of the | |||
| 36 | * global variables `output_paragraph', `fill_column', etc. | |||
| 37 | * Routines like add_char would manipulate these variables. | |||
| 38 | * | |||
| 39 | * Now, when formatting a multitable, we maintain separate environments | |||
| 40 | * for each column. That way we can build up the columns separately | |||
| 41 | * and write them all out at once. The "current" output environment" | |||
| 42 | * is still kept in those global variables, so that the old output | |||
| 43 | * routines don't have to change. But we provide routines to save | |||
| 44 | * and restore these variables in an "environment table". The | |||
| 45 | * `select_output_environment' function switches from one output | |||
| 46 | * environment to another. | |||
| 47 | * | |||
| 48 | * Environment #0 (i.e., element #0 of the table) is the regular | |||
| 49 | * environment that is used when we're not formatting a multitable. | |||
| 50 | * | |||
| 51 | * Environment #N (where N = 1,2,3,...) is the env. for column #N of | |||
| 52 | * the table, when a multitable is active. | |||
| 53 | */ | |||
| 54 | ||||
| 55 | /* contents of an output environment */ | |||
| 56 | /* some more vars may end up being needed here later @@ */ | |||
| 57 | struct env | |||
| 58 | { | |||
| 59 | unsigned char *output_paragraph; | |||
| 60 | int output_paragraph_offset; | |||
| 61 | int meta_char_pos; | |||
| 62 | int output_column; | |||
| 63 | int paragraph_is_open; | |||
| 64 | int current_indent; | |||
| 65 | int fill_column; | |||
| 66 | } envs[MAXCOLS100]; /* the environment table */ | |||
| 67 | ||||
| 68 | /* index in environment table of currently selected environment */ | |||
| 69 | static int current_env_no; | |||
| 70 | ||||
| 71 | /* current column number */ | |||
| 72 | static int current_column_no; | |||
| 73 | ||||
| 74 | /* We need to make a difference between template based widths and | |||
| 75 | @columnfractions for HTML tables' sake. Sigh. */ | |||
| 76 | static int seen_column_fractions; | |||
| 77 | ||||
| 78 | /* column number of last column in current multitable */ | |||
| 79 | static int last_column; | |||
| 80 | ||||
| 81 | /* flags indicating whether horizontal and vertical separators need | |||
| 82 | to be drawn, separating rows and columns in the current multitable. */ | |||
| 83 | static int hsep, vsep; | |||
| 84 | ||||
| 85 | /* whether this is the first row. */ | |||
| 86 | static int first_row; | |||
| 87 | ||||
| 88 | /* Called to handle a {...} template on the @multitable line. | |||
| 89 | We're at the { and our first job is to find the matching }; as a side | |||
| 90 | effect, we change *PARAMS to point to after it. Our other job is to | |||
| 91 | expand the template text and return the width of that string. */ | |||
| 92 | static unsigned | |||
| 93 | find_template_width (char **params) | |||
| 94 | { | |||
| 95 | char *template, *xtemplate; | |||
| 96 | unsigned len; | |||
| 97 | char *start = *params; | |||
| 98 | int brace_level = 0; | |||
| 99 | ||||
| 100 | /* The first character should be a {. */ | |||
| 101 | if (!params || !*params || **params != '{') | |||
| 102 | { | |||
| 103 | line_error ("find_template width internal error: passed %s", | |||
| 104 | params ? *params : "null"); | |||
| 105 | return 0; | |||
| 106 | } | |||
| 107 | ||||
| 108 | do | |||
| 109 | { | |||
| 110 | if (**params == '{' && (*params == start || (*params)[-1] != '@')) | |||
| 111 | brace_level++; | |||
| 112 | else if (**params == '}' && (*params)[-1] != '@') | |||
| 113 | brace_level--; | |||
| 114 | else if (**params == 0) | |||
| 115 | { | |||
| 116 | line_error (_("Missing } in @multitable template")((const char *) ("Missing } in @multitable template"))); | |||
| 117 | return 0; | |||
| 118 | } | |||
| 119 | (*params)++; | |||
| 120 | } | |||
| 121 | while (brace_level > 0); | |||
| 122 | ||||
| 123 | template = substring (start + 1, *params - 1); /* omit braces */ | |||
| 124 | xtemplate = expansion (template, 0); | |||
| 125 | len = strlen (xtemplate); | |||
| 126 | ||||
| 127 | free (template); | |||
| 128 | free (xtemplate); | |||
| 129 | ||||
| 130 | return len; | |||
| 131 | } | |||
| 132 | ||||
| 133 | /* Direct current output to environment number N. Used when | |||
| 134 | switching work from one column of a multitable to the next. | |||
| 135 | Returns previous environment number. */ | |||
| 136 | static int | |||
| 137 | select_output_environment (int n) | |||
| 138 | { | |||
| 139 | struct env *e = &envs[current_env_no]; | |||
| 140 | int old_env_no = current_env_no; | |||
| 141 | ||||
| 142 | /* stash current env info from global vars into the old environment */ | |||
| 143 | e->output_paragraph = output_paragraph; | |||
| 144 | e->output_paragraph_offset = output_paragraph_offset; | |||
| 145 | e->meta_char_pos = meta_char_pos; | |||
| 146 | e->output_column = output_column; | |||
| 147 | e->paragraph_is_open = paragraph_is_open; | |||
| 148 | e->current_indent = current_indent; | |||
| 149 | e->fill_column = fill_column; | |||
| 150 | ||||
| 151 | /* now copy new environment into global vars */ | |||
| 152 | current_env_no = n; | |||
| 153 | e = &envs[current_env_no]; | |||
| 154 | output_paragraph = e->output_paragraph; | |||
| 155 | output_paragraph_offset = e->output_paragraph_offset; | |||
| 156 | meta_char_pos = e->meta_char_pos; | |||
| 157 | output_column = e->output_column; | |||
| 158 | paragraph_is_open = e->paragraph_is_open; | |||
| 159 | current_indent = e->current_indent; | |||
| 160 | fill_column = e->fill_column; | |||
| 161 | return old_env_no; | |||
| 162 | } | |||
| 163 | ||||
| 164 | /* Initialize environment number ENV_NO, of width WIDTH. | |||
| 165 | The idea is that we're going to use one environment for each column of | |||
| 166 | a multitable, so we can build them up separately and print them | |||
| 167 | all out at the end. */ | |||
| 168 | static int | |||
| 169 | setup_output_environment (int env_no, int width) | |||
| 170 | { | |||
| 171 | int old_env = select_output_environment (env_no); | |||
| 172 | ||||
| 173 | /* clobber old environment and set width of new one */ | |||
| 174 | init_paragraph (); | |||
| 175 | ||||
| 176 | /* make our change */ | |||
| 177 | fill_column = width; | |||
| 178 | ||||
| 179 | /* Save new environment and restore previous one. */ | |||
| 180 | select_output_environment (old_env); | |||
| 181 | ||||
| 182 | return env_no; | |||
| 183 | } | |||
| 184 | ||||
| 185 | /* Read the parameters for a multitable from the current command | |||
| 186 | line, save the parameters away, and return the | |||
| 187 | number of columns. */ | |||
| 188 | static int | |||
| 189 | setup_multitable_parameters (void) | |||
| 190 | { | |||
| 191 | char *params = insertion_stack->item_function; | |||
| 192 | int nchars; | |||
| 193 | float columnfrac; | |||
| 194 | char command[200]; /* xx no fixed limits */ | |||
| 195 | int i = 1; | |||
| 196 | ||||
| 197 | /* We implement @hsep and @vsep even though TeX doesn't. | |||
| 198 | We don't get mixing of @columnfractions and templates right, | |||
| 199 | but TeX doesn't either. */ | |||
| 200 | hsep = vsep = 0; | |||
| 201 | ||||
| 202 | /* Assume no @columnfractions per default. */ | |||
| 203 | seen_column_fractions = 0; | |||
| 204 | ||||
| 205 | while (*params) { | |||
| 206 | while (whitespace (*params)((*params) == '\t' || (*params) == ' ')) | |||
| 207 | params++; | |||
| 208 | ||||
| 209 | if (*params == '@') { | |||
| 210 | sscanf (params, "%199s", command); | |||
| 211 | nchars = strlen (command); | |||
| 212 | params += nchars; | |||
| 213 | if (strcmp (command, "@hsep") == 0) | |||
| 214 | hsep++; | |||
| 215 | else if (strcmp (command, "@vsep") == 0) | |||
| 216 | vsep++; | |||
| 217 | else if (strcmp (command, "@columnfractions") == 0) { | |||
| 218 | seen_column_fractions = 1; | |||
| 219 | /* Clobber old environments and create new ones, starting at #1. | |||
| 220 | Environment #0 is the normal output, so don't mess with it. */ | |||
| 221 | for ( ; i <= MAXCOLS100; i++) { | |||
| 222 | if (sscanf (params, "%f", &columnfrac) < 1) | |||
| 223 | goto done; | |||
| 224 | /* Unfortunately, can't use %n since m68k-hp-bsd libc (at least) | |||
| 225 | doesn't support it. So skip whitespace (preceding the | |||
| 226 | number) and then non-whitespace (the number). */ | |||
| 227 | while (*params && (*params == ' ' || *params == '\t')) | |||
| 228 | params++; | |||
| 229 | /* Hmm, but what about @columnfractions 3foo. Oh well, | |||
| 230 | it's invalid input anyway. */ | |||
| 231 | while (*params && *params != ' ' && *params != '\t' | |||
| 232 | && *params != '\n' && *params != '@') | |||
| 233 | params++; | |||
| 234 | ||||
| 235 | { | |||
| 236 | /* For html/xml/docbook, translate fractions into integer | |||
| 237 | percentages, adding .005 to avoid rounding problems. For | |||
| 238 | info, we want the character width. */ | |||
| 239 | int width = xml || html ? (columnfrac + .005) * 100 | |||
| 240 | : (columnfrac * (fill_column - current_indent) + .5); | |||
| 241 | setup_output_environment (i, width); | |||
| 242 | } | |||
| 243 | } | |||
| 244 | } | |||
| 245 | ||||
| 246 | } else if (*params == '{') { | |||
| 247 | unsigned template_width = find_template_width (¶ms); | |||
| 248 | ||||
| 249 | /* This gives us two spaces between columns. Seems reasonable. | |||
| 250 | How to take into account current_indent here? */ | |||
| 251 | setup_output_environment (i++, template_width + 2); | |||
| 252 | ||||
| 253 | } else { | |||
| 254 | warning (_("ignoring stray text `%s' after @multitable")((const char *) ("ignoring stray text `%s' after @multitable" )), params); | |||
| 255 | break; | |||
| 256 | } | |||
| 257 | } | |||
| 258 | ||||
| 259 | done: | |||
| 260 | flush_output (); | |||
| 261 | inhibit_output_flushing (); | |||
| 262 | ||||
| 263 | last_column = i - 1; | |||
| 264 | return last_column; | |||
| 265 | } | |||
| 266 | ||||
| 267 | /* Output a row. Calls insert, but also flushes the buffered output | |||
| 268 | when we see a newline, since in multitable every line is a separate | |||
| 269 | paragraph. */ | |||
| 270 | static void | |||
| 271 | out_char (int ch) | |||
| 272 | { | |||
| 273 | if (html || xml) | |||
| 274 | add_char (ch); | |||
| 275 | else | |||
| 276 | { | |||
| 277 | int env = select_output_environment (0); | |||
| 278 | insert (ch); | |||
| 279 | if (ch == '\n') | |||
| 280 | { | |||
| 281 | uninhibit_output_flushing (); | |||
| 282 | flush_output (); | |||
| 283 | inhibit_output_flushing (); | |||
| 284 | } | |||
| 285 | select_output_environment (env); | |||
| 286 | } | |||
| 287 | } | |||
| 288 | ||||
| 289 | ||||
| 290 | static void | |||
| 291 | draw_horizontal_separator (void) | |||
| 292 | { | |||
| 293 | int i, j, s; | |||
| 294 | ||||
| 295 | if (html) | |||
| 296 | { | |||
| 297 | add_word ("<hr>"); | |||
| 298 | return; | |||
| 299 | } | |||
| 300 | if (xml) | |||
| 301 | return; | |||
| 302 | ||||
| 303 | for (s = 0; s < envs[0].current_indent; s++) | |||
| 304 | out_char (' '); | |||
| 305 | if (vsep) | |||
| 306 | out_char ('+'); | |||
| 307 | for (i = 1; i <= last_column; i++) { | |||
| 308 | for (j = 0; j <= envs[i].fill_column; j++) | |||
| 309 | out_char ('-'); | |||
| 310 | if (vsep) | |||
| 311 | out_char ('+'); | |||
| 312 | } | |||
| 313 | out_char (' '); | |||
| 314 | out_char ('\n'); | |||
| 315 | } | |||
| 316 | ||||
| 317 | ||||
| 318 | /* multitable strategy: | |||
| 319 | for each item { | |||
| 320 | for each column in an item { | |||
| 321 | initialize a new paragraph | |||
| 322 | do ordinary formatting into the new paragraph | |||
| 323 | save the paragraph away | |||
| 324 | repeat if there are more paragraphs in the column | |||
| 325 | } | |||
| 326 | dump out the saved paragraphs and free the storage | |||
| 327 | } | |||
| 328 | ||||
| 329 | For HTML we construct a simple HTML 3.2 table with <br>s inserted | |||
| 330 | to help non-tables browsers. `@item' inserts a <tr> and `@tab' | |||
| 331 | inserts <td>; we also try to close <tr>. The only real | |||
| 332 | alternative is to rely on the info formatting engine and present | |||
| 333 | preformatted text. */ | |||
| 334 | ||||
| 335 | void | |||
| 336 | do_multitable (void) | |||
| 337 | { | |||
| 338 | int ncolumns; | |||
| 339 | ||||
| 340 | if (multitable_active) | |||
| 341 | { | |||
| 342 | line_error ("Multitables cannot be nested"); | |||
| 343 | return; | |||
| 344 | } | |||
| 345 | ||||
| 346 | close_single_paragraph (); | |||
| 347 | ||||
| 348 | if (xml) | |||
| 349 | { | |||
| 350 | xml_no_para = 1; | |||
| 351 | if (output_paragraph[output_paragraph_offset-1] == '\n') | |||
| 352 | output_paragraph_offset--; | |||
| 353 | } | |||
| 354 | ||||
| 355 | /* scan the current item function to get the field widths | |||
| 356 | and number of columns, and set up the output environment list | |||
| 357 | accordingly. */ | |||
| 358 | ncolumns = setup_multitable_parameters (); | |||
| 359 | first_row = 1; | |||
| 360 | ||||
| 361 | /* <p> for non-tables browsers. @multitable implicitly ends the | |||
| 362 | current paragraph, so this is ok. */ | |||
| 363 | if (html) | |||
| 364 | add_html_block_elt ("<p><table summary=\"\">"); | |||
| 365 | /* else if (docbook)*/ /* 05-08 */ | |||
| 366 | else if (xml) | |||
| 367 | { | |||
| 368 | int *widths = xmalloc (ncolumns * sizeof (int)); | |||
| 369 | int i; | |||
| 370 | for (i=0; i<ncolumns; i++) | |||
| 371 | widths[i] = envs[i+1].fill_column; | |||
| 372 | xml_begin_multitable (ncolumns, widths); | |||
| 373 | free (widths); | |||
| 374 | } | |||
| 375 | ||||
| 376 | if (hsep) | |||
| 377 | draw_horizontal_separator (); | |||
| 378 | ||||
| 379 | /* The next @item command will direct stdout into the first column | |||
| 380 | and start processing. @tab will then switch to the next column, | |||
| 381 | and @item will flush out the saved output and return to the first | |||
| 382 | column. Environment #1 is the first column. (Environment #0 is | |||
| 383 | the normal output) */ | |||
| 384 | ||||
| 385 | ++multitable_active; | |||
| 386 | } | |||
| 387 | ||||
| 388 | /* advance to the next environment number */ | |||
| 389 | static void | |||
| 390 | nselect_next_environment (void) | |||
| 391 | { | |||
| 392 | if (current_env_no >= last_column) { | |||
| 393 | line_error (_("Too many columns in multitable item (max %d)")((const char *) ("Too many columns in multitable item (max %d)" )), last_column); | |||
| 394 | return; | |||
| 395 | } | |||
| 396 | select_output_environment (current_env_no + 1); | |||
| 397 | } | |||
| 398 | ||||
| 399 | ||||
| 400 | /* do anything needed at the beginning of processing a | |||
| 401 | multitable column. */ | |||
| 402 | static void | |||
| 403 | init_column (void) | |||
| 404 | { | |||
| 405 | /* don't indent 1st paragraph in the item */ | |||
| 406 | cm_noindent (); | |||
| 407 | ||||
| 408 | /* throw away possible whitespace after @item or @tab command */ | |||
| 409 | skip_whitespace ()while ((input_text_offset != input_text_length) && (( input_text[input_text_offset]) == '\t' || (input_text[input_text_offset ]) == ' ')) input_text_offset++; | |||
| 410 | } | |||
| 411 | ||||
| 412 | static void | |||
| 413 | output_multitable_row (void) | |||
| 414 | { | |||
| 415 | /* offset in the output paragraph of the next char needing | |||
| 416 | to be output for that column. */ | |||
| 417 | int offset[MAXCOLS100]; | |||
| 418 | int i, j, s, remaining; | |||
| 419 | int had_newline = 0; | |||
| 420 | ||||
| 421 | for (i = 0; i <= last_column; i++) | |||
| 422 | offset[i] = 0; | |||
| 423 | ||||
| 424 | /* select the current environment, to make sure the env variables | |||
| 425 | get updated */ | |||
| 426 | select_output_environment (current_env_no); | |||
| 427 | ||||
| 428 | #define CHAR_ADDR(n) (offset[i] + (n)) | |||
| 429 | #define CHAR_AT(n) (envs[i].output_paragraph[CHAR_ADDR(n)]) | |||
| 430 | ||||
| 431 | /* remove trailing whitespace from each column */ | |||
| 432 | for (i = 1; i <= last_column; i++) { | |||
| 433 | while (envs[i].output_paragraph_offset && | |||
| 434 | cr_or_whitespace (CHAR_AT (envs[i].output_paragraph_offset - 1))(((CHAR_AT (envs[i].output_paragraph_offset - 1)) == '\t' || ( CHAR_AT (envs[i].output_paragraph_offset - 1)) == ' ') || (CHAR_AT (envs[i].output_paragraph_offset - 1)) == '\r' || (CHAR_AT ( envs[i].output_paragraph_offset - 1)) == '\n')) | |||
| 435 | envs[i].output_paragraph_offset--; | |||
| 436 | ||||
| 437 | if (i == current_env_no) | |||
| 438 | output_paragraph_offset = envs[i].output_paragraph_offset; | |||
| 439 | } | |||
| 440 | ||||
| 441 | /* read the current line from each column, outputting them all | |||
| 442 | pasted together. Do this til all lines are output from all | |||
| 443 | columns. */ | |||
| 444 | for (;;) { | |||
| 445 | remaining = 0; | |||
| 446 | /* first, see if there is any work to do */ | |||
| 447 | for (i = 1; i <= last_column; i++) { | |||
| 448 | if (CHAR_ADDR (0) < envs[i].output_paragraph_offset) { | |||
| 449 | remaining = 1; | |||
| 450 | break; | |||
| 451 | } | |||
| 452 | } | |||
| 453 | if (!remaining
| |||
| 454 | break; | |||
| 455 | ||||
| 456 | for (s = 0; s < envs[0].current_indent; s++) | |||
| 457 | out_char (' '); | |||
| 458 | ||||
| 459 | if (vsep) | |||
| 460 | out_char ('|'); | |||
| 461 | ||||
| 462 | for (i = 1; i
| |||
| 463 | for (s = 0; s < envs[i].current_indent; s++) | |||
| 464 | out_char (' '); | |||
| 465 | for (j = 0; CHAR_ADDR (j) < envs[i].output_paragraph_offset; j++) { | |||
| ||||
| 466 | if (CHAR_AT (j) == '\n') | |||
| 467 | break; | |||
| 468 | out_char (CHAR_AT (j)); | |||
| 469 | } | |||
| 470 | offset[i] += j + 1; /* skip last text plus skip the newline */ | |||
| 471 | ||||
| 472 | /* Do not output trailing blanks if we're in the last column and | |||
| 473 | there will be no trailing |. */ | |||
| 474 | if (i < last_column && !vsep) | |||
| 475 | for (; j <= envs[i].fill_column; j++) | |||
| 476 | out_char (' '); | |||
| 477 | if (vsep
| |||
| 478 | out_char ('|'); /* draw column separator */ | |||
| 479 | } | |||
| 480 | out_char ('\n'); /* end of line */ | |||
| 481 | had_newline = 1; | |||
| 482 | } | |||
| 483 | ||||
| 484 | /* If completely blank item, get blank line despite no other output. */ | |||
| 485 | if (!had_newline) | |||
| 486 | out_char ('\n'); /* end of line */ | |||
| 487 | ||||
| 488 | if (hsep) | |||
| 489 | draw_horizontal_separator (); | |||
| 490 | ||||
| 491 | /* Now dispose of the buffered output. */ | |||
| 492 | for (i = 1; i <= last_column; i++) { | |||
| 493 | select_output_environment (i); | |||
| 494 | init_paragraph (); | |||
| 495 | } | |||
| 496 | } | |||
| 497 | ||||
| 498 | int after_headitem = 0; | |||
| 499 | int headitem_row = 0; | |||
| 500 | ||||
| 501 | /* start a new item (row) of a multitable */ | |||
| 502 | int | |||
| 503 | multitable_item (void) | |||
| 504 | { | |||
| 505 | if (!multitable_active) { | |||
| 506 | line_error ("multitable_item internal error: no active multitable"); | |||
| 507 | xexit (1); | |||
| 508 | } | |||
| 509 | ||||
| 510 | current_column_no = 1; | |||
| 511 | ||||
| 512 | if (html) | |||
| 513 | { | |||
| 514 | if (!first_row) | |||
| 515 | /* <br> for non-tables browsers. */ | |||
| 516 | add_word_args ("<br></%s></tr>", after_headitem ? "th" : "td"); | |||
| 517 | ||||
| 518 | if (seen_column_fractions) | |||
| 519 | add_word_args ("<tr align=\"left\"><%s valign=\"top\" width=\"%d%%\">", | |||
| 520 | headitem_flag ? "th" : "td", | |||
| 521 | envs[current_column_no].fill_column); | |||
| 522 | else | |||
| 523 | add_word_args ("<tr align=\"left\"><%s valign=\"top\">", | |||
| 524 | headitem_flag ? "th" : "td"); | |||
| 525 | ||||
| 526 | if (headitem_flag) | |||
| 527 | after_headitem = 1; | |||
| 528 | else | |||
| 529 | after_headitem = 0; | |||
| 530 | first_row = 0; | |||
| 531 | headitem_row = headitem_flag; | |||
| 532 | headitem_flag = 0; | |||
| 533 | return 0; | |||
| 534 | } | |||
| 535 | /* else if (docbook)*/ /* 05-08 */ | |||
| 536 | else if (xml) | |||
| 537 | { | |||
| 538 | xml_end_multitable_row (first_row); | |||
| 539 | if (headitem_flag) | |||
| 540 | after_headitem = 1; | |||
| 541 | else | |||
| 542 | after_headitem = 0; | |||
| 543 | first_row = 0; | |||
| 544 | headitem_flag = 0; | |||
| 545 | return 0; | |||
| 546 | } | |||
| 547 | first_row = 0; | |||
| 548 | ||||
| 549 | if (current_env_no > 0) { | |||
| 550 | output_multitable_row (); | |||
| 551 | } | |||
| 552 | /* start at column 1 */ | |||
| 553 | select_output_environment (1); | |||
| 554 | if (!output_paragraph) { | |||
| 555 | line_error (_("[unexpected] cannot select column #%d in multitable")((const char *) ("[unexpected] cannot select column #%d in multitable" )), | |||
| 556 | current_env_no); | |||
| 557 | xexit (1); | |||
| 558 | } | |||
| 559 | ||||
| 560 | init_column (); | |||
| 561 | ||||
| 562 | if (headitem_flag) | |||
| 563 | hsep = 1; | |||
| 564 | else | |||
| 565 | hsep = 0; | |||
| 566 | ||||
| 567 | if (headitem_flag) | |||
| 568 | after_headitem = 1; | |||
| 569 | else | |||
| 570 | after_headitem = 0; | |||
| 571 | headitem_flag = 0; | |||
| 572 | ||||
| 573 | return 0; | |||
| 574 | } | |||
| 575 | ||||
| 576 | #undef CHAR_AT | |||
| 577 | #undef CHAR_ADDR | |||
| 578 | ||||
| 579 | /* select a new column in current row of multitable */ | |||
| 580 | void | |||
| 581 | cm_tab (void) | |||
| 582 | { | |||
| 583 | if (!multitable_active) | |||
| 584 | error (_("ignoring @tab outside of multitable")((const char *) ("ignoring @tab outside of multitable"))); | |||
| 585 | ||||
| 586 | current_column_no++; | |||
| 587 | ||||
| 588 | if (html) | |||
| 589 | { | |||
| 590 | if (seen_column_fractions) | |||
| 591 | add_word_args ("</%s><%s valign=\"top\" width=\"%d%%\">", | |||
| 592 | headitem_row ? "th" : "td", | |||
| 593 | headitem_row ? "th" : "td", | |||
| 594 | envs[current_column_no].fill_column); | |||
| 595 | else | |||
| 596 | add_word_args ("</%s><%s valign=\"top\">", | |||
| 597 | headitem_row ? "th" : "td", | |||
| 598 | headitem_row ? "th" : "td"); | |||
| 599 | } | |||
| 600 | /* else if (docbook)*/ /* 05-08 */ | |||
| 601 | else if (xml) | |||
| 602 | xml_end_multitable_column (); | |||
| 603 | else | |||
| 604 | nselect_next_environment (); | |||
| 605 | ||||
| 606 | init_column (); | |||
| 607 | } | |||
| 608 | ||||
| 609 | /* close a multitable, flushing its output and resetting | |||
| 610 | whatever needs resetting */ | |||
| 611 | void | |||
| 612 | end_multitable (void) | |||
| 613 | { | |||
| 614 | if (!html && !docbook) | |||
| ||||
| 615 | output_multitable_row (); | |||
| 616 | ||||
| 617 | /* Multitables cannot be nested. Otherwise, we'd have to save the | |||
| 618 | previous output environment number on a stack somewhere, and then | |||
| 619 | restore to that environment. */ | |||
| 620 | select_output_environment (0); | |||
| 621 | multitable_active = 0; | |||
| 622 | uninhibit_output_flushing (); | |||
| 623 | close_insertion_paragraph (); | |||
| 624 | ||||
| 625 | if (html) | |||
| 626 | add_word_args ("<br></%s></tr></table>\n", headitem_row ? "th" : "td"); | |||
| 627 | /* else if (docbook)*/ /* 05-08 */ | |||
| 628 | else if (xml) | |||
| 629 | xml_end_multitable (); | |||
| 630 | ||||
| 631 | #if 0 | |||
| 632 | printf (_("** Multicolumn output from last row:\n")((const char *) ("** Multicolumn output from last row:\n"))); | |||
| 633 | for (i = 1; i <= last_column; i++) { | |||
| 634 | select_output_environment (i); | |||
| 635 | printf (_("* column #%d: output = %s\n")((const char *) ("* column #%d: output = %s\n")), i, output_paragraph); | |||
| 636 | } | |||
| 637 | #endif | |||
| 638 | } |