float.c 13 KB

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