* haifa-sched.c (schedule_insns): Don't assign LUIDs differently
[official-gcc.git] / texinfo / makeinfo / multi.c
blobf5b1fe9fe6188711e6c68e4775e2cdbab884f90c
1 /* multi.c -- multitable stuff for makeinfo.
2 $Id: multi.c,v 1.2 1998/03/24 18:07:57 law Exp $
4 Copyright (C) 1996, 97 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include "system.h"
21 #include "makeinfo.h"
23 #define MAXCOLS 100 /* remove this limit later @@ */
27 * Output environments. This is a hack grafted onto existing
28 * structure. The "output environment" used to consist of the
29 * global variables `output_paragraph', `fill_column', etc.
30 * Routines like add_char would manipulate these variables.
32 * Now, when formatting a multitable, we maintain separate environments
33 * for each column. That way we can build up the columns separately
34 * and write them all out at once. The "current" output environment"
35 * is still kept in those global variables, so that the old output
36 * routines don't have to change. But we provide routines to save
37 * and restore these variables in an "environment table". The
38 * `select_output_environment' function switches from one output
39 * environment to another.
41 * Environment #0 (i.e., element #0 of the table) is the regular
42 * environment that is used when we're not formatting a multitable.
44 * Environment #N (where N = 1,2,3,...) is the env. for column #N of
45 * the table, when a multitable is active.
48 /* contents of an output environment */
49 /* some more vars may end up being needed here later @@ */
50 struct env
52 unsigned char *output_paragraph;
53 int output_paragraph_offset;
54 int output_column;
55 int paragraph_is_open;
56 int current_indent;
57 int fill_column;
58 } envs[MAXCOLS]; /* the environment table */
60 /* index in environment table of currently selected environment */
61 static int current_env_no;
63 /* column number of last column in current multitable */
64 static int last_column;
66 /* flags indicating whether horizontal and vertical separators need
67 to be drawn, separating rows and columns in the current multitable. */
68 static int hsep, vsep;
70 /* Output a row. Have to keep `output_position' up-to-date for each
71 character we output, or the tags table will be off, leading to
72 chopped-off output files and undefined nodes (because they're in the
73 wrong file, etc.). Perhaps it would be better to accumulate this
74 value somewhere and add it once at the end of the table, or return it
75 as the value, but this seems simplest. */
76 static void
77 out_char (ch)
78 int ch;
80 extern int output_position;
81 putc (ch, output_stream);
82 output_position++;
86 void
87 draw_horizontal_separator ()
89 int i, j, s;
91 for (s = 0; s < envs[0].current_indent; s++)
92 out_char (' ');
93 if (vsep)
94 out_char ('+');
95 for (i = 1; i <= last_column; i++) {
96 for (j = 0; j <= envs[i].fill_column; j++)
97 out_char ('-');
98 if (vsep)
99 out_char ('+');
101 out_char ('\n');
104 void
105 do_multitable ()
107 int ncolumns;
110 * multitable strategy:
111 * for each item {
112 * for each column in an item {
113 * initialize a new paragraph
114 * do ordinary formatting into the new paragraph
115 * save the paragraph away
116 * repeat if there are more paragraphs in the column
118 * dump out the saved paragraphs and free the storage
122 if (multitable_active)
124 line_error ("Multitables cannot be nested");
125 return;
128 /* scan the current item function to get the field widths
129 and number of columns, and set up the output environment list
130 accordingly. */
131 ncolumns = setup_multitable_parameters ();
132 if (hsep)
133 draw_horizontal_separator ();
135 /* The next @item command will direct stdout into the first column
136 and start processing. @tab will then switch to the next column,
137 and @item will flush out the saved output and return to the first
138 column. Environment #1 is the first column. (Environment #0 is
139 the normal output) */
141 ++multitable_active;
144 /* Read the parameters for a multitable from the current command
145 line, save the parameters away, and return the
146 number of columns. */
148 setup_multitable_parameters ()
150 char *params = insertion_stack->item_function;
151 int nchars;
152 float columnfrac;
153 char command[200]; /* naughty, should be no fixed limits */
154 int i = 1;
156 /* We implement @hsep and @vsep even though TeX doesn't.
157 We don't get mixing of @columnfractions and templates right,
158 but TeX doesn't either. */
159 hsep = vsep = 0;
161 while (*params) {
162 while (whitespace (*params))
163 params++;
165 if (*params == '@') {
166 sscanf (params, "%200s", command);
167 nchars = strlen (command);
168 params += nchars;
169 if (strcmp (command, "@hsep") == 0)
170 hsep++;
171 else if (strcmp (command, "@vsep") == 0)
172 vsep++;
173 else if (strcmp (command, "@columnfractions") == 0) {
174 /* Clobber old environments and create new ones, starting at #1.
175 Environment #0 is the normal output, so don't mess with it. */
176 for ( ; i <= MAXCOLS; i++) {
177 if (sscanf (params, "%f", &columnfrac) < 1)
178 goto done;
179 /* Unfortunately, can't use %n since some m68k-hp-bsd libc
180 doesn't support it. So skip whitespace (preceding the
181 number) and then non-whitespace (the number). */
182 while (*params && (*params == ' ' || *params == '\t'))
183 params++;
184 /* Hmm, but what about @columnfractions 3foo? Well, I suppose
185 it's invalid input anyway. */
186 while (*params && *params != ' ' && *params != '\t'
187 && *params != '\n' && *params != '@')
188 params++;
189 setup_output_environment (i,
190 (int) (columnfrac * (fill_column - current_indent) + .5));
194 } else if (*params == '{') {
195 char *start = params;
196 while ((*params != '}' || params[-1] == '@') && *params) {
197 params++;
199 /* This gives us two spaces between columns. Seems reasonable.
200 Really should expand the text, though, so a template of
201 `@code{foo}' has a width of five, not ten. Also have to match
202 braces, then. How to take into account current_indent here? */
203 setup_output_environment (i++, params++ - start);
205 } else {
206 warning (_("ignoring stray text `%s' after @multitable"), params);
207 break;
211 done:
212 flush_output ();
213 inhibit_output_flushing ();
215 last_column = i - 1;
216 return last_column;
219 /* Initialize environment number ENV_NO, of width WIDTH.
220 The idea is that we're going to use one environment for each column of
221 a multitable, so we can build them up separately and print them
222 all out at the end. */
224 setup_output_environment (env_no, width)
225 int env_no;
226 int width;
228 int old_env = select_output_environment (env_no);
230 /* clobber old environment and set width of new one */
231 init_paragraph ();
233 /* make our change */
234 fill_column = width;
236 /* Save new environment and restore previous one. */
237 select_output_environment (old_env);
239 return env_no;
242 /* Direct current output to environment number N. Used when
243 switching work from one column of a multitable to the next.
244 Returns previous environment number. */
245 int
246 select_output_environment (n)
247 int n;
249 struct env *e = &envs[current_env_no];
250 int old_env_no = current_env_no;
252 /* stash current env info from global vars into the old environment */
253 e->output_paragraph = output_paragraph;
254 e->output_paragraph_offset = output_paragraph_offset;
255 e->output_column = output_column;
256 e->paragraph_is_open = paragraph_is_open;
257 e->current_indent = current_indent;
258 e->fill_column = fill_column;
260 /* now copy new environment into global vars */
261 current_env_no = n;
262 e = &envs[current_env_no];
263 output_paragraph = e->output_paragraph;
264 output_paragraph_offset = e->output_paragraph_offset;
265 output_column = e->output_column;
266 paragraph_is_open = e->paragraph_is_open;
267 current_indent = e->current_indent;
268 fill_column = e->fill_column;
269 return old_env_no;
272 /* advance to the next environment number */
273 void
274 nselect_next_environment ()
276 if (current_env_no >= last_column) {
277 line_error (_("Too many columns in multitable item (max %d)"), last_column);
278 return;
280 select_output_environment (current_env_no + 1);
284 static void output_multitable_row ();
286 /* do anything needed at the beginning of processing a
287 multitable column. */
288 void
289 init_column ()
291 /* don't indent 1st paragraph in the item */
292 cm_noindent ();
294 /* throw away possible whitespace after @item or @tab command */
295 skip_whitespace ();
298 /* start a new item (row) of a multitable */
300 multitable_item ()
302 if (!multitable_active) {
303 /* impossible, I think. */
304 error (_("multitable item not in active multitable"));
305 exit (1);
307 if (current_env_no > 0) {
308 output_multitable_row ();
310 /* start at column 1 */
311 select_output_environment (1);
312 if (!output_paragraph) {
313 line_error (_("Cannot select column #%d in multitable"), current_env_no);
314 exit (FATAL);
317 init_column ();
319 return 0;
322 static void
323 output_multitable_row ()
325 int i, j, s, remaining;
327 /* offset in the output paragraph of the next char needing
328 to be output for that column. */
329 int offset[MAXCOLS];
331 for (i = 0; i <= last_column; i++)
332 offset[i] = 0;
334 /* select the current environment, to make sure the env variables
335 get updated */
336 select_output_environment (current_env_no);
338 #define CHAR_ADDR(n) (offset[i] + (n))
339 #define CHAR_AT(n) (envs[i].output_paragraph[CHAR_ADDR(n)])
341 /* remove trailing whitespace from each column */
342 for (i = 1; i <= last_column; i++) {
343 while (cr_or_whitespace (CHAR_AT (envs[i].output_paragraph_offset - 1))) {
344 envs[i].output_paragraph_offset--;
348 /* read the current line from each column, outputting them all
349 pasted together. Do this til all lines are output from all
350 columns. */
351 for (;;) {
352 remaining = 0;
353 /* first, see if there is any work to do */
354 for (i = 1; i <= last_column; i++) {
355 if (CHAR_ADDR (0) < envs[i].output_paragraph_offset) {
356 remaining = 1;
357 break;
360 if (!remaining)
361 break;
363 for (s = 0; s < envs[0].current_indent; s++)
364 out_char (' ');
366 if (vsep)
367 out_char ('|');
369 for (i = 1; i <= last_column; i++) {
370 for (s = 0; i < envs[i].current_indent; s++)
371 out_char (' ');
372 for (j = 0; CHAR_ADDR (j) < envs[i].output_paragraph_offset; j++) {
373 if (CHAR_AT (j) == '\n')
374 break;
375 out_char (CHAR_AT (j));
377 offset[i] += j + 1; /* skip last text plus skip the newline */
378 for (; j <= envs[i].fill_column; j++)
379 out_char (' ');
380 if (vsep)
381 out_char ('|'); /* draw column separator */
383 out_char ('\n'); /* end of line */
386 if (hsep)
387 draw_horizontal_separator ();
389 /* Now dispose of the buffered output. */
390 for (i = 1; i <= last_column; i++) {
391 select_output_environment (i);
392 init_paragraph ();
396 #undef CHAR_AT
397 #undef CHAR_ADDR
399 /* select a new column in current row of multitable */
400 void
401 cm_tab ()
403 if (!multitable_active)
404 error (_("ignoring @tab outside of multitable"));
406 nselect_next_environment ();
407 init_column ();
410 /* close a multitable, flushing its output and resetting
411 whatever needs resetting */
412 void
413 end_multitable ()
415 output_multitable_row ();
417 /* Multitables cannot be nested. Otherwise, we'd have to save the
418 previous output environment number on a stack somewhere, and then
419 restore to that environment. */
420 select_output_environment (0);
421 close_paragraph ();
422 insert ('\n'); /* we swallow newlines, so insert one of our own */
424 multitable_active = 0;
425 uninhibit_output_flushing ();
427 #if 0
428 printf (_("** Multicolumn output from last row:\n"));
429 for (i = 1; i <= last_column; i++) {
430 select_output_environment (i);
431 printf (_("* column #%d: output = %s\n"), i, output_paragraph);
433 #endif