1114472Sru/* multi.c -- multiple-column tables (@multitable) for makeinfo.
2146515Sru   $Id: multi.c,v 1.8 2004/04/11 17:56:47 karl Exp $
321495Sjmacd
4146515Sru   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004 Free Software
5114472Sru   Foundation, Inc.
621495Sjmacd
721495Sjmacd   This program is free software; you can redistribute it and/or modify
821495Sjmacd   it under the terms of the GNU General Public License as published by
921495Sjmacd   the Free Software Foundation; either version 2, or (at your option)
1021495Sjmacd   any later version.
1121495Sjmacd
1221495Sjmacd   This program is distributed in the hope that it will be useful,
1321495Sjmacd   but WITHOUT ANY WARRANTY; without even the implied warranty of
1421495Sjmacd   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1521495Sjmacd   GNU General Public License for more details.
1621495Sjmacd
1721495Sjmacd   You should have received a copy of the GNU General Public License
1821495Sjmacd   along with this program; if not, write to the Free Software Foundation,
1993139Sru   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2093139Sru
21146515Sru   Originally written by phr@gnu.org (Paul Rubin).  */
2221495Sjmacd
2342660Smarkm#include "system.h"
24146515Sru#include "cmds.h"
2556160Sru#include "insertion.h"
2621495Sjmacd#include "makeinfo.h"
27146515Sru#include "multi.h"
2893139Sru#include "xml.h"
2921495Sjmacd
3042660Smarkm#define MAXCOLS 100             /* remove this limit later @@ */
3121495Sjmacd
3221495Sjmacd
3321495Sjmacd/*
3421495Sjmacd * Output environments.  This is a hack grafted onto existing
3521495Sjmacd * structure.  The "output environment" used to consist of the
3621495Sjmacd * global variables `output_paragraph', `fill_column', etc.
3721495Sjmacd * Routines like add_char would manipulate these variables.
3821495Sjmacd *
3921495Sjmacd * Now, when formatting a multitable, we maintain separate environments
4021495Sjmacd * for each column.  That way we can build up the columns separately
4121495Sjmacd * and write them all out at once.  The "current" output environment"
4221495Sjmacd * is still kept in those global variables, so that the old output
4321495Sjmacd * routines don't have to change.  But we provide routines to save
4421495Sjmacd * and restore these variables in an "environment table".  The
4521495Sjmacd * `select_output_environment' function switches from one output
4621495Sjmacd * environment to another.
4721495Sjmacd *
4842660Smarkm * Environment #0 (i.e., element #0 of the table) is the regular
4921495Sjmacd * environment that is used when we're not formatting a multitable.
5021495Sjmacd *
5121495Sjmacd * Environment #N (where N = 1,2,3,...) is the env. for column #N of
5221495Sjmacd * the table, when a multitable is active.
5321495Sjmacd */
5421495Sjmacd
5521495Sjmacd/* contents of an output environment */
5621495Sjmacd/* some more vars may end up being needed here later @@ */
5721495Sjmacdstruct env
5821495Sjmacd{
5921495Sjmacd  unsigned char *output_paragraph;
6021495Sjmacd  int output_paragraph_offset;
6156160Sru  int meta_char_pos;
6221495Sjmacd  int output_column;
6321495Sjmacd  int paragraph_is_open;
6421495Sjmacd  int current_indent;
6521495Sjmacd  int fill_column;
6642660Smarkm} envs[MAXCOLS];                /* the environment table */
6721495Sjmacd
6821495Sjmacd/* index in environment table of currently selected environment */
6921495Sjmacdstatic int current_env_no;
7021495Sjmacd
71146515Sru/* current column number */
72146515Srustatic int current_column_no;
73146515Sru
74146515Sru/* We need to make a difference between template based widths and
75146515Sru   @columnfractions for HTML tables' sake.  Sigh.  */
76146515Srustatic int seen_column_fractions;
77146515Sru
7821495Sjmacd/* column number of last column in current multitable */
7921495Sjmacdstatic int last_column;
8021495Sjmacd
8121495Sjmacd/* flags indicating whether horizontal and vertical separators need
8221495Sjmacd   to be drawn, separating rows and columns in the current multitable. */
8321495Sjmacdstatic int hsep, vsep;
8456160Sru
8556160Sru/* whether this is the first row. */
8656160Srustatic int first_row;
8721495Sjmacd
8856160Sru/* Called to handle a {...} template on the @multitable line.
8956160Sru   We're at the { and our first job is to find the matching }; as a side
9056160Sru   effect, we change *PARAMS to point to after it.  Our other job is to
9156160Sru   expand the template text and return the width of that string.  */
9256160Srustatic unsigned
93146515Srufind_template_width (char **params)
9456160Sru{
9556160Sru  char *template, *xtemplate;
9656160Sru  unsigned len;
9756160Sru  char *start = *params;
9856160Sru  int brace_level = 0;
9956160Sru
10056160Sru  /* The first character should be a {.  */
10156160Sru  if (!params || !*params || **params != '{')
10256160Sru    {
10356160Sru      line_error ("find_template width internal error: passed %s",
10456160Sru                  params ? *params : "null");
10556160Sru      return 0;
10656160Sru    }
10756160Sru
10856160Sru  do
10956160Sru    {
11093139Sru      if (**params == '{' && (*params == start || (*params)[-1] != '@'))
11156160Sru        brace_level++;
11256160Sru      else if (**params == '}' && (*params)[-1] != '@')
11356160Sru        brace_level--;
11456160Sru      else if (**params == 0)
11556160Sru        {
11656160Sru          line_error (_("Missing } in @multitable template"));
11756160Sru          return 0;
11856160Sru        }
11956160Sru      (*params)++;
12056160Sru    }
12156160Sru  while (brace_level > 0);
12256160Sru
12356160Sru  template = substring (start + 1, *params - 1); /* omit braces */
12456160Sru  xtemplate = expansion (template, 0);
12556160Sru  len = strlen (xtemplate);
12656160Sru
12756160Sru  free (template);
12856160Sru  free (xtemplate);
12956160Sru
13056160Sru  return len;
13156160Sru}
13256160Sru
133146515Sru/* Direct current output to environment number N.  Used when
134146515Sru   switching work from one column of a multitable to the next.
135146515Sru   Returns previous environment number. */
136146515Srustatic int
137146515Sruselect_output_environment (int n)
138146515Sru{
139146515Sru  struct env *e = &envs[current_env_no];
140146515Sru  int old_env_no = current_env_no;
14156160Sru
142146515Sru  /* stash current env info from global vars into the old environment */
143146515Sru  e->output_paragraph = output_paragraph;
144146515Sru  e->output_paragraph_offset = output_paragraph_offset;
145146515Sru  e->meta_char_pos = meta_char_pos;
146146515Sru  e->output_column = output_column;
147146515Sru  e->paragraph_is_open = paragraph_is_open;
148146515Sru  e->current_indent = current_indent;
149146515Sru  e->fill_column = fill_column;
150146515Sru
151146515Sru  /* now copy new environment into global vars */
152146515Sru  current_env_no = n;
153146515Sru  e = &envs[current_env_no];
154146515Sru  output_paragraph = e->output_paragraph;
155146515Sru  output_paragraph_offset = e->output_paragraph_offset;
156146515Sru  meta_char_pos = e->meta_char_pos;
157146515Sru  output_column = e->output_column;
158146515Sru  paragraph_is_open = e->paragraph_is_open;
159146515Sru  current_indent = e->current_indent;
160146515Sru  fill_column = e->fill_column;
161146515Sru  return old_env_no;
162146515Sru}
163146515Sru
164146515Sru/* Initialize environment number ENV_NO, of width WIDTH.
165146515Sru   The idea is that we're going to use one environment for each column of
166146515Sru   a multitable, so we can build them up separately and print them
167146515Sru   all out at the end. */
168146515Srustatic int
169146515Srusetup_output_environment (int env_no, int width)
170146515Sru{
171146515Sru  int old_env = select_output_environment (env_no);
172146515Sru
173146515Sru  /* clobber old environment and set width of new one */
174146515Sru  init_paragraph ();
175146515Sru
176146515Sru  /* make our change */
177146515Sru  fill_column = width;
178146515Sru
179146515Sru  /* Save new environment and restore previous one. */
180146515Sru  select_output_environment (old_env);
181146515Sru
182146515Sru  return env_no;
183146515Sru}
184146515Sru
18521495Sjmacd/* Read the parameters for a multitable from the current command
18621495Sjmacd   line, save the parameters away, and return the
18721495Sjmacd   number of columns. */
188146515Srustatic int
189146515Srusetup_multitable_parameters (void)
19021495Sjmacd{
19121495Sjmacd  char *params = insertion_stack->item_function;
19221495Sjmacd  int nchars;
19321495Sjmacd  float columnfrac;
19456160Sru  char command[200]; /* xx no fixed limits */
19521495Sjmacd  int i = 1;
19621495Sjmacd
19721495Sjmacd  /* We implement @hsep and @vsep even though TeX doesn't.
19821495Sjmacd     We don't get mixing of @columnfractions and templates right,
19921495Sjmacd     but TeX doesn't either.  */
20021495Sjmacd  hsep = vsep = 0;
20121495Sjmacd
202146515Sru  /* Assume no @columnfractions per default.  */
203146515Sru  seen_column_fractions = 0;
204146515Sru
20521495Sjmacd  while (*params) {
20621495Sjmacd    while (whitespace (*params))
20721495Sjmacd      params++;
20821495Sjmacd
20921495Sjmacd    if (*params == '@') {
21042660Smarkm      sscanf (params, "%200s", command);
21142660Smarkm      nchars = strlen (command);
21221495Sjmacd      params += nchars;
21321495Sjmacd      if (strcmp (command, "@hsep") == 0)
21442660Smarkm        hsep++;
21521495Sjmacd      else if (strcmp (command, "@vsep") == 0)
21642660Smarkm        vsep++;
21721495Sjmacd      else if (strcmp (command, "@columnfractions") == 0) {
218146515Sru        seen_column_fractions = 1;
21942660Smarkm        /* Clobber old environments and create new ones, starting at #1.
22042660Smarkm           Environment #0 is the normal output, so don't mess with it. */
22142660Smarkm        for ( ; i <= MAXCOLS; i++) {
22242660Smarkm          if (sscanf (params, "%f", &columnfrac) < 1)
22342660Smarkm            goto done;
22456160Sru          /* Unfortunately, can't use %n since m68k-hp-bsd libc (at least)
22542660Smarkm             doesn't support it.  So skip whitespace (preceding the
22642660Smarkm             number) and then non-whitespace (the number).  */
22742660Smarkm          while (*params && (*params == ' ' || *params == '\t'))
22842660Smarkm            params++;
229146515Sru          /* Hmm, but what about @columnfractions 3foo.  Oh well,
23042660Smarkm             it's invalid input anyway.  */
23142660Smarkm          while (*params && *params != ' ' && *params != '\t'
23242660Smarkm                 && *params != '\n' && *params != '@')
23342660Smarkm            params++;
234146515Sru
235146515Sru          {
236146515Sru            /* For html/xml/docbook, translate fractions into integer
237146515Sru               percentages, adding .005 to avoid rounding problems.  For
238146515Sru               info, we want the character width.  */
239146515Sru            int width = xml || html ? (columnfrac + .005) * 100
240146515Sru                        : (columnfrac * (fill_column - current_indent) + .5);
241146515Sru            setup_output_environment (i, width);
242146515Sru          }
24342660Smarkm        }
24421495Sjmacd      }
24521495Sjmacd
24621495Sjmacd    } else if (*params == '{') {
24756160Sru      unsigned template_width = find_template_width (&params);
248146515Sru
24921495Sjmacd      /* This gives us two spaces between columns.  Seems reasonable.
25056160Sru         How to take into account current_indent here?  */
25156160Sru      setup_output_environment (i++, template_width + 2);
25221495Sjmacd
25321495Sjmacd    } else {
25442660Smarkm      warning (_("ignoring stray text `%s' after @multitable"), params);
25521495Sjmacd      break;
25621495Sjmacd    }
25721495Sjmacd  }
25821495Sjmacd
25921495Sjmacddone:
26021495Sjmacd  flush_output ();
26121495Sjmacd  inhibit_output_flushing ();
26221495Sjmacd
26321495Sjmacd  last_column = i - 1;
26421495Sjmacd  return last_column;
26521495Sjmacd}
26621495Sjmacd
267146515Sru/* Output a row.  Calls insert, but also flushes the buffered output
268146515Sru   when we see a newline, since in multitable every line is a separate
269146515Sru   paragraph.  */
270146515Srustatic void
271146515Sruout_char (int ch)
27221495Sjmacd{
273146515Sru  if (html || xml)
274146515Sru    add_char (ch);
275146515Sru  else
276146515Sru    {
277146515Sru      int env = select_output_environment (0);
278146515Sru      insert (ch);
279146515Sru      if (ch == '\n')
280146515Sru	{
281146515Sru	  uninhibit_output_flushing ();
282146515Sru	  flush_output ();
283146515Sru	  inhibit_output_flushing ();
284146515Sru	}
285146515Sru      select_output_environment (env);
286146515Sru    }
287146515Sru}
28821495Sjmacd
28921495Sjmacd
290146515Srustatic void
291146515Srudraw_horizontal_separator (void)
292146515Sru{
293146515Sru  int i, j, s;
29421495Sjmacd
295146515Sru  if (html)
296146515Sru    {
297146515Sru      add_word ("<hr>");
298146515Sru      return;
299146515Sru    }
300146515Sru  if (xml)
301146515Sru    return;
30221495Sjmacd
303146515Sru  for (s = 0; s < envs[0].current_indent; s++)
304146515Sru    out_char (' ');
305146515Sru  if (vsep)
306146515Sru    out_char ('+');
307146515Sru  for (i = 1; i <= last_column; i++) {
308146515Sru    for (j = 0; j <= envs[i].fill_column; j++)
309146515Sru      out_char ('-');
310146515Sru    if (vsep)
311146515Sru      out_char ('+');
312146515Sru  }
313146515Sru  out_char (' ');
314146515Sru  out_char ('\n');
31521495Sjmacd}
31621495Sjmacd
317146515Sru
318146515Sru/* multitable strategy:
319146515Sru    for each item {
320146515Sru       for each column in an item {
321146515Sru        initialize a new paragraph
322146515Sru        do ordinary formatting into the new paragraph
323146515Sru        save the paragraph away
324146515Sru        repeat if there are more paragraphs in the column
325146515Sru      }
326146515Sru      dump out the saved paragraphs and free the storage
327146515Sru    }
328146515Sru
329146515Sru   For HTML we construct a simple HTML 3.2 table with <br>s inserted
330146515Sru   to help non-tables browsers.  `@item' inserts a <tr> and `@tab'
331146515Sru   inserts <td>; we also try to close <tr>.  The only real
332146515Sru   alternative is to rely on the info formatting engine and present
333146515Sru   preformatted text.  */
334146515Sru
335146515Sruvoid
336146515Srudo_multitable (void)
33721495Sjmacd{
338146515Sru  int ncolumns;
33921495Sjmacd
340146515Sru  if (multitable_active)
341146515Sru    {
342146515Sru      line_error ("Multitables cannot be nested");
343146515Sru      return;
344146515Sru    }
34521495Sjmacd
346146515Sru  close_single_paragraph ();
347146515Sru
348146515Sru  if (xml)
349146515Sru    {
350146515Sru      xml_no_para = 1;
351146515Sru      if (output_paragraph[output_paragraph_offset-1] == '\n')
352146515Sru        output_paragraph_offset--;
353146515Sru    }
354146515Sru
355146515Sru  /* scan the current item function to get the field widths
356146515Sru     and number of columns, and set up the output environment list
357146515Sru     accordingly. */
358146515Sru  ncolumns = setup_multitable_parameters ();
359146515Sru  first_row = 1;
360146515Sru
361146515Sru  /* <p> for non-tables browsers.  @multitable implicitly ends the
362146515Sru     current paragraph, so this is ok.  */
363146515Sru  if (html)
364146515Sru    add_html_block_elt ("<p><table summary=\"\">");
365146515Sru  /*  else if (docbook)*/ /* 05-08 */
366146515Sru  else if (xml)
367146515Sru    {
368146515Sru      int *widths = xmalloc (ncolumns * sizeof (int));
369146515Sru      int i;
370146515Sru      for (i=0; i<ncolumns; i++)
371146515Sru	widths[i] = envs[i+1].fill_column;
372146515Sru      xml_begin_multitable (ncolumns, widths);
373146515Sru      free (widths);
374146515Sru    }
375146515Sru
376146515Sru  if (hsep)
377146515Sru    draw_horizontal_separator ();
378146515Sru
379146515Sru  /* The next @item command will direct stdout into the first column
380146515Sru     and start processing.  @tab will then switch to the next column,
381146515Sru     and @item will flush out the saved output and return to the first
382146515Sru     column.  Environment #1 is the first column.  (Environment #0 is
383146515Sru     the normal output) */
384146515Sru
385146515Sru  ++multitable_active;
38621495Sjmacd}
38721495Sjmacd
38821495Sjmacd/* advance to the next environment number */
389146515Srustatic void
390146515Srunselect_next_environment (void)
39121495Sjmacd{
39221495Sjmacd  if (current_env_no >= last_column) {
39342660Smarkm    line_error (_("Too many columns in multitable item (max %d)"), last_column);
39442660Smarkm    return;
39521495Sjmacd  }
39621495Sjmacd  select_output_environment (current_env_no + 1);
39721495Sjmacd}
39821495Sjmacd
39921495Sjmacd
40042660Smarkm/* do anything needed at the beginning of processing a
40142660Smarkm   multitable column. */
402146515Srustatic void
403146515Sruinit_column (void)
40442660Smarkm{
40542660Smarkm  /* don't indent 1st paragraph in the item */
40642660Smarkm  cm_noindent ();
40742660Smarkm
40842660Smarkm  /* throw away possible whitespace after @item or @tab command */
40942660Smarkm  skip_whitespace ();
41042660Smarkm}
41142660Smarkm
41221495Sjmacdstatic void
413146515Sruoutput_multitable_row (void)
41421495Sjmacd{
41521495Sjmacd  /* offset in the output paragraph of the next char needing
41621495Sjmacd     to be output for that column. */
41721495Sjmacd  int offset[MAXCOLS];
41856160Sru  int i, j, s, remaining;
41956160Sru  int had_newline = 0;
42021495Sjmacd
42121495Sjmacd  for (i = 0; i <= last_column; i++)
42221495Sjmacd    offset[i] = 0;
42321495Sjmacd
42421495Sjmacd  /* select the current environment, to make sure the env variables
42521495Sjmacd     get updated */
42621495Sjmacd  select_output_environment (current_env_no);
42721495Sjmacd
42821495Sjmacd#define CHAR_ADDR(n) (offset[i] + (n))
42921495Sjmacd#define CHAR_AT(n) (envs[i].output_paragraph[CHAR_ADDR(n)])
43021495Sjmacd
43121495Sjmacd  /* remove trailing whitespace from each column */
43221495Sjmacd  for (i = 1; i <= last_column; i++) {
43356160Sru    if (envs[i].output_paragraph_offset)
43456160Sru      while (cr_or_whitespace (CHAR_AT (envs[i].output_paragraph_offset - 1)))
43556160Sru        envs[i].output_paragraph_offset--;
43656160Sru
43756160Sru    if (i == current_env_no)
43856160Sru      output_paragraph_offset = envs[i].output_paragraph_offset;
43921495Sjmacd  }
44021495Sjmacd
44121495Sjmacd  /* read the current line from each column, outputting them all
44221495Sjmacd     pasted together.  Do this til all lines are output from all
44321495Sjmacd     columns.  */
44421495Sjmacd  for (;;) {
44521495Sjmacd    remaining = 0;
44621495Sjmacd    /* first, see if there is any work to do */
44721495Sjmacd    for (i = 1; i <= last_column; i++) {
44821495Sjmacd      if (CHAR_ADDR (0) < envs[i].output_paragraph_offset) {
44942660Smarkm        remaining = 1;
45042660Smarkm        break;
45121495Sjmacd      }
45221495Sjmacd    }
45321495Sjmacd    if (!remaining)
45421495Sjmacd      break;
45542660Smarkm
45642660Smarkm    for (s = 0; s < envs[0].current_indent; s++)
45742660Smarkm      out_char (' ');
45842660Smarkm
45921495Sjmacd    if (vsep)
46021495Sjmacd      out_char ('|');
46121495Sjmacd
46221495Sjmacd    for (i = 1; i <= last_column; i++) {
46356160Sru      for (s = 0; s < envs[i].current_indent; s++)
46442660Smarkm        out_char (' ');
46521495Sjmacd      for (j = 0; CHAR_ADDR (j) < envs[i].output_paragraph_offset; j++) {
46642660Smarkm        if (CHAR_AT (j) == '\n')
46742660Smarkm          break;
46842660Smarkm        out_char (CHAR_AT (j));
46921495Sjmacd      }
47042660Smarkm      offset[i] += j + 1;       /* skip last text plus skip the newline */
47156160Sru
47256160Sru      /* Do not output trailing blanks if we're in the last column and
47356160Sru         there will be no trailing |.  */
47456160Sru      if (i < last_column && !vsep)
47556160Sru        for (; j <= envs[i].fill_column; j++)
47656160Sru          out_char (' ');
47721495Sjmacd      if (vsep)
47842660Smarkm        out_char ('|'); /* draw column separator */
47921495Sjmacd    }
48042660Smarkm    out_char ('\n');    /* end of line */
48156160Sru    had_newline = 1;
48221495Sjmacd  }
48356160Sru
48456160Sru  /* If completely blank item, get blank line despite no other output.  */
48556160Sru  if (!had_newline)
48656160Sru    out_char ('\n');    /* end of line */
48721495Sjmacd
48821495Sjmacd  if (hsep)
48921495Sjmacd    draw_horizontal_separator ();
49021495Sjmacd
49121495Sjmacd  /* Now dispose of the buffered output. */
49221495Sjmacd  for (i = 1; i <= last_column; i++) {
49321495Sjmacd    select_output_environment (i);
49421495Sjmacd    init_paragraph ();
49521495Sjmacd  }
49621495Sjmacd}
49721495Sjmacd
498146515Sruint after_headitem = 0;
499146515Sruint headitem_row = 0;
500146515Sru
501146515Sru/* start a new item (row) of a multitable */
502146515Sruint
503146515Srumultitable_item (void)
504146515Sru{
505146515Sru  if (!multitable_active) {
506146515Sru    line_error ("multitable_item internal error: no active multitable");
507146515Sru    xexit (1);
508146515Sru  }
509146515Sru
510146515Sru  current_column_no = 1;
511146515Sru
512146515Sru  if (html)
513146515Sru    {
514146515Sru      if (!first_row)
515146515Sru        /* <br> for non-tables browsers. */
516146515Sru	add_word_args ("<br></%s></tr>", after_headitem ? "th" : "td");
517146515Sru
518146515Sru      if (seen_column_fractions)
519146515Sru        add_word_args ("<tr align=\"left\"><%s valign=\"top\" width=\"%d%%\">",
520146515Sru            headitem_flag ? "th" : "td",
521146515Sru            envs[current_column_no].fill_column);
522146515Sru      else
523146515Sru        add_word_args ("<tr align=\"left\"><%s valign=\"top\">",
524146515Sru            headitem_flag ? "th" : "td");
525146515Sru
526146515Sru      if (headitem_flag)
527146515Sru        after_headitem = 1;
528146515Sru      else
529146515Sru        after_headitem = 0;
530146515Sru      first_row = 0;
531146515Sru      headitem_row = headitem_flag;
532146515Sru      headitem_flag = 0;
533146515Sru      return 0;
534146515Sru    }
535146515Sru  /*  else if (docbook)*/ /* 05-08 */
536146515Sru  else if (xml)
537146515Sru    {
538146515Sru      xml_end_multitable_row (first_row);
539146515Sru      if (headitem_flag)
540146515Sru        after_headitem = 1;
541146515Sru      else
542146515Sru        after_headitem = 0;
543146515Sru      first_row = 0;
544146515Sru      headitem_flag = 0;
545146515Sru      return 0;
546146515Sru    }
547146515Sru  first_row = 0;
548146515Sru
549146515Sru  if (current_env_no > 0) {
550146515Sru    output_multitable_row ();
551146515Sru  }
552146515Sru  /* start at column 1 */
553146515Sru  select_output_environment (1);
554146515Sru  if (!output_paragraph) {
555146515Sru    line_error (_("[unexpected] cannot select column #%d in multitable"),
556146515Sru                current_env_no);
557146515Sru    xexit (1);
558146515Sru  }
559146515Sru
560146515Sru  init_column ();
561146515Sru
562146515Sru  if (headitem_flag)
563146515Sru    hsep = 1;
564146515Sru  else
565146515Sru    hsep = 0;
566146515Sru
567146515Sru  if (headitem_flag)
568146515Sru    after_headitem = 1;
569146515Sru  else
570146515Sru    after_headitem = 0;
571146515Sru  headitem_flag = 0;
572146515Sru
573146515Sru  return 0;
574146515Sru}
575146515Sru
57621495Sjmacd#undef CHAR_AT
57721495Sjmacd#undef CHAR_ADDR
57821495Sjmacd
57921495Sjmacd/* select a new column in current row of multitable */
58021495Sjmacdvoid
581146515Srucm_tab (void)
58221495Sjmacd{
58321495Sjmacd  if (!multitable_active)
58442660Smarkm    error (_("ignoring @tab outside of multitable"));
585146515Sru
586146515Sru  current_column_no++;
58721495Sjmacd
58856160Sru  if (html)
589146515Sru    {
590146515Sru      if (seen_column_fractions)
591146515Sru        add_word_args ("</%s><%s valign=\"top\" width=\"%d%%\">",
592146515Sru            headitem_row ? "th" : "td",
593146515Sru            headitem_row ? "th" : "td",
594146515Sru            envs[current_column_no].fill_column);
595146515Sru      else
596146515Sru        add_word_args ("</%s><%s valign=\"top\">",
597146515Sru            headitem_row ? "th" : "td",
598146515Sru            headitem_row ? "th" : "td");
599146515Sru    }
60093139Sru  /*  else if (docbook)*/ /* 05-08 */
60193139Sru  else if (xml)
60293139Sru    xml_end_multitable_column ();
60356160Sru  else
60456160Sru    nselect_next_environment ();
60556160Sru
60621495Sjmacd  init_column ();
60721495Sjmacd}
60821495Sjmacd
60921495Sjmacd/* close a multitable, flushing its output and resetting
61021495Sjmacd   whatever needs resetting */
61121495Sjmacdvoid
612146515Sruend_multitable (void)
61321495Sjmacd{
61493139Sru  if (!html && !docbook)
61556160Sru    output_multitable_row ();
61621495Sjmacd
61721495Sjmacd  /* Multitables cannot be nested.  Otherwise, we'd have to save the
61821495Sjmacd     previous output environment number on a stack somewhere, and then
61921495Sjmacd     restore to that environment.  */
62021495Sjmacd  select_output_environment (0);
62121495Sjmacd  multitable_active = 0;
62221495Sjmacd  uninhibit_output_flushing ();
62356160Sru  close_insertion_paragraph ();
62421495Sjmacd
62556160Sru  if (html)
626146515Sru    add_word_args ("<br></%s></tr></table>\n", headitem_row ? "th" : "td");
62793139Sru  /*  else if (docbook)*/ /* 05-08 */
62893139Sru  else if (xml)
62993139Sru    xml_end_multitable ();
63056160Sru
63121495Sjmacd#if 0
63242660Smarkm  printf (_("** Multicolumn output from last row:\n"));
63321495Sjmacd  for (i = 1; i <= last_column; i++) {
63421495Sjmacd    select_output_environment (i);
63542660Smarkm    printf (_("* column #%d: output = %s\n"), i, output_paragraph);
63621495Sjmacd  }
63721495Sjmacd#endif
63821495Sjmacd}
639