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 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 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 * 102 current_float_title (void) 103 { 104 return float_stack->title; 105 } 106 107 char * 108 current_float_shorttitle (void) 109 { 110 return float_stack->shorttitle; 111 } 112 113 char * 114 current_float_type (void) 115 { 116 return float_stack->type; 117 } 118 119 char * 120 current_float_position (void) 121 { 122 return float_stack->position; 123 } 124 125 char * 126 current_float_number (void) 127 { 128 return float_stack->number; 129 } 130 131 char * 132 current_float_id (void) 133 { 134 return float_stack->id; 135 } 136 137 char * 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 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 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 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 } 431