separator.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. /* Copyright 2010, 2011, 2012, 2013, 2014, 2015
  2. Free Software Foundation, Inc.
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "parser.h"
  16. #include "tree.h"
  17. #include "text.h"
  18. #include "errors.h"
  19. #include "convert.h"
  20. #include "input.h"
  21. #include "labels.h"
  22. // 3600
  23. /* Add the contents of CURRENT as an element to the extra value with
  24. key KEY, except that some "empty space" elements are removed. Used for
  25. 'brace_command_contents' for the arguments to a brace command, and
  26. 'block_command_line_contents' for the arguments to a block line command.
  27. For a brace command $element, $element->{'args'} has pretty much the same
  28. information as $element->{'extra'}->{'brace_command_contents'}. */
  29. void
  30. register_command_arg (ELEMENT *current, char *key)
  31. {
  32. ELEMENT *value;
  33. ELEMENT *new;
  34. KEY_PAIR *k;
  35. new = trim_spaces_comment_from_content (current);
  36. if (new->contents.number == 0)
  37. {
  38. free (new);
  39. new = 0;
  40. }
  41. /* FIXME: Could we add all the command args together, instead of one-by-one,
  42. to avoid having to look for the extra value every time? */
  43. k = lookup_extra_key (current->parent, key);
  44. if (k)
  45. value = k->value;
  46. else
  47. {
  48. value = new_element (ET_NONE);
  49. value->parent_type = route_not_in_tree;
  50. add_extra_contents_array (current->parent, key, value);
  51. }
  52. add_to_contents_as_array (value, new);
  53. }
  54. /* 4888 */
  55. ELEMENT *
  56. handle_open_brace (ELEMENT *current, char **line_inout)
  57. {
  58. char *line = *line_inout;
  59. abort_empty_line (&current, NULL);
  60. /* 4890 */
  61. if (command_flags(current) & CF_brace)
  62. {
  63. enum command_id command;
  64. ELEMENT *arg;
  65. command = current->cmd;
  66. /* 4896 */
  67. counter_push (&count_remaining_args, current,
  68. command_data(current->cmd).data);
  69. counter_dec (&count_remaining_args);
  70. arg = new_element (ET_NONE);
  71. add_to_element_args (current, arg);
  72. current = arg;
  73. if (command == CM_verb)
  74. {
  75. current->type = ET_brace_command_arg;
  76. /* Save the deliminating character in 'type'. This is a reuse of
  77. 'type' for a different purpose. */
  78. if (!*line || *line == '\n')
  79. {
  80. line_error ("@verb without associated character");
  81. current->parent->type = 0;
  82. }
  83. else
  84. current->parent->type = (enum element_type) *line++;
  85. }
  86. /* 4903 */
  87. else if (command_data(command).data == BRACE_context)
  88. {
  89. if (command == CM_caption || command == CM_shortcaption)
  90. {
  91. #define float floatxx
  92. ELEMENT *float;
  93. if (!current->parent->parent
  94. || current->parent->parent->cmd != CM_float)
  95. {
  96. float = current->parent;
  97. while (float->parent && float->cmd != CM_float)
  98. float = float->parent;
  99. if (float->cmd != CM_float)
  100. {
  101. line_error ("@%s is not meaningful outside "
  102. "`@float' environment",
  103. command_name(command));
  104. float = 0;
  105. }
  106. else
  107. line_warn ("@%s should be right below `@float'",
  108. command_name(command));
  109. }
  110. else
  111. float = current->parent->parent;
  112. if (float)
  113. {
  114. if (lookup_extra_key (float, command_name(command)))
  115. line_warn ("ignoring multiple @%s",
  116. command_name(command));
  117. else
  118. {
  119. add_extra_element (current->parent, "float", float);
  120. add_extra_element (float, command_name(command),
  121. current->parent);
  122. }
  123. }
  124. #undef float
  125. }
  126. /* Add to context stack. */
  127. switch (command)
  128. {
  129. case CM_footnote:
  130. push_context (ct_footnote);
  131. break;
  132. case CM_caption:
  133. push_context (ct_caption);
  134. break;
  135. case CM_shortcaption:
  136. push_context (ct_shortcaption);
  137. break;
  138. case CM_math:
  139. push_context (ct_math);
  140. break;
  141. default:
  142. abort ();
  143. }
  144. {
  145. ELEMENT *e;
  146. int n;
  147. n = strspn (line, whitespace_chars_except_newline);
  148. e = new_element (ET_empty_spaces_before_argument);
  149. text_append_n (&e->text, line, n);
  150. add_to_element_contents (current, e);
  151. add_extra_element (current->parent,
  152. "spaces_before_argument", e);
  153. line += n;
  154. }
  155. current->type = ET_brace_command_context;
  156. }
  157. /* 4945 */
  158. else /* not context brace */
  159. {
  160. current->type = ET_brace_command_arg;
  161. /* Commands which are said to take a positive number of arguments
  162. disregard leading and trailing whitespace. In
  163. 'handle_close_brace', the 'brace_command_contents' array
  164. is set. */
  165. if (command_data(command).data > 0)
  166. {
  167. ELEMENT *e;
  168. e = new_element (ET_empty_spaces_before_argument);
  169. /* See comment in parser.c:merge_text */
  170. text_append (&e->text, "");
  171. add_to_element_contents (current, e);
  172. add_extra_element (current->parent,
  173. "spaces_before_argument", e);
  174. if (command == CM_inlineraw)
  175. push_context (ct_inlineraw);
  176. }
  177. }
  178. debug ("OPENED");
  179. }
  180. /* 4967 */
  181. else if (current->parent && (current->parent->cmd == CM_multitable
  182. || current->parent->type == ET_def_line))
  183. {
  184. ELEMENT *b, *e;
  185. b = new_element (ET_bracketed);
  186. add_to_element_contents (current, b);
  187. current = b;
  188. /* We need the line number here in case @ protects the
  189. end of the line. */
  190. if (current->parent->parent->type == ET_def_line)
  191. current->line_nr = line_nr;
  192. e = new_element (ET_empty_spaces_before_argument);
  193. text_append (&e->text, ""); /* See comment in parser.c:merge_text */
  194. add_to_element_contents (current, e);
  195. debug ("BRACKETED in def/multitable");
  196. add_extra_element (current, "spaces_before_argument", e);
  197. }
  198. else if (current->type == ET_rawpreformatted)
  199. {
  200. ELEMENT *e = new_element (ET_NONE);
  201. text_append (&e->text, "{");
  202. add_to_element_contents (current, e);
  203. }
  204. // 4993
  205. else if (current_context() == ct_math
  206. || current_context() == ct_rawpreformatted
  207. || current_context() == ct_inlineraw)
  208. {
  209. ELEMENT *b = new_element (ET_bracketed);
  210. b->line_nr = line_nr;
  211. add_to_element_contents (current, b);
  212. current = b;
  213. debug ("BRACKETED in math");
  214. }
  215. else
  216. line_error ("misplaced {");
  217. *line_inout = line;
  218. return current;
  219. }
  220. /* 5007 */
  221. ELEMENT *
  222. handle_close_brace (ELEMENT *current, char **line_inout)
  223. {
  224. char *line = *line_inout;
  225. abort_empty_line (&current, NULL);
  226. if (current->type == ET_bracketed)
  227. {
  228. /* Used in @math */
  229. current = current->parent;
  230. goto funexit;
  231. }
  232. else if (command_flags(current->parent) & CF_brace)
  233. {
  234. enum command_id closed_command;
  235. // 5019
  236. if (command_data(current->parent->cmd).data == BRACE_context)
  237. {
  238. enum context c;
  239. c = pop_context ();
  240. /* The Perl code here checks that the popped context and the
  241. parent command match as strings. */
  242. }
  243. else if (command_data(current->parent->cmd).data > 0) /* sic */
  244. {
  245. // 5033
  246. /* @inline* always have end spaces considered as normal text */
  247. if (!(command_flags(current->parent) & CF_inline))
  248. isolate_last_space (current, 0);
  249. register_command_arg (current, "brace_command_contents");
  250. remove_empty_content_arguments (current);
  251. }
  252. closed_command = current->parent->cmd;
  253. debug ("CLOSING(brace) %s", command_data(closed_command).cmdname);
  254. counter_pop (&count_remaining_args);
  255. // 5044
  256. if (current->contents.number > 0
  257. && command_data(closed_command).data == 0)
  258. line_warn ("command @%s does not accept arguments",
  259. command_name(closed_command));
  260. if (closed_command == CM_anchor) // 5051
  261. {
  262. NODE_SPEC_EXTRA *parsed_anchor;
  263. current->parent->line_nr = line_nr;
  264. parsed_anchor = parse_node_manual (current);
  265. if (check_node_label (parsed_anchor, CM_anchor))
  266. {
  267. register_label (current->parent, parsed_anchor);
  268. if (current_region ())
  269. add_extra_element (current, "region", current_region ());
  270. }
  271. }
  272. else if (command_data(closed_command).flags & CF_ref) // 5062
  273. {
  274. ELEMENT *ref = current->parent, *args;
  275. KEY_PAIR *k;
  276. if (ref->args.number > 0)
  277. {
  278. k = lookup_extra_key (ref, "brace_command_contents");
  279. args = k->value;
  280. if ((closed_command == CM_inforef
  281. && (args->contents.number <= 0
  282. || !args->contents.list[0])
  283. && (args->contents.number <= 2
  284. || !args->contents.list[2]))
  285. || (closed_command != CM_inforef
  286. && (args->contents.number <= 0
  287. || !args->contents.list[0])
  288. && (args->contents.number <= 3
  289. || !args->contents.list[3])
  290. && (args->contents.number <= 4
  291. || !args->contents.list[4])))
  292. {
  293. line_warn ("command @%s missing a node or external manual "
  294. "argument", command_name(closed_command));
  295. }
  296. else
  297. {
  298. NODE_SPEC_EXTRA *nse;
  299. nse = parse_node_manual (args_child_by_index (ref, 0));
  300. if (nse && (nse->manual_content || nse->node_content))
  301. add_extra_node_spec (ref, "node_argument", nse);
  302. else
  303. free (nse);
  304. if (closed_command != CM_inforef
  305. && (args->contents.number <= 3
  306. || args->contents.number <= 4
  307. && !contents_child_by_index(args, 3)
  308. || (!contents_child_by_index(args, 3)
  309. && !contents_child_by_index(args, 4)))
  310. && !nse->manual_content)
  311. {
  312. remember_internal_xref (ref);
  313. }
  314. }
  315. // TODO 5085 check node name not empty after normalization
  316. }
  317. }
  318. else if (closed_command == CM_image) // 5109
  319. {
  320. ELEMENT *image = current->parent;
  321. KEY_PAIR *k;
  322. if (image->args.number == 0)
  323. goto image_no_args;
  324. k = lookup_extra_key (image, "brace_command_contents");
  325. if (!k)
  326. goto image_no_args;
  327. if (!contents_child_by_index (k->value, 0))
  328. goto image_no_args;
  329. if (0)
  330. {
  331. image_no_args:
  332. line_error ("@image missing filename argument");
  333. }
  334. }
  335. else if (closed_command == CM_dotless)
  336. {
  337. if (current->contents.number > 0)
  338. {
  339. char *text = current->contents.list[0]->text.text;
  340. if (!text || (strcmp (text, "i") && strcmp (text, "j")))
  341. {
  342. line_error ("@dotless expects `i' or `j' as argument, "
  343. "not `%s'", text);
  344. }
  345. }
  346. }
  347. else if ((command_data(closed_command).flags & CF_inline)
  348. || closed_command == CM_abbr
  349. || closed_command == CM_acronym)
  350. { // 5129
  351. KEY_PAIR *k;
  352. if (current->parent->cmd == CM_inlineraw)
  353. {
  354. if (ct_inlineraw != pop_context ())
  355. abort ();
  356. }
  357. if (current->parent->args.number == 0
  358. || !(k = lookup_extra_key (current->parent,
  359. "brace_command_contents"))
  360. || !k->value || k->value->contents.number == 0
  361. || !k->value->contents.list[0])
  362. {
  363. line_warn ("@%s missing first argument",
  364. command_name(current->parent->cmd));
  365. }
  366. }
  367. else if (closed_command == CM_errormsg) // 5173
  368. {
  369. int i;
  370. /* Find arg */
  371. /* Should we use trim_spaces_comment_from_content instead? */
  372. for (i = 0; i < current->contents.number; i++)
  373. {
  374. enum element_type t = current->contents.list[i]->type;
  375. if (current->contents.list[i]->text.end > 0
  376. && t != ET_empty_line_after_command
  377. && t != ET_empty_spaces_after_command
  378. && t != ET_empty_spaces_before_argument
  379. && t != ET_empty_space_at_end_def_bracketed
  380. && t != ET_empty_spaces_after_close_brace)
  381. break;
  382. }
  383. if (i == current->contents.number)
  384. ;
  385. else
  386. {
  387. char *arg = current->contents.list[i]->text.text;
  388. line_error (arg);
  389. }
  390. }
  391. else if (closed_command == CM_U)
  392. {
  393. int i;
  394. /* Find arg */
  395. /* Should we use trim_spaces_comment_from_content instead? */
  396. for (i = 0; i < current->contents.number; i++)
  397. {
  398. enum element_type t = current->contents.list[i]->type;
  399. if (current->contents.list[i]->text.end > 0
  400. && t != ET_empty_line_after_command
  401. && t != ET_empty_spaces_after_command
  402. && t != ET_empty_spaces_before_argument
  403. && t != ET_empty_space_at_end_def_bracketed
  404. && t != ET_empty_spaces_after_close_brace)
  405. break;
  406. }
  407. if (i == current->contents.number)
  408. {
  409. line_warn ("no argument specified for @U");
  410. }
  411. else
  412. {
  413. char *arg = current->contents.list[i]->text.text;
  414. int n = strspn (arg, "0123456789ABCDEFabcdef");
  415. if (arg[n])
  416. {
  417. line_error ("non-hex digits in argument for @U: %s", arg);
  418. }
  419. else if (n < 4)
  420. {
  421. line_warn
  422. ("fewer than four hex digits in argument for @U: %s", arg);
  423. }
  424. else
  425. {
  426. int val;
  427. int ret = sscanf (arg, "%d", &val);
  428. if (ret != 1)
  429. {
  430. debug ("hex sscanf failed %s", arg);
  431. /* unknown error. possibly argument is too large
  432. for an int. */
  433. }
  434. if (ret != 1 || val > 0x10FFF)
  435. {
  436. line_error
  437. ("argument for @U exceeds Unicode maximum 0x10FFFF: %s",
  438. arg);
  439. }
  440. }
  441. }
  442. }
  443. else if (command_with_command_as_argument (current->parent->parent)
  444. && current->contents.number == 0)
  445. {
  446. debug ("FOR PARENT ... command_as_argument_braces ...");
  447. if (!current->parent->type)
  448. current->parent->type = ET_command_as_argument;
  449. add_extra_element (current->parent->parent->parent,
  450. "command_as_argument", current->parent);
  451. }
  452. register_global_command (current->parent->cmd, current->parent);
  453. // 5190
  454. if (current->parent->cmd == CM_anchor
  455. || current->parent->cmd == CM_hyphenation
  456. || current->parent->cmd == CM_caption
  457. || current->parent->cmd == CM_shortcaption)
  458. {
  459. ELEMENT *e;
  460. e = new_element (ET_empty_spaces_after_close_brace);
  461. text_append (&e->text, "");
  462. add_to_element_contents (current->parent->parent, e);
  463. }
  464. current = current->parent->parent;
  465. if (close_preformatted_command(closed_command))
  466. current = begin_preformatted (current);
  467. } /* CF_brace */
  468. else if (current->type == ET_rawpreformatted) // 5199
  469. {
  470. /* lone right braces are accepted in a rawpreformatted */
  471. ELEMENT *e = new_element (ET_NONE);
  472. text_append_n (&e->text, "}", 1);
  473. add_to_element_contents (current, e);
  474. goto funexit;
  475. }
  476. // 5203 -- context brace command (e.g. @footnote)
  477. else if (current_context() == ct_footnote
  478. || current_context() == ct_caption
  479. || current_context() == ct_shortcaption
  480. || current_context() == ct_math)
  481. {
  482. enum context c;
  483. current = end_paragraph (current, 0, 0);
  484. if (current->parent
  485. && (command_flags(current->parent) & CF_brace)
  486. && (command_data(current->parent->cmd).data == BRACE_context))
  487. {
  488. enum command_id closed_command;
  489. c = pop_context ();
  490. debug ("CLOSING(context command)");
  491. closed_command = current->parent->cmd;
  492. register_global_command (current->parent->cmd, current->parent);
  493. // 5220
  494. current = current->parent->parent;
  495. if (close_preformatted_command(closed_command))
  496. current = begin_preformatted (current);
  497. }
  498. }
  499. else // 5224
  500. {
  501. line_error ("misplaced }");
  502. goto funexit;
  503. }
  504. funexit:
  505. *line_inout = line;
  506. return current;
  507. }
  508. // 2577
  509. /* Remove 'brace_command_contents' or 'block_command_line_contents'
  510. extra value if empty.
  511. TODO: If not empty, remove empty elements thereof. */
  512. void
  513. remove_empty_content_arguments (ELEMENT *current)
  514. {
  515. KEY_PAIR *k;
  516. k = lookup_extra_key (current, "block_command_line_contents");
  517. if (!k)
  518. k = lookup_extra_key (current, "brace_command_contents");
  519. if (!k)
  520. return;
  521. while (k->value->contents.number > 0
  522. && !last_contents_child(k->value)) // ->contents.number == 0)
  523. pop_element_from_contents (k->value);
  524. if (k->value->contents.number == 0)
  525. {
  526. k->key = "";
  527. k->type = extra_deleted;
  528. }
  529. }
  530. /* Handle a comma separating arguments to a Texinfo command. */
  531. /* 5228 */
  532. ELEMENT *
  533. handle_comma (ELEMENT *current, char **line_inout)
  534. {
  535. char *line = *line_inout;
  536. enum element_type type;
  537. ELEMENT *new_arg, *e;
  538. abort_empty_line (&current, NULL);
  539. /* Register brace_command_contents or block_command_line_contents in extra
  540. key. */
  541. if (command_flags(current->parent) & CF_brace
  542. && command_data(current->parent->cmd).data > 0)
  543. {
  544. // 5033
  545. isolate_last_space (current, 0);
  546. register_command_arg (current, "brace_command_contents");
  547. remove_empty_content_arguments (current);
  548. }
  549. else
  550. {
  551. isolate_last_space (current, 0);
  552. if (command_flags(current->parent) & CF_block)
  553. {
  554. register_command_arg (current, "block_command_line_contents");
  555. }
  556. }
  557. type = current->type;
  558. current = current->parent;
  559. // 5244
  560. if (command_flags(current) & CF_inline)
  561. {
  562. KEY_PAIR *k;
  563. int expandp = 0;
  564. debug ("THE INLINE PART");
  565. k = lookup_extra_key (current, "format");
  566. if (!k)
  567. {
  568. KEY_PAIR *k;
  569. char *inline_type = 0;
  570. k = lookup_extra_key (current, "brace_command_contents");
  571. if (k)
  572. {
  573. ELEMENT *args = 0, *arg = 0;
  574. int i;
  575. args = (ELEMENT *) k->value;
  576. if (!args)
  577. goto inline_no_arg;
  578. if (args->contents.number == 0)
  579. goto inline_no_arg;
  580. arg = args->contents.list[0];
  581. if (!arg)
  582. goto inline_no_arg; /* Possible if registered as 'undef'. */
  583. /* Find text argument.
  584. TODO: Should we use trim_spaces_comment_from_content instead?
  585. Or use a function for this? */
  586. for (i = 0; i < arg->contents.number; i++)
  587. {
  588. enum element_type t = arg->contents.list[i]->type;
  589. if (arg->contents.list[i]->text.end > 0
  590. && t != ET_empty_line_after_command
  591. && t != ET_empty_spaces_after_command
  592. && t != ET_empty_spaces_before_argument
  593. && t != ET_empty_space_at_end_def_bracketed
  594. && t != ET_empty_spaces_after_close_brace)
  595. break;
  596. }
  597. if (i != arg->contents.number)
  598. {
  599. inline_type = arg->contents.list[i]->text.text;
  600. }
  601. }
  602. debug ("INLINE <%s>", inline_type);
  603. if (!inline_type)
  604. {
  605. inline_no_arg:
  606. /* Condition is missing */
  607. debug ("INLINE COND MISSING");
  608. }
  609. else if (current->cmd == CM_inlineraw
  610. || current->cmd == CM_inlinefmt
  611. || current->cmd == CM_inlinefmtifelse)
  612. {
  613. if (format_expanded_p (inline_type))
  614. {
  615. expandp = 1;
  616. add_extra_string (current, "expand_index", "1");
  617. }
  618. else
  619. expandp = 0;
  620. }
  621. else if (current->cmd == CM_inlineifset
  622. || current->cmd == CM_inlineifclear)
  623. {
  624. expandp = 0;
  625. if (fetch_value (inline_type, strlen (inline_type)))
  626. expandp = 1;
  627. if (current->cmd == CM_inlineifclear)
  628. expandp = !expandp;
  629. if (expandp)
  630. add_extra_string (current, "expand_index", "1");
  631. }
  632. else
  633. expandp = 0;
  634. add_extra_string (current, "format", inline_type);
  635. /* Skip first argument for a false @inlinefmtifelse */
  636. if (!expandp && current->cmd == CM_inlinefmtifelse)
  637. {
  638. ELEMENT *e;
  639. int brace_count = 1;
  640. add_extra_string (current, "expand_index", "2");
  641. /* Add a dummy argument for the first argument. */
  642. e = new_element (ET_elided);
  643. add_to_element_args (current, e);
  644. register_command_arg (e, "brace_command_contents");
  645. /* Scan forward to get the next argument. */
  646. while (brace_count > 0)
  647. {
  648. line += strcspn (line, "{},");
  649. switch (*line)
  650. {
  651. case ',':
  652. if (brace_count == 1)
  653. {
  654. line++;
  655. goto inlinefmtifelse_done;
  656. }
  657. break;
  658. case '{':
  659. brace_count++;
  660. break;
  661. case '}':
  662. brace_count--;
  663. break;
  664. default:
  665. line = next_text ();
  666. if (!line)
  667. {
  668. /* ERROR - unbalanced brace */
  669. }
  670. continue;
  671. }
  672. line++;
  673. }
  674. inlinefmtifelse_done:
  675. /* Check if the second argument is missing. */
  676. if (brace_count == 0)
  677. {
  678. line--; /* on '}' */
  679. }
  680. counter_dec (&count_remaining_args);
  681. expandp = 1;
  682. }
  683. }
  684. else if (current->cmd == CM_inlinefmtifelse)
  685. {
  686. /* Second art of @inlinefmtifelse when condition is true. Discard
  687. second argument. */
  688. expandp = 0;
  689. }
  690. /* If this command is not being expanded, add a dummy argument, and
  691. scan forward to the closing brace. */
  692. if (!expandp)
  693. {
  694. ELEMENT *e;
  695. int brace_count = 1;
  696. e = new_element (ET_elided);
  697. add_to_element_args (current, e);
  698. while (brace_count > 0)
  699. {
  700. line += strcspn (line, "{}");
  701. switch (*line)
  702. {
  703. case '{':
  704. brace_count++;
  705. break;
  706. case '}':
  707. brace_count--;
  708. break;
  709. default:
  710. line = next_text ();
  711. if (!line)
  712. {
  713. /* ERROR - unbalanced brace */
  714. }
  715. continue;
  716. }
  717. line++;
  718. }
  719. current = last_args_child (current);
  720. line--; /* on '}' */
  721. goto funexit;
  722. }
  723. }
  724. counter_dec (&count_remaining_args);
  725. new_arg = new_element (type);
  726. add_to_element_args (current, new_arg);
  727. current = new_arg;
  728. e = new_element (ET_empty_spaces_before_argument);
  729. text_append (&e->text, ""); /* See comment in parser.c:merge_text */
  730. add_to_element_contents (current, e);
  731. funexit:
  732. *line_inout = line;
  733. return current;
  734. }
  735. /* Actions to be taken when a special character appears in the input. */
  736. ELEMENT *
  737. handle_separator (ELEMENT *current, char separator, char **line_inout)
  738. {
  739. char *line = *line_inout;
  740. if (separator == '{') // 4888
  741. {
  742. current = handle_open_brace (current, &line);
  743. }
  744. else if (separator == '}') // 5007
  745. {
  746. current = handle_close_brace (current, &line);
  747. }
  748. /* If a comma is seen after all the arguments for the command have been
  749. read, it is included in the last argument. */
  750. else if (separator == ',' // 5228
  751. && counter_value (&count_remaining_args, current->parent) > 0)
  752. {
  753. current = handle_comma (current, &line);
  754. }
  755. else if (separator == ',' && current->type == ET_misc_line_arg
  756. && current->parent->cmd == CM_node) // 5297
  757. {
  758. line_warn ("superfluous arguments for node");
  759. }
  760. /* 5303 After a separator in a menu. */
  761. else if ((separator == ','
  762. || separator == '\t'
  763. || separator == '.')
  764. && current->type == ET_menu_entry_node
  765. || separator == ':' && current->type == ET_menu_entry_name)
  766. {
  767. ELEMENT *e;
  768. current = current->parent;
  769. e = new_element (ET_menu_entry_separator);
  770. text_append_n (&e->text, &separator, 1);
  771. add_to_element_args (current, e);
  772. /* Note in 'handle_menu' in menus.c, if a '.' is not followed by
  773. whitespace, we revert was was done here. */
  774. }
  775. else if (separator == '\f' && current->type == ET_paragraph)
  776. {
  777. ELEMENT *e;
  778. /* A form feed stops and restarts a paragraph. */
  779. current = end_paragraph (current, 0, 0);
  780. e = new_element (ET_empty_line);
  781. text_append_n (&e->text, "\f", 1);
  782. add_to_element_contents (current, e);
  783. e = new_element (ET_empty_line);
  784. add_to_element_contents (current, e);
  785. }
  786. else // 5322
  787. {
  788. /* Default - merge the character as usual. */
  789. char t[2];
  790. t[0] = separator;
  791. t[1] = '\0';
  792. current = merge_text (current, t);
  793. }
  794. *line_inout = line;
  795. return current;
  796. }