Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / texinfo / makeinfo / float.c
1 /* float.c -- float environment functions.
2    $Id: float.c,v 1.12 2007/07/01 21:20:32 karl Exp $
3
4    Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
5
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 3 of the License, or
9    (at your option) any later version.
10
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.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19    Originally written by Alper Ersoy <dirt@gtk.org>.  */
20
21 #include "system.h"
22 #include "makeinfo.h"
23 #include "cmds.h"
24 #include "files.h"
25 #include "float.h"
26 #include "html.h"
27 #include "sectioning.h"
28 #include "xml.h"
29
30 static FLOAT_ELT *float_stack = NULL;
31
32 void
33 add_new_float (char *id, char *title, char *shorttitle,
34     char *type, char *position)
35 {
36   FLOAT_ELT *new = xmalloc (sizeof (FLOAT_ELT));
37   unsigned long num_len;
38
39   new->id = id;
40   new->type = type;
41   new->title = title;
42   new->shorttitle = shorttitle;
43   new->position = position;
44   new->title_used = 0;
45   new->defining_line = line_number - 1;
46
47   new->number = current_chapter_number ();
48   /* Append dot if not @unnumbered.  */
49   num_len = strlen (new->number);
50   if (num_len > 0)
51     {
52       new->number = xrealloc (new->number, num_len + 1 + 1);
53       new->number[num_len] = '.';
54       new->number[num_len+1] = '\0';
55     }
56
57   { /* Append the current float number.  */
58     unsigned len = strlen (new->number) + 21;  /* that's 64 bits */
59     char *s = xmalloc (len + 1);
60
61     sprintf (s, "%s%d", new->number,
62                 count_floats_of_type_in_chapter (text_expansion (type),
63                                                  new->number) + 1); 
64     free (new->number);
65     new->number = xstrdup (s);
66   }
67
68   /* Plain text output needs sectioning number and its title,
69      when listing floats.  */
70   if (!html && !xml && no_headers)
71     {
72       new->section = current_sectioning_number ();
73       if (strlen (new->section) == 0)
74         new->section_name = current_sectioning_name ();
75       else
76         new->section_name = "";
77     }
78
79   new->next = float_stack;
80   float_stack = new;
81 }
82
83 int
84 count_floats_of_type_in_chapter (char *type, char *chapter)
85 {
86   int i = 0;
87   int l = strlen (chapter);
88   FLOAT_ELT *temp = float_stack;
89
90   while (temp && strncmp (temp->number, chapter, l) == 0)
91     {
92       if (strlen (temp->id) > 0 && STREQ (text_expansion (temp->type), type))
93         i++;
94       temp = temp->next;
95     }
96
97   return i;
98 }
99
100 char *
101 current_float_title (void)
102 {
103   return float_stack->title;
104 }
105
106 char *
107 current_float_shorttitle (void)
108 {
109   return float_stack->shorttitle;
110 }
111
112 char *
113 current_float_type (void)
114 {
115   return float_stack->type;
116 }
117
118 char *
119 current_float_position (void)
120 {
121   return float_stack->position;
122 }
123
124 char *
125 current_float_number (void)
126 {
127   return float_stack->number;
128 }
129
130 char *
131 current_float_id (void)
132 {
133   return float_stack->id;
134 }
135
136 char *
137 get_float_ref (char *id)
138 {
139   FLOAT_ELT *temp = float_stack;
140
141   while (temp)
142     {
143       if (STREQ (id, temp->id))
144         {
145           char *s = xmalloc (strlen (temp->type) + strlen (temp->number) + 2);
146           sprintf (s, "%s %s", temp->type, temp->number);
147           return s;
148         }
149       temp = temp->next;
150     }
151
152   return NULL;
153 }
154
155 static int
156 float_type_exists (char *check_type)
157 {
158   /* Check if the requested float_type exists in the floats stack.  */
159   FLOAT_ELT *temp;
160
161   for (temp = float_stack; temp; temp = temp->next)
162     if (STREQ (temp->type, check_type) && temp->id && *temp->id)
163       return 1;
164
165   return 0;
166 }
167
168 void
169 cm_listoffloats (void)
170 {
171   char *float_type;
172   get_rest_of_line (1, &float_type);
173
174   /* get_rest_of_line increments the line number by one,
175      so to make warnings/errors point to the correct line,
176      we decrement the line_number again.  */
177   if (!handling_delayed_writes)
178     line_number--;
179
180   if (handling_delayed_writes && !float_type_exists (float_type))
181     warning (_("Requested float type `%s' not previously used"), float_type);
182
183   if (xml)
184     {
185       xml_insert_element_with_attribute (LISTOFFLOATS, START,
186           "type=\"%s\"", text_expansion (float_type));
187       xml_insert_element (LISTOFFLOATS, END);
188     }
189   else if (!handling_delayed_writes)
190     {
191       int command_len = sizeof ("@ ") + strlen (command) + strlen (float_type);
192       char *list_command = xmalloc (command_len + 1);
193
194       /* These are for the text following @listoffloats command.
195          Handling them with delayed writes is too late.  */
196       close_paragraph ();
197       cm_noindent ();
198
199       sprintf (list_command, "@%s %s", command, float_type);
200       register_delayed_write (list_command);
201       free (list_command);
202     }
203   else if (float_type_exists (float_type))
204     {
205       FLOAT_ELT *temp = (FLOAT_ELT *) reverse_list
206         ((GENERIC_LIST *) float_stack);
207       FLOAT_ELT *new_start = temp;
208
209       if (html)
210         insert_string ("<ul class=\"listoffloats\">\n");
211       else
212         {
213           if (!no_headers)
214             insert_string ("* Menu:\n\n");
215         }
216
217       while (temp)
218         {
219           if (strlen (temp->id) > 0 && STREQ (float_type, temp->type))
220             {
221               char *caption;
222               if (strlen (temp->shorttitle) > 0)
223                 caption = expansion (temp->shorttitle, 0);
224               else if (strlen (temp->title) > 0)
225                 caption = expansion (temp->title, 0);
226               else
227                 caption = "";
228                   
229               if (html)
230                 {
231                   /* A bit of space for HTML reabality.  */
232                   insert_string ("  ");
233                   add_html_block_elt ("<li>");
234
235                   /* Simply relying on @ref command doesn't work here, because
236                      commas in the caption may confuse the argument parsing.  */
237                   add_word ("<a href=\"");
238                   add_anchor_name (temp->id, 1);
239                   add_word ("\">");
240
241                   if (strlen (float_type) > 0)
242                     execute_string ("%s", float_type);
243
244                   if (strlen (temp->id) > 0)
245                     {
246                       if (strlen (float_type) > 0)
247                         add_char (' ');
248
249                       add_word (temp->number);
250                     }
251
252                   if (caption)
253                     {
254                       if (strlen (float_type) > 0 || strlen (temp->id) > 0)
255                         insert_string (": ");
256                       execute_string ("%s", caption);
257                     }
258
259                   add_word ("</a>");
260
261                   add_html_block_elt ("</li>\n");
262                 }
263               else
264                 {
265                   char *entry;
266                   char *raw_entry;
267
268                   int len;
269                   int aux_chars_len; /* these are asterisk, colon, etc.  */
270                   int column_width; /* width of the first column in menus.  */
271                   int number_len; /* length of Figure X.Y: etc.   */
272                   int i = 0;
273
274                   /* Chosen widths are to match what @printindex produces.  */
275                   if (no_headers)
276                     {
277                       column_width = 43;
278                       /* We have only one auxiliary character, NULL.  */
279                       aux_chars_len = sizeof ("");
280                     }
281                   else
282                     {
283                       column_width = 37;
284                       /* We'll be adding an asterisk, followed by a space
285                          and then a colon after the title, to construct a
286                          proper menu item.  */
287                       aux_chars_len = sizeof ("* :");
288                     }
289
290                   /* Allocate enough space for possible expansion later.  */
291                   raw_entry = (char *) xmalloc (strlen (float_type)
292                       + strlen (temp->number) + strlen (caption)
293                       + sizeof (":  "));
294
295                   sprintf (raw_entry, "%s %s", float_type, temp->number);
296
297                   if (strlen (caption) > 0)
298                     strcat (raw_entry, ": ");
299
300                   number_len = strlen (raw_entry);
301
302                   len = strlen (caption) + strlen (raw_entry);
303
304                   strcat (raw_entry, caption);
305                   len = strlen (raw_entry);
306
307                   if (len + aux_chars_len > column_width)
308                     { /* Shorten long titles by looking for a space before
309                          column_width - strlen (" ...").  */
310                       /* -1 is for NULL, which is already in aux_chars_len.  */
311                       aux_chars_len += sizeof ("...") - 1;
312                       len = column_width - aux_chars_len;
313                       while (raw_entry[len] != ' ' && len >= 0)
314                         len--;
315
316                       /* Advance to the whitespace.  */
317                       len++;
318
319                       /* If we are at the end of, say, Figure X.Y:, but
320                          we have a title, then this means title does not
321                          contain any whitespaces.  Or it may be that we
322                          went as far as the beginning.  Just print as much
323                          as possible of the title.  */
324                       if (len == 0
325                           || (len == number_len && strlen (caption) > 0))
326                         len = column_width - sizeof ("...");
327
328                       /* Break here.  */
329                       raw_entry[len] = 0;
330
331                       entry = xmalloc (len + aux_chars_len);
332
333                       if (!no_headers)
334                         strcpy (entry, "* ");
335                       else
336                         entry[0] = 0;
337
338                       strcat (entry, raw_entry);
339                       strcat (entry, "...");
340
341                       if (!no_headers)
342                         strcat (entry, ":");
343                     }
344                   else
345                     {
346                       entry = xmalloc (len + aux_chars_len);
347
348                       if (!no_headers)
349                         strcpy (entry, "* ");
350                       else
351                         entry[0] = 0;
352
353                       strcat (entry, raw_entry);
354
355                       if (!no_headers)
356                         strcat (entry, ":");
357                     }
358
359                   insert_string (entry);
360
361                   i = strlen (entry);
362                   /* We insert space chars until ``column_width + four spaces''
363                      is reached, to make the layout the same with what we produce
364                      for @printindex.  This is of course not obligatory, though
365                      easier on the eye.  -1 is for NULL.  */
366                   while (i < column_width + sizeof ("    ") - 1)
367                     {
368                       insert (' ');
369                       i++;
370                     }
371
372                   if (no_headers)
373                     {
374                       if (strlen (temp->section) > 0)
375                         { /* We got your number.  */
376                           insert_string ((char *) _("See "));
377                           insert_string (temp->section);
378                         }
379                       else
380                         { /* Sigh, @float in an @unnumbered. :-\  */
381                           insert_string ("\n          ");
382                           insert_string ((char *) _("See "));
383                           insert_string ("``");
384                           insert_string (expansion (temp->section_name, 0));
385                           insert_string ("''");
386                         }
387                     }
388                   else
389                     insert_string (temp->id);
390
391                   insert_string (".\n");
392
393                   free (entry);
394                 }
395               
396               if (strlen (caption) > 0)
397                 free (caption);
398             }
399           temp = temp->next;
400         }
401
402       if (html)
403         {
404           inhibit_paragraph_indentation = 1;
405           insert_string ("</ul>\n\n");
406         }
407       else
408         insert ('\n');
409
410       /* Retain the original order of float stack.  */
411       temp = new_start;
412       float_stack = (FLOAT_ELT *) reverse_list ((GENERIC_LIST *) temp);
413     }
414
415   free (float_type);
416   /* Re-increment the line number, because get_rest_of_line
417      left us looking at the next line after the command.  */
418   line_number++;
419 }
420
421 int
422 current_float_used_title (void)
423 {
424         return float_stack->title_used;
425 }
426
427 void current_float_set_title_used (void)
428 {
429         float_stack->title_used = 1;
430 }