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