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