node.c 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948
  1. /* node.c -- nodes for Texinfo.
  2. $Id: node.c,v 1.41 2008-07-05 23:57:29 karl Exp $
  3. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
  4. Free Software Foundation, Inc.
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include "system.h"
  16. #include "cmds.h"
  17. #include "files.h"
  18. #include "float.h"
  19. #include "footnote.h"
  20. #include "macro.h"
  21. #include "makeinfo.h"
  22. #include "node.h"
  23. #include "html.h"
  24. #include "sectioning.h"
  25. #include "insertion.h"
  26. #include "xml.h"
  27. /* See comments in node.h. */
  28. NODE_REF *node_references = NULL;
  29. NODE_REF *node_node_references = NULL;
  30. TAG_ENTRY *tag_table = NULL;
  31. int node_number = -1;
  32. int node_order = 0;
  33. int current_section = 0;
  34. int outstanding_node = 0;
  35. /* Adding nodes, and making tags. */
  36. /* Start a new tag table. */
  37. void
  38. init_tag_table (void)
  39. {
  40. while (tag_table)
  41. {
  42. TAG_ENTRY *temp = tag_table;
  43. free (temp->node);
  44. free (temp->prev);
  45. free (temp->next);
  46. free (temp->up);
  47. tag_table = tag_table->next_ent;
  48. free (temp);
  49. }
  50. }
  51. /* Write out the contents of the existing tag table.
  52. INDIRECT_P says how to format the output (it depends on whether the
  53. table is direct or indirect). */
  54. static void
  55. write_tag_table_internal (int indirect_p)
  56. {
  57. TAG_ENTRY *node;
  58. int old_indent = no_indent;
  59. if (xml)
  60. {
  61. flush_output ();
  62. return;
  63. }
  64. no_indent = 1;
  65. filling_enabled = 0;
  66. must_start_paragraph = 0;
  67. close_paragraph ();
  68. if (!indirect_p)
  69. {
  70. no_indent = 1;
  71. insert ('\n');
  72. }
  73. add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
  74. /* Do not collapse -- to -, etc., in node names. */
  75. in_fixed_width_font++;
  76. for (node = tag_table; node; node = node->next_ent)
  77. {
  78. if (node->flags & TAG_FLAG_ANCHOR)
  79. { /* This reference is to an anchor. */
  80. execute_string ("Ref: %s", node->node);
  81. }
  82. else
  83. { /* This reference is to a node. */
  84. execute_string ("Node: %s", node->node);
  85. }
  86. add_word_args ("\177%d\n", node->position);
  87. }
  88. add_word ("\037\nEnd Tag Table\n");
  89. /* Do not collapse -- to -, etc., in node names. */
  90. in_fixed_width_font--;
  91. flush_output ();
  92. no_indent = old_indent;
  93. }
  94. void
  95. write_tag_table (char *filename)
  96. {
  97. output_stream = fopen (filename, "a");
  98. if (!output_stream)
  99. {
  100. fs_error (filename);
  101. return;
  102. }
  103. write_tag_table_internal (0); /* Not indirect. */
  104. if (fclose (output_stream) != 0)
  105. fs_error (filename);
  106. }
  107. static void
  108. write_tag_table_indirect (void)
  109. {
  110. write_tag_table_internal (1);
  111. }
  112. /* Convert "top" and friends into "Top". */
  113. static void
  114. normalize_node_name (char *string)
  115. {
  116. if (mbscasecmp (string, "Top") == 0)
  117. strcpy (string, "Top");
  118. }
  119. static char *
  120. get_node_token (int expand)
  121. {
  122. char *string;
  123. get_until_in_line (expand, ",", &string);
  124. if (curchar () == ',')
  125. input_text_offset++;
  126. fix_whitespace (string);
  127. /* Force all versions of "top" to be "Top". */
  128. normalize_node_name (string);
  129. return string;
  130. }
  131. /* Expand any macros and other directives in a node name, and
  132. return the expanded name as an malloc'ed string. */
  133. char *
  134. expand_node_name (char *node)
  135. {
  136. char *result = node;
  137. if (node)
  138. {
  139. /* Don't expand --, `` etc., in case somebody will want
  140. to print the result. */
  141. in_fixed_width_font++;
  142. result = expansion (node, 0);
  143. in_fixed_width_font--;
  144. fix_whitespace (result);
  145. normalize_node_name (result);
  146. }
  147. return result;
  148. }
  149. /* Look up NAME in the tag table, and return the associated
  150. tag_entry. If the node is not in the table return NULL. */
  151. TAG_ENTRY *
  152. find_node (char *name)
  153. {
  154. TAG_ENTRY *tag = tag_table;
  155. char *expanded_name;
  156. char n1 = name[0];
  157. while (tag)
  158. {
  159. if (tag->node[0] == n1 && strcmp (tag->node, name) == 0)
  160. return tag;
  161. tag = tag->next_ent;
  162. }
  163. if (!expensive_validation)
  164. return NULL;
  165. /* Try harder. Maybe TAG_TABLE has the expanded NAME, or maybe NAME
  166. is expanded while TAG_TABLE has its unexpanded form. This may
  167. slow down the search, but if they want this feature, let them
  168. pay! If they want it fast, they should write every node name
  169. consistently (either always expanded or always unexpaned). */
  170. expanded_name = expand_node_name (name);
  171. for (tag = tag_table; tag; tag = tag->next_ent)
  172. {
  173. if (STREQ (tag->node, expanded_name))
  174. break;
  175. /* If the tag name doesn't have the command prefix, there's no
  176. chance it could expand into anything but itself. */
  177. if (strchr (tag->node, COMMAND_PREFIX))
  178. {
  179. char *expanded_node = expand_node_name (tag->node);
  180. if (STREQ (expanded_node, expanded_name))
  181. {
  182. free (expanded_node);
  183. break;
  184. }
  185. free (expanded_node);
  186. }
  187. }
  188. free (expanded_name);
  189. return tag;
  190. }
  191. /* Look in the tag table for a node whose file name is FNAME, and
  192. return the associated tag_entry. If there's no such node in the
  193. table, return NULL. */
  194. static TAG_ENTRY *
  195. find_node_by_fname (char *fname)
  196. {
  197. TAG_ENTRY *tag = tag_table;
  198. while (tag)
  199. {
  200. if (tag->html_fname && FILENAME_CMP (tag->html_fname, fname) == 0)
  201. return tag;
  202. tag = tag->next_ent;
  203. }
  204. return tag;
  205. }
  206. /* Remember next, prev, etc. references in a @node command, where we
  207. don't care about most of the entries. */
  208. static void
  209. remember_node_node_reference (char *node)
  210. {
  211. NODE_REF *temp = xmalloc (sizeof (NODE_REF));
  212. int number;
  213. if (!node) return;
  214. temp->next = node_node_references;
  215. temp->node = xstrdup (node);
  216. temp->type = followed_reference;
  217. number = number_of_node (node);
  218. if (number)
  219. temp->number = number; /* Already assigned. */
  220. else
  221. {
  222. node_number++;
  223. temp->number = node_number;
  224. }
  225. node_node_references = temp;
  226. }
  227. /* Remember NODE and associates. */
  228. static void
  229. remember_node (char *node, char *prev, char *next, char *up,
  230. int position, int line_no, char *fname, int flags)
  231. {
  232. /* Check for existence of this tag already. */
  233. if (validating)
  234. {
  235. TAG_ENTRY *tag = find_node (node);
  236. if (tag)
  237. {
  238. line_error (_("Node `%s' previously defined at line %d"),
  239. node, tag->line_no);
  240. return;
  241. }
  242. }
  243. if (!(flags & TAG_FLAG_ANCHOR))
  244. {
  245. /* Make this the current node. */
  246. current_node = node;
  247. }
  248. /* Add it to the list. */
  249. {
  250. int number = number_of_node (node);
  251. TAG_ENTRY *new = xmalloc (sizeof (TAG_ENTRY));
  252. new->node = node;
  253. new->prev = prev;
  254. new->next = next;
  255. new->up = up;
  256. new->position = position;
  257. new->line_no = line_no;
  258. new->filename = node_filename;
  259. new->touched = 0;
  260. new->flags = flags;
  261. if (number)
  262. new->number = number; /* Already assigned. */
  263. else
  264. {
  265. node_number++;
  266. new->number = node_number;
  267. }
  268. if (fname)
  269. new->html_fname = fname;
  270. else
  271. /* This happens for Top node under split-HTML, for example. */
  272. new->html_fname
  273. = normalize_filename (filename_part (current_output_filename));
  274. new->next_ent = tag_table;
  275. /* Increment the order counter, and save it. */
  276. node_order++;
  277. new->order = node_order;
  278. tag_table = new;
  279. }
  280. if (html)
  281. { /* Note the references to the next etc. nodes too. */
  282. remember_node_node_reference (next);
  283. remember_node_node_reference (prev);
  284. remember_node_node_reference (up);
  285. }
  286. }
  287. /* Remember this node name for later validation use. This is used to
  288. remember menu references while reading the input file. After the
  289. output file has been written, if validation is on, then we use the
  290. contents of `node_references' as a list of nodes to validate. */
  291. void
  292. remember_node_reference (char *node, int line, enum reftype type)
  293. {
  294. NODE_REF *temp = xmalloc (sizeof (NODE_REF));
  295. int number = number_of_node (node);
  296. temp->next = node_references;
  297. temp->node = xstrdup (node);
  298. temp->line_no = line;
  299. temp->section = current_section;
  300. temp->type = type;
  301. temp->containing_node = xstrdup (current_node ? current_node : "");
  302. temp->filename = node_filename;
  303. if (number)
  304. temp->number = number; /* Already assigned. */
  305. else
  306. {
  307. node_number++;
  308. temp->number = node_number;
  309. }
  310. node_references = temp;
  311. }
  312. static void
  313. isolate_nodename (char *nodename)
  314. {
  315. int i, c;
  316. int paren_seen, paren;
  317. if (!nodename)
  318. return;
  319. canon_white (nodename);
  320. paren_seen = paren = i = 0;
  321. if (*nodename == '.' || !*nodename)
  322. {
  323. *nodename = 0;
  324. return;
  325. }
  326. if (*nodename == '(')
  327. {
  328. paren++;
  329. paren_seen++;
  330. i++;
  331. }
  332. for (; (c = nodename[i]); i++)
  333. {
  334. if (paren)
  335. {
  336. if (c == '(')
  337. paren++;
  338. else if (c == ')')
  339. paren--;
  340. continue;
  341. }
  342. /* If the character following the close paren is a space, then this
  343. node has no more characters associated with it. */
  344. if (c == '\t' ||
  345. c == '\n' ||
  346. c == ',' ||
  347. ((paren_seen && i > 0 && nodename[i - 1] == ')') &&
  348. (c == ' ' || c == '.')) ||
  349. (c == '.' &&
  350. ((!nodename[i + 1] ||
  351. (cr_or_whitespace (nodename[i + 1])) ||
  352. (nodename[i + 1] == ')')))))
  353. break;
  354. }
  355. nodename[i] = 0;
  356. }
  357. /* This function gets called at the start of every line while inside a
  358. menu. It checks to see if the line starts with "* ", and if so and
  359. REMEMBER_REF is nonzero, remembers the node reference as type
  360. REF_TYPE that this menu refers to. input_text_offset is at the \n
  361. just before the menu line. If REMEMBER_REF is zero, REF_TYPE is unused. */
  362. #define MENU_STARTER "* "
  363. char *
  364. glean_node_from_menu (int remember_ref, enum reftype ref_type)
  365. {
  366. int i, orig_offset = input_text_offset;
  367. char *nodename;
  368. char *line, *expanded_line;
  369. char *old_input = input_text;
  370. int old_size = input_text_length;
  371. if (strncmp (&input_text[input_text_offset + 1],
  372. MENU_STARTER,
  373. strlen (MENU_STARTER)) != 0)
  374. return NULL;
  375. else
  376. input_text_offset += strlen (MENU_STARTER) + 1;
  377. /* The menu entry might include macro calls, so we need to expand them. */
  378. get_until ("\n", &line);
  379. only_macro_expansion++; /* only expand macros in menu entries */
  380. expanded_line = expansion (line, 0);
  381. only_macro_expansion--;
  382. free (line);
  383. input_text = expanded_line;
  384. input_text_offset = 0;
  385. input_text_length = strlen (expanded_line);
  386. get_until_in_line (0, ":", &nodename);
  387. if (curchar () == ':')
  388. input_text_offset++;
  389. if (curchar () != ':')
  390. {
  391. free (nodename);
  392. get_until_in_line (0, "\n", &nodename);
  393. isolate_nodename (nodename);
  394. }
  395. input_text = old_input;
  396. input_text_offset = orig_offset;
  397. input_text_length = old_size;
  398. free (expanded_line);
  399. fix_whitespace (nodename);
  400. normalize_node_name (nodename);
  401. i = strlen (nodename);
  402. if (i && nodename[i - 1] == ':')
  403. nodename[i - 1] = 0;
  404. if (remember_ref)
  405. remember_node_reference (nodename, line_number, ref_type);
  406. return nodename;
  407. }
  408. /* Set the name of the current output file. */
  409. void
  410. set_current_output_filename (const char *fname)
  411. {
  412. if (current_output_filename)
  413. free (current_output_filename);
  414. current_output_filename = xstrdup (fname);
  415. }
  416. /* Output the <a name="..."></a> constructs for NODE. We output both
  417. the new-style conversion and the old-style, if they are different.
  418. See comments at `add_escaped_anchor_name' in html.c. */
  419. static void
  420. add_html_names (char *node)
  421. {
  422. char *tem = expand_node_name (node);
  423. char *otem = xstrdup (tem);
  424. /* Determine if the old and new schemes come up with different names;
  425. only output the old scheme if that is so. We don't want to output
  426. the same name twice. */
  427. canon_white (otem);
  428. {
  429. char *optr = otem;
  430. int need_old = 0;
  431. for (; *optr; optr++)
  432. {
  433. if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr))
  434. {
  435. need_old = 1;
  436. break;
  437. }
  438. }
  439. if (need_old)
  440. {
  441. add_word ("<a name=\"");
  442. add_anchor_name (otem, -1); /* old anchor name conversion */
  443. add_word ("\"></a>\n");
  444. }
  445. free (otem);
  446. }
  447. /* Always output the new scheme. */
  448. canon_white (tem);
  449. add_word ("<a name=\"");
  450. add_anchor_name (tem, 0);
  451. add_word ("\"></a>\n");
  452. free (tem);
  453. }
  454. /* The order is: nodename, nextnode, prevnode, upnode.
  455. If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
  456. You must follow a node command which has those fields defaulted
  457. with a sectioning command (e.g., @chapter) giving the "level" of that node.
  458. It is an error not to do so.
  459. The defaults come from the menu in this node's parent. */
  460. void
  461. cm_node (void)
  462. {
  463. static long epilogue_len = 0L;
  464. char *node, *prev, *next, *up;
  465. int new_node_pos, defaulting, this_section;
  466. int no_warn = 0;
  467. char *fname_for_this_node = NULL;
  468. char *tem;
  469. TAG_ENTRY *tag = NULL;
  470. if (strcmp (command, "nwnode") == 0)
  471. no_warn = TAG_FLAG_NO_WARN;
  472. /* Get rid of unmatched brace arguments from previous commands. */
  473. discard_braces ();
  474. /* There also might be insertions left lying around that haven't been
  475. ended yet. Do that also. */
  476. discard_insertions (1);
  477. if (!html && !already_outputting_pending_notes)
  478. {
  479. close_paragraph ();
  480. output_pending_notes ();
  481. }
  482. new_node_pos = output_position;
  483. if (macro_expansion_output_stream && !executing_string)
  484. append_to_expansion_output (input_text_offset + 1);
  485. /* Do not collapse -- to -, etc., in node names. */
  486. in_fixed_width_font++;
  487. /* While expanding the @node line, leave any non-macros
  488. intact, so that the macro-expanded output includes them. */
  489. only_macro_expansion++;
  490. node = get_node_token (1);
  491. only_macro_expansion--;
  492. next = get_node_token (0);
  493. prev = get_node_token (0);
  494. up = get_node_token (0);
  495. if (html && splitting
  496. /* If there is a Top node, it always goes into index.html. So
  497. don't start a new HTML file for Top. */
  498. && (top_node_seen || mbscasecmp (node, "Top") != 0))
  499. {
  500. /* We test *node here so that @node without a valid name won't
  501. start a new file name with a bogus name such as ".html".
  502. This could happen if we run under "--force", where we cannot
  503. simply bail out. Continuing to use the same file sounds like
  504. the best we can do in such cases. */
  505. if (current_output_filename && output_stream && *node)
  506. {
  507. char *fname_for_prev_node;
  508. if (current_node)
  509. {
  510. /* NOTE: current_node at this point still holds the name
  511. of the previous node. */
  512. tem = expand_node_name (current_node);
  513. fname_for_prev_node = nodename_to_filename (tem);
  514. free (tem);
  515. }
  516. else /* could happen if their top node isn't named "Top" */
  517. fname_for_prev_node = filename_part (current_output_filename);
  518. tem = expand_node_name (node);
  519. fname_for_this_node = nodename_to_filename (tem);
  520. free (tem);
  521. /* Don't close current output file, if next output file is
  522. to have the same name. This may happen at top level, or
  523. if two nodes produce the same file name under --split. */
  524. if (FILENAME_CMP (fname_for_this_node, fname_for_prev_node) != 0)
  525. {
  526. long pos1 = 0;
  527. /* End the current split output file. */
  528. close_paragraph ();
  529. output_pending_notes ();
  530. start_paragraph ();
  531. /* Compute the length of the HTML file's epilogue. We
  532. cannot know the value until run time, due to the
  533. text/binary nuisance on DOS/Windows platforms, where
  534. 2 `\r' characters could be added to the epilogue when
  535. it is written in text mode. */
  536. if (epilogue_len == 0)
  537. {
  538. flush_output ();
  539. pos1 = ftell (output_stream);
  540. }
  541. add_word ("</body></html>\n");
  542. close_paragraph ();
  543. if (epilogue_len == 0)
  544. epilogue_len = ftell (output_stream) - pos1;
  545. fclose (output_stream);
  546. output_stream = NULL;
  547. output_position = 0;
  548. tag = find_node_by_fname (fname_for_this_node);
  549. }
  550. free (fname_for_prev_node);
  551. }
  552. }
  553. filling_enabled = indented_fill = 0;
  554. if (!html || (html && splitting))
  555. current_footnote_number = 1;
  556. if (verbose_mode)
  557. printf (_("Formatting node %s...\n"), node);
  558. if (macro_expansion_output_stream && !executing_string)
  559. remember_itext (input_text, input_text_offset);
  560. /* Reset the line number in each node for Info output, so that
  561. index entries will save the line numbers of parent node. */
  562. node_line_number = 0;
  563. no_indent = 1;
  564. if (xml)
  565. {
  566. xml_begin_node ();
  567. if (!docbook)
  568. {
  569. xml_insert_element (NODENAME, START);
  570. if (macro_expansion_output_stream && !executing_string)
  571. me_execute_string (node);
  572. else
  573. execute_string ("%s", node);
  574. xml_insert_element (NODENAME, END);
  575. }
  576. else
  577. xml_node_id = xml_id (node);
  578. }
  579. else if (!no_headers && !html)
  580. {
  581. /* Emacs Info reader cannot grok indented escape sequence. */
  582. kill_self_indent (-1);
  583. add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
  584. if (macro_expansion_output_stream && !executing_string)
  585. me_execute_string (node);
  586. else
  587. execute_string ("%s", node);
  588. filling_enabled = indented_fill = 0;
  589. }
  590. /* Check for defaulting of this node's next, prev, and up fields. */
  591. defaulting = (*next == 0 && *prev == 0 && *up == 0);
  592. this_section = what_section (input_text + input_text_offset, NULL);
  593. /* If we are defaulting, then look at the immediately following
  594. sectioning command (error if none) to determine the node's
  595. level. Find the node that contains the menu mentioning this node
  596. that is one level up (error if not found). That node is the "Up"
  597. of this node. Default the "Next" and "Prev" from the menu. */
  598. if (defaulting)
  599. {
  600. NODE_REF *last_ref = NULL;
  601. NODE_REF *ref = node_references;
  602. if (this_section < 0 && !STREQ (node, "Top"))
  603. {
  604. char *polite_section_name = "top";
  605. int i;
  606. for (i = 0; section_alist[i].name; i++)
  607. if (section_alist[i].level == current_section + 1)
  608. {
  609. polite_section_name = section_alist[i].name;
  610. break;
  611. }
  612. line_error
  613. (_("Node `%s' requires a sectioning command (e.g., %c%s)"),
  614. node, COMMAND_PREFIX, polite_section_name);
  615. }
  616. else
  617. {
  618. if (strcmp (node, "Top") == 0)
  619. {
  620. /* Default the NEXT pointer to be the first menu item in
  621. this node, if there is a menu in this node. We have to
  622. try very hard to find the menu, as it may be obscured
  623. by execution_strings which are on the filestack. For
  624. every member of the filestack which has a FILENAME
  625. member which is identical to the current INPUT_FILENAME,
  626. search forward from that offset. */
  627. int saved_input_text_offset = input_text_offset;
  628. int saved_input_text_length = input_text_length;
  629. char *saved_input_text = input_text;
  630. FSTACK *next_file = filestack;
  631. int orig_offset, orig_size;
  632. int bye_offset = search_forward ("\n@bye", input_text_offset);
  633. /* No matter what, make this file point back at `(dir)'. */
  634. free (up);
  635. up = xstrdup ("(dir)"); /* html fixxme */
  636. while (1)
  637. {
  638. orig_offset = input_text_offset;
  639. orig_size =
  640. search_forward (node_search_string, orig_offset);
  641. if (orig_size < 0)
  642. orig_size = input_text_length;
  643. input_text_offset = search_forward ("\n@menu", orig_offset);
  644. if (input_text_offset > -1
  645. && (bye_offset > -1 && input_text_offset < bye_offset)
  646. && cr_or_whitespace (input_text[input_text_offset + 6]))
  647. {
  648. char *nodename_from_menu = NULL;
  649. input_text_offset =
  650. search_forward ("\n* ", input_text_offset);
  651. if (input_text_offset != -1)
  652. nodename_from_menu = glean_node_from_menu (0,
  653. (enum reftype) 0);
  654. if (nodename_from_menu)
  655. {
  656. free (next);
  657. next = nodename_from_menu;
  658. break;
  659. }
  660. }
  661. /* We got here, so it hasn't been found yet. Try
  662. the next file on the filestack if there is one. */
  663. if (next_file
  664. && FILENAME_CMP (next_file->filename, input_filename)
  665. == 0)
  666. {
  667. input_text = next_file->text;
  668. input_text_offset = next_file->offset;
  669. input_text_length = next_file->size;
  670. next_file = next_file->next;
  671. }
  672. else
  673. { /* No more input files to check. */
  674. break;
  675. }
  676. }
  677. input_text = saved_input_text;
  678. input_text_offset = saved_input_text_offset;
  679. input_text_length = saved_input_text_length;
  680. }
  681. }
  682. /* Fix the level of the menu references in the Top node, iff it
  683. was declared with @top, and no subsequent reference was found. */
  684. if (top_node_seen && !non_top_node_seen)
  685. {
  686. /* Then this is the first non-@top node seen. */
  687. int level;
  688. level = set_top_section_level (this_section - 1);
  689. non_top_node_seen = 1;
  690. while (ref)
  691. {
  692. if (ref->section == level)
  693. ref->section = this_section - 1;
  694. ref = ref->next;
  695. }
  696. ref = node_references;
  697. }
  698. while (ref)
  699. {
  700. if (ref->section == (this_section - 1)
  701. && ref->type == menu_reference
  702. && strcmp (ref->node, node) == 0)
  703. {
  704. char *containing_node = ref->containing_node;
  705. free (up);
  706. up = xstrdup (containing_node);
  707. if (last_ref
  708. && last_ref->type == menu_reference
  709. && strcmp (last_ref->containing_node, containing_node) == 0)
  710. {
  711. free (next);
  712. next = xstrdup (last_ref->node);
  713. }
  714. while (ref->section == this_section - 1
  715. && ref->next
  716. && ref->next->type != menu_reference)
  717. ref = ref->next;
  718. if (ref->next && ref->type == menu_reference
  719. && strcmp (ref->next->containing_node, containing_node) == 0)
  720. {
  721. free (prev);
  722. prev = xstrdup (ref->next->node);
  723. }
  724. else if (!ref->next
  725. && mbscasecmp (ref->containing_node, "Top") == 0)
  726. {
  727. free (prev);
  728. prev = xstrdup (ref->containing_node);
  729. }
  730. break;
  731. }
  732. last_ref = ref;
  733. ref = ref->next;
  734. }
  735. }
  736. /* Insert the correct args if we are expanding macros, and the node's
  737. pointers weren't defaulted. */
  738. if (macro_expansion_output_stream && !executing_string && !defaulting)
  739. {
  740. char *temp;
  741. int op_orig = output_paragraph_offset;
  742. int meta_pos_orig = meta_char_pos;
  743. int extra = html ? strlen (node) : 0;
  744. temp = xmalloc (7 + extra + strlen (next) + strlen (prev) + strlen (up));
  745. sprintf (temp, "%s, %s, %s, %s", html ? node : "", next, prev, up);
  746. me_execute_string (temp);
  747. free (temp);
  748. output_paragraph_offset = op_orig;
  749. meta_char_pos = meta_pos_orig;
  750. }
  751. if (!*node)
  752. {
  753. line_error (_("No node name specified for `%c%s' command"),
  754. COMMAND_PREFIX, command);
  755. free (node);
  756. free (next); next = NULL;
  757. free (prev); prev= NULL;
  758. free (up); up = NULL;
  759. node_number++; /* else it doesn't get bumped */
  760. }
  761. else
  762. {
  763. if (!*next) { free (next); next = NULL; }
  764. if (!*prev) { free (prev); prev = NULL; }
  765. if (!*up) { free (up); up = NULL; }
  766. remember_node (node, prev, next, up, new_node_pos, line_number,
  767. fname_for_this_node, no_warn);
  768. outstanding_node = 1;
  769. }
  770. if (html)
  771. {
  772. if (splitting && *node && output_stream == NULL)
  773. {
  774. char *dirname;
  775. char filename[PATH_MAX];
  776. dirname = pathname_part (current_output_filename);
  777. strcpy (filename, dirname);
  778. strcat (filename, fname_for_this_node);
  779. free (dirname);
  780. /* See if the node name converted to a file name clashes
  781. with other nodes or anchors. If it clashes with an
  782. anchor, we complain and nuke that anchor's file. */
  783. if (!tag)
  784. {
  785. output_stream = fopen (filename, "w");
  786. output_head_p = 0; /* so that we generate HTML preamble */
  787. output_head ();
  788. }
  789. else if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
  790. {
  791. line_error (_("Anchor `%s' and node `%s' map to the same file name"),
  792. tag->node, node);
  793. file_line_error (tag->filename, tag->line_no,
  794. _("This @anchor command ignored; references to it will not work"));
  795. file_line_error (tag->filename, tag->line_no,
  796. _("Rename this anchor or use the `--no-split' option"));
  797. /* Nuke the file name recorded in anchor's tag.
  798. Since we are about to nuke the file itself, we
  799. don't want find_node_by_fname to consider this
  800. anchor anymore. */
  801. free (tag->html_fname);
  802. tag->html_fname = NULL;
  803. output_stream = fopen (filename, "w");
  804. output_head_p = 0; /* so that we generate HTML preamble */
  805. output_head ();
  806. }
  807. else
  808. {
  809. /* This node's file name clashes with another node.
  810. We put them both on the same file. */
  811. output_stream = fopen (filename, "r+");
  812. if (output_stream)
  813. {
  814. static char html_end[] = "</body></html>\n";
  815. char end_line[sizeof(html_end)];
  816. int fpos = fseek (output_stream, -epilogue_len,
  817. SEEK_END);
  818. if (fpos < 0
  819. || fgets (end_line, sizeof (html_end),
  820. output_stream) == NULL
  821. /* Paranoia: did someone change the way HTML
  822. files are finished up? */
  823. || mbscasecmp (end_line, html_end) != 0)
  824. {
  825. line_error (_("Unexpected string at end of split-HTML file `%s'"),
  826. fname_for_this_node);
  827. fclose (output_stream);
  828. xexit (1);
  829. }
  830. fseek (output_stream, -epilogue_len, SEEK_END);
  831. }
  832. }
  833. if (output_stream == NULL)
  834. {
  835. fs_error (filename);
  836. xexit (1);
  837. }
  838. set_current_output_filename (filename);
  839. }
  840. if (!splitting && no_headers)
  841. { /* cross refs need a name="#anchor" even if not writing headers */
  842. add_html_names (node);
  843. }
  844. if (splitting || !no_headers)
  845. { /* Navigation bar. */
  846. add_html_block_elt ("<div class=\"node\">\n");
  847. /* In the split HTML case, the filename is wrong for the
  848. old-style converted names, but we'll add them anyway, for
  849. consistency. (And we need them in the normal (not
  850. no_headers) nonsplit case.) */
  851. add_html_names (node);
  852. /* Do this after adding the anchors, so the browser rendering
  853. can be better. The <p> avoids the links area running on
  854. with old Lynxen. */
  855. add_word_args ("<p>%s\n", splitting ? "" : "<hr>");
  856. if (next)
  857. {
  858. tem = expansion (next, 0);
  859. add_word ((char *) gdt("Next:"));
  860. add_word ("&nbsp;");
  861. add_word ("<a rel=\"next\" accesskey=\"n\" href=\"");
  862. add_anchor_name (tem, 1);
  863. tem = escape_string (tem);
  864. add_word_args ("\">%s</a>", tem);
  865. free (tem);
  866. if (prev || up)
  867. add_word (",\n");
  868. }
  869. if (prev)
  870. {
  871. tem = expansion (prev, 0);
  872. add_word ((char *) gdt("Previous:"));
  873. add_word ("&nbsp;");
  874. add_word ("<a rel=\"previous\" accesskey=\"p\" href=\"");
  875. add_anchor_name (tem, 1);
  876. tem = escape_string (tem);
  877. add_word_args ("\">%s</a>", tem);
  878. free (tem);
  879. if (up)
  880. add_word (",\n");
  881. }
  882. if (up)
  883. {
  884. tem = expansion (up, 0);
  885. add_word ((char *) gdt("Up:"));
  886. add_word ("&nbsp;");
  887. add_word ("<a rel=\"up\" accesskey=\"u\" href=\"");
  888. add_anchor_name (tem, 1);
  889. tem = escape_string (tem);
  890. add_word_args ("\">%s</a>", tem);
  891. free (tem);
  892. }
  893. /* html fixxme: we want a `top' or `contents' link here. */
  894. add_word_args ("\n%s\n", splitting ? "<hr>" : "");
  895. add_word ("</div>\n");
  896. }
  897. }
  898. else if (docbook)
  899. ;
  900. else if (xml)
  901. {
  902. if (next)
  903. {
  904. xml_insert_element (NODENEXT, START);
  905. execute_string ("%s", next);
  906. xml_insert_element (NODENEXT, END);
  907. }
  908. if (prev)
  909. {
  910. xml_insert_element (NODEPREV, START);
  911. execute_string ("%s", prev);
  912. xml_insert_element (NODEPREV, END);
  913. }
  914. if (up)
  915. {
  916. xml_insert_element (NODEUP, START);
  917. execute_string ("%s", up);
  918. xml_insert_element (NODEUP, END);
  919. }
  920. }
  921. else if (!no_headers)
  922. {
  923. if (macro_expansion_output_stream)
  924. me_inhibit_expansion++;
  925. /* These strings are not translatable. */
  926. if (next)
  927. {
  928. execute_string (", Next: %s", next);
  929. filling_enabled = indented_fill = 0;
  930. }
  931. if (prev)
  932. {
  933. execute_string (", Prev: %s", prev);
  934. filling_enabled = indented_fill = 0;
  935. }
  936. if (up)
  937. {
  938. execute_string (", Up: %s", up);
  939. filling_enabled = indented_fill = 0;
  940. }
  941. if (macro_expansion_output_stream)
  942. me_inhibit_expansion--;
  943. }
  944. close_paragraph ();
  945. no_indent = 0;
  946. /* Change the section only if there was a sectioning command. */
  947. if (this_section >= 0)
  948. current_section = this_section;
  949. if (current_node && STREQ (current_node, "Top"))
  950. top_node_seen = 1;
  951. filling_enabled = 1;
  952. in_fixed_width_font--;
  953. }
  954. /* Cross-reference target at an arbitrary spot. */
  955. void
  956. cm_anchor (int arg)
  957. {
  958. char *anchor;
  959. char *fname_for_anchor = NULL;
  960. if (arg == END)
  961. {
  962. /* We want to ignore whitespace following @anchor a la
  963. texinfo.tex, but we're sitting at the }. So advance past it,
  964. ignore the whitespace, and then go back one character. When we
  965. return, reader_loop will increment input_text_offset again (see
  966. the '}' case). Sorry. */
  967. input_text_offset++;
  968. skip_whitespace_and_newlines ();
  969. input_text_offset--;
  970. return;
  971. }
  972. /* Parse the anchor text. */
  973. anchor = get_xref_token (1);
  974. /* Force all versions of "top" to be "Top". */
  975. normalize_node_name (anchor);
  976. /* In HTML mode, need to actually produce some output. */
  977. if (html)
  978. {
  979. /* If this anchor is at the beginning of a new paragraph, make
  980. sure a new paragraph is indeed started. */
  981. if (!paragraph_is_open)
  982. {
  983. if (!executing_string && html)
  984. output_head ();
  985. start_paragraph ();
  986. if (!in_fixed_width_font || in_menu || in_detailmenu)
  987. {
  988. insert_string ("<p>");
  989. in_paragraph = 1;
  990. }
  991. }
  992. add_word ("<a name=\"");
  993. add_anchor_name (anchor, 0);
  994. add_word ("\"></a>");
  995. if (splitting)
  996. {
  997. /* If we are splitting, cm_xref will produce a reference to
  998. a file whose name is derived from the anchor name. So we
  999. must create a file when we see an @anchor, otherwise
  1000. xref's to anchors won't work. The file we create simply
  1001. redirects to the file of this anchor's node. */
  1002. TAG_ENTRY *tag;
  1003. fname_for_anchor = nodename_to_filename (anchor);
  1004. /* See if the anchor name converted to a file name clashes
  1005. with other anchors or nodes. */
  1006. tag = find_node_by_fname (fname_for_anchor);
  1007. if (tag)
  1008. {
  1009. if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
  1010. line_error (_("Anchors `%s' and `%s' map to the same file name"),
  1011. anchor, tag->node);
  1012. else
  1013. line_error (_("Anchor `%s' and node `%s' map to the same file name"),
  1014. anchor, tag->node);
  1015. line_error (_("@anchor command ignored; references to it will not work"));
  1016. line_error (_("Rename this anchor or use the `--no-split' option"));
  1017. free (fname_for_anchor);
  1018. /* We will not be creating a file for this anchor, so
  1019. set its name to NULL, so that remember_node stores a
  1020. NULL and find_node_by_fname won't consider this
  1021. anchor for clashes. */
  1022. fname_for_anchor = NULL;
  1023. }
  1024. else
  1025. {
  1026. char *dirname, *p;
  1027. char filename[PATH_MAX];
  1028. FILE *anchor_stream;
  1029. dirname = pathname_part (current_output_filename);
  1030. strcpy (filename, dirname);
  1031. strcat (filename, fname_for_anchor);
  1032. free (dirname);
  1033. anchor_stream = fopen (filename, "w");
  1034. if (anchor_stream == NULL)
  1035. {
  1036. fs_error (filename);
  1037. xexit (1);
  1038. }
  1039. /* The HTML magic below will cause the browser to
  1040. immediately go to the anchor's node's file. Lynx
  1041. seems not to support this redirection, but it looks
  1042. like a bug in Lynx, and they can work around it by
  1043. clicking on the link once more. */
  1044. fputs ("<meta http-equiv=\"refresh\" content=\"0; url=",
  1045. anchor_stream);
  1046. /* Make the indirect link point to the current node's
  1047. file and anchor's "<a name" label. If we don't have
  1048. a valid node name, refer to the current output file
  1049. instead. */
  1050. if (current_node && *current_node)
  1051. {
  1052. char *fn, *tem;
  1053. tem = expand_node_name (current_node);
  1054. fn = nodename_to_filename (tem);
  1055. free (tem);
  1056. fputs (fn, anchor_stream);
  1057. free (fn);
  1058. }
  1059. else
  1060. {
  1061. char *base = filename_part (current_output_filename);
  1062. fputs (base, anchor_stream);
  1063. free (base);
  1064. }
  1065. fputs ("#", anchor_stream);
  1066. for (p = anchor; *p; p++)
  1067. {
  1068. if (*p == '&')
  1069. fputs ("&amp;", anchor_stream);
  1070. else if (!URL_SAFE_CHAR (*p))
  1071. fprintf (anchor_stream, "%%%x", (unsigned char) *p);
  1072. else
  1073. fputc (*p, anchor_stream);
  1074. }
  1075. fputs ("\">\n", anchor_stream);
  1076. fclose (anchor_stream);
  1077. }
  1078. }
  1079. }
  1080. else if (xml || docbook)
  1081. {
  1082. xml_insert_element_with_attribute (ANCHOR, START,
  1083. docbook ? "id=\"%s\"" : "name=\"%s\"",
  1084. anchor);
  1085. xml_insert_element (ANCHOR, END);
  1086. }
  1087. /* Save it in the tag table. */
  1088. remember_node (anchor, NULL, NULL, NULL,
  1089. output_position + output_paragraph_offset,
  1090. line_number, fname_for_anchor, TAG_FLAG_ANCHOR);
  1091. }
  1092. /* Find NODE in REF_LIST. */
  1093. static NODE_REF *
  1094. find_node_reference (char *node, NODE_REF *ref_list)
  1095. {
  1096. NODE_REF *orig_ref_list = ref_list;
  1097. char *expanded_node;
  1098. while (ref_list)
  1099. {
  1100. if (strcmp (node, ref_list->node) == 0)
  1101. break;
  1102. ref_list = ref_list->next;
  1103. }
  1104. if (ref_list || !expensive_validation)
  1105. return ref_list;
  1106. /* Maybe NODE is not expanded yet. This may be SLOW. */
  1107. expanded_node = expand_node_name (node);
  1108. for (ref_list = orig_ref_list; ref_list; ref_list = ref_list->next)
  1109. {
  1110. if (STREQ (expanded_node, ref_list->node))
  1111. break;
  1112. if (strchr (ref_list->node, COMMAND_PREFIX))
  1113. {
  1114. char *expanded_ref = expand_node_name (ref_list->node);
  1115. if (STREQ (expanded_node, expanded_ref))
  1116. {
  1117. free (expanded_ref);
  1118. break;
  1119. }
  1120. free (expanded_ref);
  1121. }
  1122. }
  1123. free (expanded_node);
  1124. return ref_list;
  1125. }
  1126. void
  1127. free_node_references (void)
  1128. {
  1129. NODE_REF *list, *temp;
  1130. list = node_references;
  1131. while (list)
  1132. {
  1133. temp = list;
  1134. free (list->node);
  1135. free (list->containing_node);
  1136. list = list->next;
  1137. free (temp);
  1138. }
  1139. node_references = NULL;
  1140. }
  1141. void
  1142. free_node_node_references (void)
  1143. {
  1144. NODE_REF *list, *temp;
  1145. list = node_references;
  1146. while (list)
  1147. {
  1148. temp = list;
  1149. free (list->node);
  1150. list = list->next;
  1151. free (temp);
  1152. }
  1153. node_node_references = NULL;
  1154. }
  1155. /* Return the number assigned to a named node in either the tag_table
  1156. or node_references list or zero if no number has been assigned. */
  1157. int
  1158. number_of_node (char *node)
  1159. {
  1160. NODE_REF *temp_ref;
  1161. TAG_ENTRY *temp_node = find_node (node);
  1162. if (temp_node)
  1163. return temp_node->number;
  1164. else if ((temp_ref = find_node_reference (node, node_references)))
  1165. return temp_ref->number;
  1166. else if ((temp_ref = find_node_reference (node, node_node_references)))
  1167. return temp_ref->number;
  1168. else
  1169. return 0;
  1170. }
  1171. /* validation */
  1172. /* Return 1 if TAG (at LINE) correctly validated, or 0 if not.
  1173. LABEL is the (translated) description of the type of reference --
  1174. Menu, Cross, Next, etc. */
  1175. static int
  1176. validate (char *tag, int line, const char *label)
  1177. {
  1178. TAG_ENTRY *result;
  1179. /* If there isn't a tag to verify, or if the tag is in another file,
  1180. then it must be okay. */
  1181. if (!tag || !*tag || *tag == '(')
  1182. return 1;
  1183. /* Otherwise, the tag must exist. */
  1184. result = find_node (tag);
  1185. if (!result)
  1186. {
  1187. line_number = line;
  1188. line_error (_("%s reference to nonexistent node `%s' (perhaps incorrect sectioning?)"), label, tag);
  1189. return 0;
  1190. }
  1191. result->touched++;
  1192. return 1;
  1193. }
  1194. /* The strings here are followed in the message by `reference to...' in
  1195. the `validate' routine. They are only used in messages, thus are
  1196. translated. */
  1197. static const char *
  1198. reftype_type_string (enum reftype type)
  1199. {
  1200. switch (type)
  1201. {
  1202. case menu_reference:
  1203. return gdt("Menu");
  1204. case followed_reference:
  1205. return gdt("Cross");
  1206. default:
  1207. return "Internal-bad-reference-type";
  1208. }
  1209. }
  1210. static void
  1211. validate_other_references (NODE_REF *ref_list)
  1212. {
  1213. char *old_input_filename = input_filename;
  1214. while (ref_list)
  1215. {
  1216. input_filename = ref_list->filename;
  1217. validate (ref_list->node, ref_list->line_no,
  1218. reftype_type_string (ref_list->type));
  1219. ref_list = ref_list->next;
  1220. }
  1221. input_filename = old_input_filename;
  1222. }
  1223. /* Validation of an info file.
  1224. Scan through the list of tag entries touching the Prev, Next, and Up
  1225. elements of each. It is an error not to be able to touch one of them,
  1226. except in the case of external node references, such as "(DIR)".
  1227. If the Prev is different from the Up,
  1228. then the Prev node must have a Next pointing at this node.
  1229. Every node except Top must have an Up.
  1230. The Up node must contain some sort of reference, other than a Next,
  1231. to this node.
  1232. If the Next is different from the Next of the Up,
  1233. then the Next node must have a Prev pointing at this node. */
  1234. void
  1235. validate_file (TAG_ENTRY *tag_table)
  1236. {
  1237. char *old_input_filename = input_filename;
  1238. TAG_ENTRY *tags = tag_table;
  1239. while (tags)
  1240. {
  1241. TAG_ENTRY *temp_tag;
  1242. char *tem1, *tem2;
  1243. input_filename = tags->filename;
  1244. line_number = tags->line_no;
  1245. /* If this is a "no warn" node, don't validate it in any way. */
  1246. if (tags->flags & TAG_FLAG_NO_WARN)
  1247. {
  1248. tags = tags->next_ent;
  1249. continue;
  1250. }
  1251. /* If this node has a Next, then make sure that the Next exists. */
  1252. if (tags->next)
  1253. {
  1254. validate (tags->next, tags->line_no, gdt("Next"));
  1255. /* If the Next node exists, and there is no Up, then make sure
  1256. that the Prev of the Next points back. But do nothing if
  1257. we aren't supposed to issue warnings about this node. */
  1258. temp_tag = find_node (tags->next);
  1259. if (temp_tag && !(temp_tag->flags & TAG_FLAG_NO_WARN))
  1260. {
  1261. char *prev = temp_tag->prev;
  1262. int you_lose = !prev || !STREQ (prev, tags->node);
  1263. if (you_lose && expensive_validation)
  1264. {
  1265. tem1 = expand_node_name (prev);
  1266. tem2 = expand_node_name (tags->node);
  1267. if (tem1 && tem2 && STREQ (tem1, tem2))
  1268. you_lose = 0;
  1269. free (tem1);
  1270. free (tem2);
  1271. }
  1272. if (you_lose)
  1273. {
  1274. line_error (_("Next field of node `%s' not pointed to (perhaps incorrect sectioning?)"),
  1275. tags->node);
  1276. file_line_error (temp_tag->filename, temp_tag->line_no,
  1277. _("This node (%s) has the bad Prev"),
  1278. temp_tag->node);
  1279. temp_tag->flags |= TAG_FLAG_PREV_ERROR;
  1280. }
  1281. }
  1282. }
  1283. /* Validate the Prev field if there is one, and we haven't already
  1284. complained about it in some way. You don't have to have a Prev
  1285. field at this stage. */
  1286. if (!(tags->flags & TAG_FLAG_PREV_ERROR) && tags->prev)
  1287. {
  1288. int valid_p = validate (tags->prev, tags->line_no, gdt("Prev"));
  1289. if (!valid_p)
  1290. tags->flags |= TAG_FLAG_PREV_ERROR;
  1291. else
  1292. { /* If the Prev field is not the same as the Up field,
  1293. then the node pointed to by the Prev field must have
  1294. a Next field which points to this node. */
  1295. int prev_equals_up = !tags->up || STREQ (tags->prev, tags->up);
  1296. if (!prev_equals_up && expensive_validation)
  1297. {
  1298. tem1 = expand_node_name (tags->prev);
  1299. tem2 = expand_node_name (tags->up);
  1300. prev_equals_up = STREQ (tem1, tem2);
  1301. free (tem1);
  1302. free (tem2);
  1303. }
  1304. if (!prev_equals_up)
  1305. {
  1306. temp_tag = find_node (tags->prev);
  1307. /* If we aren't supposed to issue warnings about the
  1308. target node, do nothing. */
  1309. if (!temp_tag || (temp_tag->flags & TAG_FLAG_NO_WARN))
  1310. /* Do nothing. */ ;
  1311. else
  1312. {
  1313. int you_lose = !temp_tag->next
  1314. || !STREQ (temp_tag->next, tags->node);
  1315. if (temp_tag->next && you_lose && expensive_validation)
  1316. {
  1317. tem1 = expand_node_name (temp_tag->next);
  1318. tem2 = expand_node_name (tags->node);
  1319. if (STREQ (tem1, tem2))
  1320. you_lose = 0;
  1321. free (tem1);
  1322. free (tem2);
  1323. }
  1324. if (you_lose)
  1325. {
  1326. line_error
  1327. (_("Prev field of node `%s' not pointed to"),
  1328. tags->node);
  1329. file_line_error (temp_tag->filename,
  1330. temp_tag->line_no,
  1331. _("This node (%s) has the bad Next"),
  1332. temp_tag->node);
  1333. temp_tag->flags |= TAG_FLAG_NEXT_ERROR;
  1334. }
  1335. }
  1336. }
  1337. }
  1338. }
  1339. if (!tags->up
  1340. && !(tags->flags & TAG_FLAG_ANCHOR)
  1341. && mbscasecmp (tags->node, "Top") != 0)
  1342. line_error (_("`%s' has no Up field (perhaps incorrect sectioning?)"), tags->node);
  1343. else if (tags->up)
  1344. {
  1345. int valid_p = validate (tags->up, tags->line_no, gdt("Up"));
  1346. /* If node X has Up: Y, then warn if Y fails to have a menu item
  1347. or note pointing at X, if Y isn't of the form "(Y)". */
  1348. if (valid_p && *tags->up != '(')
  1349. {
  1350. NODE_REF *nref;
  1351. NODE_REF *tref = NULL;
  1352. NODE_REF *list = node_references;
  1353. for (;;)
  1354. {
  1355. nref = find_node_reference (tags->node, list);
  1356. if (!nref)
  1357. break;
  1358. if (strcmp (nref->containing_node, tags->up) == 0)
  1359. {
  1360. if (nref->type != menu_reference)
  1361. {
  1362. tref = nref;
  1363. list = nref->next;
  1364. }
  1365. else
  1366. break;
  1367. }
  1368. list = nref->next;
  1369. }
  1370. if (!nref)
  1371. {
  1372. if (!tref && expensive_validation)
  1373. {
  1374. /* Sigh... This might be AWFULLY slow, but if
  1375. they want this feature, they'll have to pay!
  1376. We do all the loop again expanding each
  1377. containing_node reference as we go. */
  1378. char *tags_up = expand_node_name (tags->up);
  1379. char *tem;
  1380. list = node_references;
  1381. for (;;)
  1382. {
  1383. nref = find_node_reference (tags->node, list);
  1384. if (!nref)
  1385. break;
  1386. tem = expand_node_name (nref->containing_node);
  1387. if (STREQ (tem, tags_up))
  1388. {
  1389. if (nref->type != menu_reference)
  1390. tref = nref;
  1391. else
  1392. {
  1393. free (tem);
  1394. break;
  1395. }
  1396. }
  1397. free (tem);
  1398. list = nref->next;
  1399. }
  1400. }
  1401. if (!nref && !tref)
  1402. {
  1403. temp_tag = find_node (tags->up);
  1404. file_line_error (temp_tag->filename, temp_tag->line_no,
  1405. _("Node `%s' lacks menu item for `%s' despite being its Up target"),
  1406. tags->up, tags->node);
  1407. }
  1408. }
  1409. }
  1410. }
  1411. tags = tags->next_ent;
  1412. }
  1413. validate_other_references (node_references);
  1414. /* We have told the user about the references which didn't exist.
  1415. Now tell him about the nodes which aren't referenced. */
  1416. for (tags = tag_table; tags; tags = tags->next_ent)
  1417. {
  1418. /* If this node is a "no warn" node, do nothing. */
  1419. if (tags->flags & TAG_FLAG_NO_WARN)
  1420. {
  1421. tags = tags->next_ent;
  1422. continue;
  1423. }
  1424. if (tags->touched == 0)
  1425. {
  1426. input_filename = tags->filename;
  1427. line_number = tags->line_no;
  1428. /* Notice that the node "Top" is special, and doesn't have to
  1429. be referenced. Anchors don't have to be referenced
  1430. either, you might define them for another document. */
  1431. if (mbscasecmp (tags->node, "Top") != 0
  1432. && !(tags->flags & TAG_FLAG_ANCHOR))
  1433. warning (_("unreferenced node `%s'"), tags->node);
  1434. }
  1435. }
  1436. input_filename = old_input_filename;
  1437. }
  1438. /* Splitting */
  1439. /* Return true if the tag entry pointed to by TAGS is the last node.
  1440. This means only anchors follow. */
  1441. static int
  1442. last_node_p (TAG_ENTRY *tags)
  1443. {
  1444. int last = 1;
  1445. while (tags->next_ent) {
  1446. tags = tags->next_ent;
  1447. if (tags->flags & TAG_FLAG_ANCHOR)
  1448. ;
  1449. else
  1450. {
  1451. last = 0;
  1452. break;
  1453. }
  1454. }
  1455. return last;
  1456. }
  1457. static char *
  1458. enumerate_filename (char *pathname, char *basename, int number)
  1459. {
  1460. /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
  1461. const int dos_file_names = !HAVE_LONG_FILENAMES (pathname ? pathname : ".");
  1462. unsigned name_len = strlen (basename);
  1463. char *filename = xmalloc (10 + strlen (pathname) + name_len);
  1464. char *base_filename = xmalloc (10 + name_len);
  1465. sprintf (base_filename, "%s-%d", basename, number);
  1466. if (dos_file_names)
  1467. {
  1468. char *dot = strchr (base_filename, '.');
  1469. unsigned base_len = strlen (base_filename);
  1470. if (dot)
  1471. { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
  1472. dot[1] = 'i';
  1473. memmove (number <= 99 ? dot + 2 : dot + 1,
  1474. base_filename + name_len + 1,
  1475. strlen (base_filename + name_len + 1) + 1);
  1476. }
  1477. else if (base_len > 8)
  1478. {
  1479. /* Make foobar-1, .., fooba-10, .., foob-100, ... */
  1480. unsigned numlen = base_len - name_len;
  1481. memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1);
  1482. }
  1483. }
  1484. sprintf (filename, "%s%s", pathname, base_filename);
  1485. return filename;
  1486. }
  1487. /* Remove previously split files, to avoid
  1488. lingering parts of shrinked documents. */
  1489. void
  1490. clean_old_split_files (char *filename)
  1491. {
  1492. char *root_filename = filename_part (filename);
  1493. char *root_pathname = pathname_part (filename);
  1494. int i;
  1495. /* We break as soon as we hit an inexistent file,
  1496. so looping until large numbers is harmless. */
  1497. for (i = 1; i < 1000; i++)
  1498. {
  1499. struct stat st;
  1500. char *check_file = enumerate_filename (root_pathname, root_filename, i);
  1501. if (stat (check_file, &st) != 0)
  1502. break;
  1503. else if (!S_ISDIR (st.st_mode))
  1504. {
  1505. /* Give feedback if requested, removing a file is important. */
  1506. if (verbose_mode)
  1507. printf (_("Removing %s\n"), check_file);
  1508. /* Warn user that we cannot remove the file. */
  1509. if (unlink (check_file) != 0)
  1510. warning (_("Can't remove file `%s': %s"), check_file, strerror (errno));
  1511. }
  1512. free (check_file);
  1513. }
  1514. }
  1515. /* Split large output files into a series of smaller files. Each file
  1516. is pointed to in the tag table, which then gets written out as the
  1517. original file. The new files have the same name as the original file
  1518. with a "-num" attached. SIZE is the largest number of bytes to allow
  1519. in any single split file. */
  1520. void
  1521. split_file (char *filename, int size)
  1522. {
  1523. char *root_filename, *root_pathname;
  1524. char *the_file;
  1525. struct stat fileinfo;
  1526. long file_size;
  1527. char *the_header;
  1528. int header_size;
  1529. /* Can only do this to files with tag tables. */
  1530. if (!tag_table)
  1531. return;
  1532. if (size == 0)
  1533. size = DEFAULT_SPLIT_SIZE;
  1534. if ((stat (filename, &fileinfo) != 0)
  1535. || (((long) fileinfo.st_size) < size))
  1536. return;
  1537. file_size = (long) fileinfo.st_size;
  1538. the_file = find_and_load (filename, 0);
  1539. if (!the_file)
  1540. return;
  1541. root_filename = filename_part (filename);
  1542. root_pathname = pathname_part (filename);
  1543. if (!root_pathname)
  1544. root_pathname = xstrdup ("");
  1545. /* Start splitting the file. Walk along the tag table
  1546. outputting sections of the file. When we have written
  1547. all of the nodes in the tag table, make the top-level
  1548. pointer file, which contains indirect pointers and
  1549. tags for the nodes. */
  1550. {
  1551. int which_file = 1;
  1552. TAG_ENTRY *tags = tag_table;
  1553. char *indirect_info = NULL;
  1554. /* Maybe we want a Local Variables section. */
  1555. char *trailer = info_trailer ();
  1556. int trailer_len = trailer ? strlen (trailer) : 0;
  1557. /* Remember the `header' of this file. The first tag in the file is
  1558. the bottom of the header; the top of the file is the start. */
  1559. the_header = xmalloc (1 + (header_size = tags->position));
  1560. memcpy (the_header, the_file, header_size);
  1561. while (tags)
  1562. {
  1563. int file_top, file_bot, limit;
  1564. /* Have to include the Control-_. */
  1565. file_top = file_bot = tags->position;
  1566. limit = file_top + size;
  1567. /* If the rest of this file is only one node, then
  1568. that is the entire subfile. */
  1569. if (last_node_p (tags))
  1570. {
  1571. int i = tags->position + 1;
  1572. char last_char = the_file[i];
  1573. while (i < file_size)
  1574. {
  1575. if ((the_file[i] == '\037') &&
  1576. ((last_char == '\n') ||
  1577. (last_char == '\014')))
  1578. break;
  1579. else
  1580. last_char = the_file[i];
  1581. i++;
  1582. }
  1583. file_bot = i;
  1584. tags = tags->next_ent;
  1585. goto write_region;
  1586. }
  1587. /* Otherwise, find the largest number of nodes that can fit in
  1588. this subfile. */
  1589. for (; tags; tags = tags->next_ent)
  1590. {
  1591. if (last_node_p (tags))
  1592. {
  1593. /* This entry is the last node. Search forward for the end
  1594. of this node, and that is the end of this file. */
  1595. int i = tags->position + 1;
  1596. char last_char = the_file[i];
  1597. while (i < file_size)
  1598. {
  1599. if ((the_file[i] == '\037') &&
  1600. ((last_char == '\n') ||
  1601. (last_char == '\014')))
  1602. break;
  1603. else
  1604. last_char = the_file[i];
  1605. i++;
  1606. }
  1607. file_bot = i;
  1608. if (file_bot < limit)
  1609. {
  1610. tags = tags->next_ent;
  1611. goto write_region;
  1612. }
  1613. else
  1614. {
  1615. /* Here we want to write out everything before the last
  1616. node, and then write the last node out in a file
  1617. by itself. */
  1618. file_bot = tags->position;
  1619. goto write_region;
  1620. }
  1621. }
  1622. /* Write region only if this was a node, not an anchor. */
  1623. if (tags->next_ent->position > limit
  1624. && !(tags->flags & TAG_FLAG_ANCHOR))
  1625. {
  1626. if (tags->position == file_top)
  1627. tags = tags->next_ent;
  1628. file_bot = tags->position;
  1629. write_region:
  1630. {
  1631. int fd;
  1632. char *split_filename = enumerate_filename (root_pathname,
  1633. root_filename, which_file);
  1634. char *split_basename = filename_part (split_filename);
  1635. fd = open (split_filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
  1636. if (fd < 0
  1637. || write (fd, the_header, header_size) != header_size
  1638. || write (fd, the_file + file_top, file_bot - file_top)
  1639. != (file_bot - file_top)
  1640. || (trailer_len
  1641. && write (fd, trailer, trailer_len) != trailer_len)
  1642. || close (fd) < 0)
  1643. {
  1644. perror (split_filename);
  1645. if (fd != -1)
  1646. close (fd);
  1647. xexit (1);
  1648. }
  1649. if (!indirect_info)
  1650. {
  1651. indirect_info = the_file + file_top;
  1652. sprintf (indirect_info, "\037\nIndirect:\n");
  1653. indirect_info += strlen (indirect_info);
  1654. }
  1655. sprintf (indirect_info, "%s: %d\n",
  1656. split_basename, file_top);
  1657. free (split_basename);
  1658. free (split_filename);
  1659. indirect_info += strlen (indirect_info);
  1660. which_file++;
  1661. break;
  1662. }
  1663. }
  1664. }
  1665. }
  1666. /* We have sucessfully created the subfiles. Now write out the
  1667. original again. We must use `output_stream', or
  1668. write_tag_table_indirect () won't know where to place the output. */
  1669. output_stream = fopen (filename, "w");
  1670. if (!output_stream)
  1671. {
  1672. perror (filename);
  1673. xexit (1);
  1674. }
  1675. {
  1676. int distance = indirect_info - the_file;
  1677. fwrite (the_file, 1, distance, output_stream);
  1678. /* Inhibit newlines. */
  1679. paragraph_is_open = 0;
  1680. /* Write the indirect tag table. */
  1681. write_tag_table_indirect ();
  1682. /* preserve local variables in info output. */
  1683. if (trailer)
  1684. {
  1685. fwrite (trailer, 1, trailer_len, output_stream);
  1686. free (trailer);
  1687. }
  1688. fclose (output_stream);
  1689. free (the_header);
  1690. free (the_file);
  1691. return;
  1692. }
  1693. }
  1694. }