1146515Sru/* float.c -- float environment functions.
2146515Sru   $Id: float.c,v 1.8 2004/07/05 22:23:22 karl Exp $
3146515Sru
4146515Sru   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
5146515Sru
6146515Sru   This program is free software; you can redistribute it and/or modify
7146515Sru   it under the terms of the GNU General Public License as published by
8146515Sru   the Free Software Foundation; either version 2, or (at your option)
9146515Sru   any later version.
10146515Sru
11146515Sru   This program is distributed in the hope that it will be useful,
12146515Sru   but WITHOUT ANY WARRANTY; without even the implied warranty of
13146515Sru   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14146515Sru   GNU General Public License for more details.
15146515Sru
16146515Sru   You should have received a copy of the GNU General Public License
17146515Sru   along with this program; if not, write to the Free Software
18146515Sru   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19146515Sru
20146515Sru   Originally written by Alper Ersoy <dirt@gtk.org>.  */
21146515Sru
22146515Sru#include "system.h"
23146515Sru#include "makeinfo.h"
24146515Sru#include "cmds.h"
25146515Sru#include "files.h"
26146515Sru#include "float.h"
27146515Sru#include "html.h"
28146515Sru#include "sectioning.h"
29146515Sru#include "xml.h"
30146515Sru
31146515Srustatic FLOAT_ELT *float_stack = NULL;
32146515Sru
33146515Sruvoid
34146515Sruadd_new_float (char *id, char *title, char *shorttitle,
35146515Sru    char *type, char *position)
36146515Sru{
37146515Sru  FLOAT_ELT *new = xmalloc (sizeof (FLOAT_ELT));
38146515Sru  unsigned long num_len;
39146515Sru
40146515Sru  new->id = id;
41146515Sru  new->type = type;
42146515Sru  new->title = title;
43146515Sru  new->shorttitle = shorttitle;
44146515Sru  new->position = position;
45146515Sru  new->title_used = 0;
46146515Sru  new->defining_line = line_number - 1;
47146515Sru
48146515Sru  new->number = current_chapter_number ();
49146515Sru  /* Append dot if not @unnumbered.  */
50146515Sru  num_len = strlen (new->number);
51146515Sru  if (num_len > 0)
52146515Sru    {
53146515Sru      new->number = xrealloc (new->number, num_len + 1 + 1);
54146515Sru      new->number[num_len] = '.';
55146515Sru      new->number[num_len+1] = '\0';
56146515Sru    }
57146515Sru
58146515Sru  { /* Append the current float number.  */
59146515Sru    unsigned len = strlen (new->number) + 21;  /* that's 64 bits */
60146515Sru    char *s = xmalloc (len + 1);
61146515Sru
62146515Sru    sprintf (s, "%s%d", new->number,
63146515Sru                count_floats_of_type_in_chapter (text_expansion (type),
64146515Sru                                                 new->number) + 1);
65146515Sru    free (new->number);
66146515Sru    new->number = xstrdup (s);
67146515Sru  }
68146515Sru
69146515Sru  /* Plain text output needs sectioning number and its title,
70146515Sru     when listing floats.  */
71146515Sru  if (!html && !xml && no_headers)
72146515Sru    {
73146515Sru      new->section = current_sectioning_number ();
74146515Sru      if (strlen (new->section) == 0)
75146515Sru        new->section_name = current_sectioning_name ();
76146515Sru      else
77146515Sru        new->section_name = "";
78146515Sru    }
79146515Sru
80146515Sru  new->next = float_stack;
81146515Sru  float_stack = new;
82146515Sru}
83146515Sru
84146515Sruint
85146515Srucount_floats_of_type_in_chapter (char *type, char *chapter)
86146515Sru{
87146515Sru  int i = 0;
88146515Sru  int l = strlen (chapter);
89146515Sru  FLOAT_ELT *temp = float_stack;
90146515Sru
91146515Sru  while (temp && strncmp (temp->number, chapter, l) == 0)
92146515Sru    {
93146515Sru      if (strlen (temp->id) > 0 && STREQ (text_expansion (temp->type), type))
94146515Sru        i++;
95146515Sru      temp = temp->next;
96146515Sru    }
97146515Sru
98146515Sru  return i;
99146515Sru}
100146515Sru
101146515Sruchar *
102146515Srucurrent_float_title (void)
103146515Sru{
104146515Sru  return float_stack->title;
105146515Sru}
106146515Sru
107146515Sruchar *
108146515Srucurrent_float_shorttitle (void)
109146515Sru{
110146515Sru  return float_stack->shorttitle;
111146515Sru}
112146515Sru
113146515Sruchar *
114146515Srucurrent_float_type (void)
115146515Sru{
116146515Sru  return float_stack->type;
117146515Sru}
118146515Sru
119146515Sruchar *
120146515Srucurrent_float_position (void)
121146515Sru{
122146515Sru  return float_stack->position;
123146515Sru}
124146515Sru
125146515Sruchar *
126146515Srucurrent_float_number (void)
127146515Sru{
128146515Sru  return float_stack->number;
129146515Sru}
130146515Sru
131146515Sruchar *
132146515Srucurrent_float_id (void)
133146515Sru{
134146515Sru  return float_stack->id;
135146515Sru}
136146515Sru
137146515Sruchar *
138146515Sruget_float_ref (char *id)
139146515Sru{
140146515Sru  FLOAT_ELT *temp = float_stack;
141146515Sru
142146515Sru  while (temp)
143146515Sru    {
144146515Sru      if (STREQ (id, temp->id))
145146515Sru        {
146146515Sru          char *s = xmalloc (strlen (temp->type) + strlen (temp->number) + 2);
147146515Sru          sprintf (s, "%s %s", temp->type, temp->number);
148146515Sru          return s;
149146515Sru        }
150146515Sru      temp = temp->next;
151146515Sru    }
152146515Sru
153146515Sru  return NULL;
154146515Sru}
155146515Sru
156146515Srustatic int
157146515Srufloat_type_exists (char *check_type)
158146515Sru{
159146515Sru  /* Check if the requested float_type exists in the floats stack.  */
160146515Sru  FLOAT_ELT *temp;
161146515Sru
162146515Sru  for (temp = float_stack; temp; temp = temp->next)
163146515Sru    if (STREQ (temp->type, check_type) && temp->id && *temp->id)
164146515Sru      return 1;
165146515Sru
166146515Sru  return 0;
167146515Sru}
168146515Sru
169146515Sruvoid
170146515Srucm_listoffloats (void)
171146515Sru{
172146515Sru  char *float_type;
173146515Sru  get_rest_of_line (1, &float_type);
174146515Sru
175146515Sru  /* get_rest_of_line increments the line number by one,
176146515Sru     so to make warnings/errors point to the correct line,
177146515Sru     we decrement the line_number again.  */
178146515Sru  if (!handling_delayed_writes)
179146515Sru    line_number--;
180146515Sru
181146515Sru  if (handling_delayed_writes && !float_type_exists (float_type))
182146515Sru    warning (_("Requested float type `%s' not previously used"), float_type);
183146515Sru
184146515Sru  if (xml)
185146515Sru    {
186146515Sru      xml_insert_element_with_attribute (LISTOFFLOATS, START,
187146515Sru          "type=\"%s\"", text_expansion (float_type));
188146515Sru      xml_insert_element (LISTOFFLOATS, END);
189146515Sru    }
190146515Sru  else if (!handling_delayed_writes)
191146515Sru    {
192146515Sru      int command_len = sizeof ("@ ") + strlen (command) + strlen (float_type);
193146515Sru      char *list_command = xmalloc (command_len + 1);
194146515Sru
195146515Sru      /* These are for the text following @listoffloats command.
196146515Sru         Handling them with delayed writes is too late.  */
197146515Sru      close_paragraph ();
198146515Sru      cm_noindent ();
199146515Sru
200146515Sru      sprintf (list_command, "@%s %s", command, float_type);
201146515Sru      register_delayed_write (list_command);
202146515Sru      free (list_command);
203146515Sru    }
204146515Sru  else if (float_type_exists (float_type))
205146515Sru    {
206146515Sru      FLOAT_ELT *temp = (FLOAT_ELT *) reverse_list
207146515Sru        ((GENERIC_LIST *) float_stack);
208146515Sru      FLOAT_ELT *new_start = temp;
209146515Sru
210146515Sru      if (html)
211146515Sru        insert_string ("<ul class=\"listoffloats\">\n");
212146515Sru      else
213146515Sru        {
214146515Sru          if (!no_headers)
215146515Sru            insert_string ("* Menu:\n\n");
216146515Sru        }
217146515Sru
218146515Sru      while (temp)
219146515Sru        {
220146515Sru          if (strlen (temp->id) > 0 && STREQ (float_type, temp->type))
221146515Sru            {
222146515Sru              if (html)
223146515Sru                {
224146515Sru                  /* A bit of space for HTML reabality.  */
225146515Sru                  insert_string ("  ");
226146515Sru                  add_html_block_elt ("<li>");
227146515Sru
228146515Sru                  /* Simply relying on @ref command doesn't work here, because
229146515Sru                     commas in the caption may confuse the argument parsing.  */
230146515Sru                  add_word ("<a href=\"");
231146515Sru                  add_anchor_name (temp->id, 1);
232146515Sru                  add_word ("\">");
233146515Sru
234146515Sru                  if (strlen (float_type) > 0)
235146515Sru                    execute_string ("%s", float_type);
236146515Sru
237146515Sru                  if (strlen (temp->id) > 0)
238146515Sru                    {
239146515Sru                      if (strlen (float_type) > 0)
240146515Sru                        add_char (' ');
241146515Sru
242146515Sru                      add_word (temp->number);
243146515Sru                    }
244146515Sru
245146515Sru                  if (strlen (temp->title) > 0)
246146515Sru                    {
247146515Sru                      if (strlen (float_type) > 0
248146515Sru                          || strlen (temp->id) > 0)
249146515Sru                        insert_string (": ");
250146515Sru
251146515Sru                      execute_string ("%s", temp->title);
252146515Sru                    }
253146515Sru
254146515Sru                  add_word ("</a>");
255146515Sru
256146515Sru                  add_html_block_elt ("</li>\n");
257146515Sru                }
258146515Sru              else
259146515Sru                {
260146515Sru                  char *entry;
261146515Sru                  char *raw_entry;
262146515Sru                  char *title = expansion (temp->title, 0);
263146515Sru
264146515Sru                  int len;
265146515Sru                  int aux_chars_len; /* these are asterisk, colon, etc.  */
266146515Sru                  int column_width; /* width of the first column in menus.  */
267146515Sru                  int number_len; /* length of Figure X.Y: etc.   */
268146515Sru                  int i = 0;
269146515Sru
270146515Sru                  /* Chosen widths are to match what @printindex produces.  */
271146515Sru                  if (no_headers)
272146515Sru                    {
273146515Sru                      column_width = 43;
274146515Sru                      /* We have only one auxiliary character, NULL.  */
275146515Sru                      aux_chars_len = sizeof ("");
276146515Sru                    }
277146515Sru                  else
278146515Sru                    {
279146515Sru                      column_width = 37;
280146515Sru                      /* We'll be adding an asterisk, followed by a space
281146515Sru                         and then a colon after the title, to construct a
282146515Sru                         proper menu item.  */
283146515Sru                      aux_chars_len = sizeof ("* :");
284146515Sru                    }
285146515Sru
286146515Sru                  /* Allocate enough space for possible expansion later.  */
287146515Sru                  raw_entry = (char *) xmalloc (strlen (float_type)
288146515Sru                      + strlen (temp->number) + strlen (title)
289146515Sru                      + sizeof (":  "));
290146515Sru
291146515Sru                  sprintf (raw_entry, "%s %s", float_type, temp->number);
292146515Sru
293146515Sru                  if (strlen (title) > 0)
294146515Sru                    strcat (raw_entry, ": ");
295146515Sru
296146515Sru                  number_len = strlen (raw_entry);
297146515Sru
298146515Sru                  len = strlen (title) + strlen (raw_entry);
299146515Sru
300146515Sru                  /* If we have a @shortcaption, try it if @caption is
301146515Sru                     too long to fit on a line.  */
302146515Sru                  if (len + aux_chars_len > column_width
303146515Sru                      && strlen (temp->shorttitle) > 0)
304146515Sru                    title = expansion (temp->shorttitle, 0);
305146515Sru
306146515Sru                  strcat (raw_entry, title);
307146515Sru                  len = strlen (raw_entry);
308146515Sru
309146515Sru                  if (len + aux_chars_len > column_width)
310146515Sru                    { /* Shorten long titles by looking for a space before
311146515Sru                         column_width - strlen (" ...").  */
312146515Sru                      /* -1 is for NULL, which is already in aux_chars_len.  */
313146515Sru                      aux_chars_len += sizeof ("...") - 1;
314146515Sru                      len = column_width - aux_chars_len;
315146515Sru                      while (raw_entry[len] != ' ' && len >= 0)
316146515Sru                        len--;
317146515Sru
318146515Sru                      /* Advance to the whitespace.  */
319146515Sru                      len++;
320146515Sru
321146515Sru                      /* If we are at the end of, say, Figure X.Y:, but
322146515Sru                         we have a title, then this means title does not
323146515Sru                         contain any whitespaces.  Or it may be that we
324146515Sru                         went as far as the beginning.  Just print as much
325146515Sru                         as possible of the title.  */
326146515Sru                      if (len == 0
327146515Sru                          || (len == number_len && strlen (title) > 0))
328146515Sru                        len = column_width - sizeof ("...");
329146515Sru
330146515Sru                      /* Break here.  */
331146515Sru                      raw_entry[len] = 0;
332146515Sru
333146515Sru                      entry = xmalloc (len + aux_chars_len);
334146515Sru
335146515Sru                      if (!no_headers)
336146515Sru                        strcpy (entry, "* ");
337146515Sru                      else
338146515Sru                        entry[0] = 0;
339146515Sru
340146515Sru                      strcat (entry, raw_entry);
341146515Sru                      strcat (entry, "...");
342146515Sru
343146515Sru                      if (!no_headers)
344146515Sru                        strcat (entry, ":");
345146515Sru                    }
346146515Sru                  else
347146515Sru                    {
348146515Sru                      entry = xmalloc (len + aux_chars_len);
349146515Sru
350146515Sru                      if (!no_headers)
351146515Sru                        strcpy (entry, "* ");
352146515Sru                      else
353146515Sru                        entry[0] = 0;
354146515Sru
355146515Sru                      strcat (entry, raw_entry);
356146515Sru
357146515Sru                      if (!no_headers)
358146515Sru                        strcat (entry, ":");
359146515Sru                    }
360146515Sru
361146515Sru                  insert_string (entry);
362146515Sru
363146515Sru                  i = strlen (entry);
364146515Sru                  /* We insert space chars until ``column_width + four spaces''
365146515Sru                     is reached, to make the layout the same with what we produce
366146515Sru                     for @printindex.  This is of course not obligatory, though
367146515Sru                     easier on the eye.  -1 is for NULL.  */
368146515Sru                  while (i < column_width + sizeof ("    ") - 1)
369146515Sru                    {
370146515Sru                      insert (' ');
371146515Sru                      i++;
372146515Sru                    }
373146515Sru
374146515Sru                  if (no_headers)
375146515Sru                    {
376146515Sru                      if (strlen (temp->section) > 0)
377146515Sru                        { /* We got your number.  */
378146515Sru                          insert_string ((char *) _("See "));
379146515Sru                          insert_string (temp->section);
380146515Sru                        }
381146515Sru                      else
382146515Sru                        { /* Sigh, @float in an @unnumbered. :-\  */
383146515Sru                          insert_string ("\n          ");
384146515Sru                          insert_string ((char *) _("See "));
385146515Sru                          insert_string ("``");
386146515Sru                          insert_string (expansion (temp->section_name, 0));
387146515Sru                          insert_string ("''");
388146515Sru                        }
389146515Sru                    }
390146515Sru                  else
391146515Sru                    insert_string (temp->id);
392146515Sru
393146515Sru                  insert_string (".\n");
394146515Sru
395146515Sru                  free (entry);
396146515Sru                  free (title);
397146515Sru                }
398146515Sru            }
399146515Sru          temp = temp->next;
400146515Sru        }
401146515Sru
402146515Sru      if (html)
403146515Sru        {
404146515Sru          inhibit_paragraph_indentation = 1;
405146515Sru          insert_string ("</ul>\n\n");
406146515Sru        }
407146515Sru      else
408146515Sru        insert ('\n');
409146515Sru
410146515Sru      /* Retain the original order of float stack.  */
411146515Sru      temp = new_start;
412146515Sru      float_stack = (FLOAT_ELT *) reverse_list ((GENERIC_LIST *) temp);
413146515Sru    }
414146515Sru
415146515Sru  free (float_type);
416146515Sru  /* Re-increment the line number, because get_rest_of_line
417146515Sru     left us looking at the next line after the command.  */
418146515Sru  line_number++;
419146515Sru}
420146515Sru
421146515Sruint
422146515Srucurrent_float_used_title (void)
423146515Sru{
424146515Sru	return float_stack->title_used;
425146515Sru}
426146515Sru
427146515Sruvoid current_float_set_title_used (void)
428146515Sru{
429146515Sru	float_stack->title_used = 1;
430146515Sru}
431