handle_commands.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. /* handle_commands.c -- what to do when a command name is first read */
  2. /* Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016
  3. 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. #include <stdlib.h>
  15. #include <string.h>
  16. #include "parser.h"
  17. #include "input.h"
  18. #include "text.h"
  19. #include "errors.h"
  20. static int section_level (ELEMENT *section);
  21. /* Return a containing @itemize or @enumerate if inside it. */
  22. // 1847
  23. ELEMENT *
  24. item_container_parent (ELEMENT *current)
  25. {
  26. if ((current->cmd == CM_item
  27. || current->type == ET_before_item)
  28. && current->parent
  29. && ((current->parent->cmd == CM_itemize
  30. || current->parent->cmd == CM_enumerate)))
  31. {
  32. return current->parent;
  33. }
  34. return 0;
  35. }
  36. // 1352
  37. /* Check that there are no text holding environments (currently
  38. checking only paragraphs and preformatted) in contents. */
  39. int
  40. check_no_text (ELEMENT *current)
  41. {
  42. int after_paragraph = 0;
  43. int i, j;
  44. for (i = 0; i < current->contents.number; i++)
  45. {
  46. enum element_type t;
  47. ELEMENT *f;
  48. f = current->contents.list[i];
  49. t = f->type;
  50. if (t == ET_paragraph)
  51. {
  52. after_paragraph = 1;
  53. break;
  54. }
  55. else if (t == ET_preformatted
  56. || t == ET_rawpreformatted)
  57. {
  58. for (j = 0; j < f->contents.number; j++)
  59. {
  60. ELEMENT *g = f->contents.list[j];
  61. if ((g->text.end > 0
  62. && g->text.text[strspn (g->text.text, whitespace_chars)])
  63. || (g->cmd && g->cmd != CM_c
  64. && g->cmd != CM_comment
  65. && g->type != ET_index_entry_command))
  66. {
  67. after_paragraph = 1;
  68. break;
  69. }
  70. }
  71. if (after_paragraph)
  72. break;
  73. }
  74. }
  75. return after_paragraph;
  76. }
  77. // 1056
  78. /* Record the information from a command of global effect.
  79. TODO: Could we scrap the first argument and use CURRENT->cmd? */
  80. int
  81. register_global_command (enum command_id cmd, ELEMENT *current)
  82. {
  83. // TODO: Why even give @author this flag in the first place?
  84. if (cmd != CM_author && (command_data(cmd).flags & CF_global))
  85. {
  86. if (!current->line_nr.line_nr)
  87. current->line_nr = line_nr;
  88. switch (cmd)
  89. {
  90. #define GLOBAL_CASE(cmx) \
  91. case CM_##cmx: \
  92. add_to_contents_as_array (&global_info.cmx, current); \
  93. break
  94. case CM_footnote:
  95. add_to_contents_as_array (&global_info.footnotes, current);
  96. break;
  97. GLOBAL_CASE(hyphenation);
  98. GLOBAL_CASE(insertcopying);
  99. GLOBAL_CASE(printindex);
  100. GLOBAL_CASE(subtitle);
  101. GLOBAL_CASE(titlefont);
  102. GLOBAL_CASE(listoffloats);
  103. GLOBAL_CASE(detailmenu);
  104. GLOBAL_CASE(part);
  105. /* from Common.pm %document_settable_at_commands */
  106. GLOBAL_CASE(allowcodebreaks);
  107. GLOBAL_CASE(clickstyle);
  108. GLOBAL_CASE(codequotebacktick);
  109. GLOBAL_CASE(codequoteundirected);
  110. GLOBAL_CASE(contents);
  111. GLOBAL_CASE(deftypefnnewline);
  112. GLOBAL_CASE(documentencoding);
  113. GLOBAL_CASE(documentlanguage);
  114. GLOBAL_CASE(exampleindent);
  115. GLOBAL_CASE(firstparagraphindent);
  116. GLOBAL_CASE(frenchspacing);
  117. GLOBAL_CASE(headings);
  118. GLOBAL_CASE(kbdinputstyle);
  119. GLOBAL_CASE(paragraphindent);
  120. GLOBAL_CASE(shortcontents);
  121. GLOBAL_CASE(urefbreakstyle);
  122. GLOBAL_CASE(xrefautomaticsectiontitle);
  123. #undef GLOBAL_CASE
  124. }
  125. /* TODO: Check if all of these are necessary. */
  126. return 1;
  127. }
  128. else if ((command_data(cmd).flags & CF_global_unique))
  129. {
  130. ELEMENT **where = 0;
  131. if (cmd == CM_shortcontents)
  132. cmd = CM_summarycontents;
  133. if (!current->line_nr.line_nr)
  134. current->line_nr = line_nr;
  135. switch (cmd)
  136. {
  137. extern int input_number;
  138. case CM_setfilename:
  139. /* Check if we are inside an @include, and if so, do nothing. */
  140. if (input_number > 1)
  141. break;
  142. where = &global_info.setfilename;
  143. break;
  144. #define GLOBAL_UNIQUE_CASE(cmd) \
  145. case CM_##cmd: \
  146. where = &global_info.cmd; \
  147. break
  148. GLOBAL_UNIQUE_CASE(settitle);
  149. GLOBAL_UNIQUE_CASE(copying);
  150. GLOBAL_UNIQUE_CASE(titlepage);
  151. GLOBAL_UNIQUE_CASE(top);
  152. GLOBAL_UNIQUE_CASE(documentdescription);
  153. GLOBAL_UNIQUE_CASE(setcontentsaftertitlepage);
  154. GLOBAL_UNIQUE_CASE(setshortcontentsaftertitlepage);
  155. GLOBAL_UNIQUE_CASE(novalidate);
  156. GLOBAL_UNIQUE_CASE(validatemenus);
  157. GLOBAL_UNIQUE_CASE(pagesizes);
  158. GLOBAL_UNIQUE_CASE(fonttextsize);
  159. GLOBAL_UNIQUE_CASE(footnotestyle);
  160. GLOBAL_UNIQUE_CASE(setchapternewpage);
  161. GLOBAL_UNIQUE_CASE(everyheading);
  162. GLOBAL_UNIQUE_CASE(everyfooting);
  163. GLOBAL_UNIQUE_CASE(evenheading);
  164. GLOBAL_UNIQUE_CASE(evenfooting);
  165. GLOBAL_UNIQUE_CASE(oddheading);
  166. GLOBAL_UNIQUE_CASE(oddfooting);
  167. GLOBAL_UNIQUE_CASE(everyheadingmarks);
  168. GLOBAL_UNIQUE_CASE(everyfootingmarks);
  169. GLOBAL_UNIQUE_CASE(evenheadingmarks);
  170. GLOBAL_UNIQUE_CASE(oddheadingmarks);
  171. GLOBAL_UNIQUE_CASE(evenfootingmarks);
  172. GLOBAL_UNIQUE_CASE(oddfootingmarks);
  173. GLOBAL_UNIQUE_CASE(shorttitlepage);
  174. GLOBAL_UNIQUE_CASE(title);
  175. #undef GLOBAL_UNIQUE_CASE
  176. /* NOTE: Same list in api.c:build_global_info2. */
  177. }
  178. if (where)
  179. {
  180. if (*where)
  181. line_warn ("multiple @%s", command_name(cmd));
  182. else
  183. *where = current;
  184. }
  185. return 1;
  186. }
  187. return 0;
  188. }
  189. /* Line 4289 */
  190. /* STATUS is set to 1 if we should get a new line after this,
  191. 2 if we should stop processing completely. */
  192. ELEMENT *
  193. handle_misc_command (ELEMENT *current, char **line_inout,
  194. enum command_id cmd, int *status,
  195. enum command_id invalid_parent)
  196. {
  197. ELEMENT *misc = 0;
  198. char *line = *line_inout;
  199. int arg_spec;
  200. *status = 0;
  201. /* Root commands (like @node) and @bye 4290 */
  202. if (command_data(cmd).flags & CF_root || cmd == CM_bye)
  203. {
  204. ELEMENT *closed_elt; /* Not used */
  205. current = close_commands (current, 0, &closed_elt, cmd);
  206. if (current->type == ET_text_root)
  207. {
  208. if (cmd != CM_bye)
  209. {
  210. /* Something to do with document_root and text_root. */
  211. ELEMENT *new_root = new_element (ET_document_root);
  212. add_to_element_contents (new_root, current);
  213. current = new_root;
  214. }
  215. }
  216. else
  217. {
  218. current = current->parent;
  219. if (!current)
  220. abort ();
  221. }
  222. }
  223. /* Look up information about this command ( noarg skipline skipspace text
  224. line lineraw /^\d$/). */
  225. arg_spec = command_data(cmd).data;
  226. /* noarg 4312 */
  227. if (arg_spec == MISC_noarg)
  228. {
  229. int ignored = 0;
  230. int only_in_headings = 0;
  231. if (cmd == CM_insertcopying)
  232. {
  233. ELEMENT *p = current;
  234. while (p)
  235. {
  236. if (p->cmd == CM_copying)
  237. {
  238. line_error ("@%s not allowed inside `@copying' block",
  239. command_name(cmd));
  240. ignored = 1;
  241. break;
  242. }
  243. p = p->parent;
  244. }
  245. }
  246. else if (command_data(cmd).flags & CF_in_heading)
  247. {
  248. line_error ("@%s should only appear in heading or footing",
  249. command_name(cmd));
  250. only_in_headings = 1;
  251. }
  252. if (!ignored)
  253. {
  254. misc = new_element (ET_NONE);
  255. misc->cmd = cmd;
  256. add_to_element_contents (current, misc);
  257. if (only_in_headings)
  258. add_extra_string (misc, "invalid_nesting", "1");
  259. register_global_command (cmd, misc);
  260. }
  261. mark_and_warn_invalid (cmd, invalid_parent, misc);
  262. if (close_preformatted_command(cmd))
  263. current = begin_preformatted (current);
  264. }
  265. /* All the cases using the raw line.
  266. I don't understand what the difference is between these. */
  267. else if (arg_spec == MISC_skipline /* 4347 */
  268. || arg_spec == MISC_lineraw
  269. || arg_spec == MISC_special)
  270. {
  271. ELEMENT *args = 0;
  272. enum command_id equivalent_cmd = 0;
  273. int has_comment = 0;
  274. /* 4350 If the current input is the result of a macro expansion,
  275. it may not be a complete line. Check for this and acquire the rest
  276. of the line if necessary. */
  277. if (!strchr (line, '\n'))
  278. {
  279. char *line2;
  280. LINE_NR save_ln;
  281. input_push_text (strdup (line), 0);
  282. save_ln = line_nr;
  283. line2 = new_line ();
  284. if (line2)
  285. {
  286. line = line2;
  287. line_nr = save_ln;
  288. }
  289. }
  290. misc = new_element (ET_NONE);
  291. misc->cmd = cmd;
  292. if (arg_spec == MISC_skipline || arg_spec == MISC_lineraw)
  293. {
  294. ELEMENT *arg;
  295. args = new_element (ET_NONE);
  296. arg = new_element (ET_NONE);
  297. add_to_element_contents (args, arg);
  298. text_append (&arg->text, line);
  299. }
  300. else /* arg_spec == MISC_special */
  301. {
  302. args = parse_special_misc_command (line, cmd, &has_comment); //4362
  303. add_extra_string (misc, "arg_line", strdup (line));
  304. }
  305. /* Handle @set txicodequoteundirected as an
  306. obsolete alternative to @codequoteundirected. */
  307. if (cmd == CM_set || cmd == CM_clear)
  308. {
  309. if (args->contents.number > 0
  310. && args->contents.list[0]->text.end > 0)
  311. {
  312. if (!strcmp (args->contents.list[0]->text.text,
  313. "txicodequoteundirected"))
  314. equivalent_cmd = CM_codequoteundirected;
  315. else if (!strcmp (args->contents.list[0]->text.text,
  316. "txicodequotebacktick"))
  317. equivalent_cmd = CM_codequotebacktick;
  318. }
  319. }
  320. if (equivalent_cmd)
  321. {
  322. char *arg = 0;
  323. ELEMENT *misc_line_args;
  324. ELEMENT *spaces_after_command;
  325. ELEMENT *e;
  326. if (cmd == CM_set)
  327. arg = "on";
  328. else
  329. arg = "off";
  330. /* Now manufacture the parse tree for the equivalent
  331. command and add it to the tree. */
  332. destroy_element (args);
  333. args = new_element (ET_NONE);
  334. e = new_element (ET_NONE);
  335. text_append (&e->text, arg);
  336. add_to_element_contents (args, e);
  337. destroy_element (misc);
  338. misc = new_element (ET_NONE);
  339. misc->cmd = equivalent_cmd;
  340. misc->line_nr = line_nr;
  341. misc_line_args = new_element (ET_misc_line_arg);
  342. add_to_element_args (misc, misc_line_args);
  343. add_extra_misc_args (misc, "misc_args", args);
  344. spaces_after_command = new_element
  345. (ET_empty_spaces_after_command);
  346. text_append_n (&spaces_after_command->text, " ", 1);
  347. add_extra_element (misc, "spaces_after_command",
  348. spaces_after_command);
  349. add_extra_element (spaces_after_command, "command", misc);
  350. add_to_element_contents (misc_line_args, spaces_after_command);
  351. e = new_element (ET_NONE);
  352. text_append (&e->text, arg);
  353. add_to_element_contents (misc_line_args, e);
  354. e = new_element (ET_spaces_at_end);
  355. text_append_n (&e->text, "\n", 1);
  356. add_to_element_contents (misc_line_args, e);
  357. add_to_element_contents (current, misc);
  358. }
  359. else // 4402
  360. {
  361. int i;
  362. add_to_element_contents (current, misc);
  363. for (i = 0; i < args->contents.number; i++)
  364. {
  365. ELEMENT *misc_arg = new_element (ET_misc_arg);
  366. text_append_n (&misc_arg->text,
  367. args->contents.list[i]->text.text,
  368. args->contents.list[i]->text.end);
  369. add_to_element_args (misc, misc_arg);
  370. }
  371. /* TODO: Could we have just set misc->args directly as args? */
  372. if (args->contents.number > 0 && arg_spec != MISC_skipline)
  373. add_extra_misc_args (misc, "misc_args", args);
  374. else
  375. {
  376. for (i = 0; i < args->contents.number; i++)
  377. {
  378. destroy_element (args->contents.list[i]);
  379. }
  380. destroy_element (args);
  381. }
  382. }
  383. if (0 || cmd == CM_raisesections)
  384. {
  385. }
  386. else if (0 || cmd == CM_raisesections)
  387. {
  388. }
  389. else if (cmd == CM_novalidate)
  390. {
  391. }
  392. mark_and_warn_invalid (cmd, invalid_parent, misc);
  393. register_global_command (cmd, misc); // 4423
  394. if (arg_spec != MISC_special || !has_comment)
  395. current = end_line (current);
  396. // 4429
  397. if (cmd == CM_bye)
  398. {
  399. *status = 2; /* Finish processing completely. */
  400. goto funexit;
  401. }
  402. if (close_preformatted_command(cmd))
  403. current = begin_preformatted (current);
  404. *status = 1; /* Get a new line */
  405. goto funexit;
  406. }
  407. else
  408. {
  409. /* line 4435 - text, line, skipspace or a number.
  410. (This includes handling of "@end", which is MISC_text.) */
  411. int line_arg = 0;
  412. if (arg_spec != MISC_skipspace)
  413. line_arg = 1;
  414. /* 4439 */
  415. /*************************************************************/
  416. /* Special handling of @item because it can appear
  417. in several contents: in an @itemize, a @table, or
  418. a @multitable. */
  419. if (cmd == CM_item || cmd == CM_itemx
  420. || cmd == CM_headitem || cmd == CM_tab)
  421. {
  422. ELEMENT *parent;
  423. /* @itemize or @enumerate */ // 4443
  424. if ((parent = item_container_parent (current)))
  425. {
  426. if (cmd == CM_item)
  427. {
  428. char *s;
  429. debug ("ITEM CONTAINER");
  430. counter_inc (&count_items);
  431. misc = new_element (ET_NONE);
  432. misc->cmd = CM_item;
  433. asprintf (&s, "%d", counter_value (&count_items, parent));
  434. add_extra_string (misc, "item_number", s);
  435. add_to_element_contents (parent, misc);
  436. current = misc;
  437. }
  438. else
  439. {
  440. line_error ("@%s not meaningful inside `@%s' block",
  441. command_name(cmd),
  442. command_name(parent->cmd));
  443. }
  444. current = begin_preformatted (current);
  445. }
  446. /* @table, @vtable, @ftable */
  447. else if ((parent = item_line_parent (current)))
  448. {
  449. if (cmd == CM_item || cmd == CM_itemx)
  450. {
  451. debug ("ITEM_LINE");
  452. current = parent;
  453. gather_previous_item (current, cmd);
  454. misc = new_element (ET_NONE);
  455. misc->cmd = cmd;
  456. add_to_element_contents (current, misc);
  457. line_arg = 1;
  458. }
  459. else
  460. {
  461. line_error ("@%s not meaningful inside `@%s' block",
  462. command_name(cmd),
  463. command_name(parent->cmd));
  464. current = begin_preformatted (current);
  465. }
  466. }
  467. /* In a @multitable */
  468. else if ((parent = item_multitable_parent (current))) // 4477
  469. {
  470. if (cmd != CM_item && cmd != CM_headitem
  471. && cmd != CM_tab)
  472. {
  473. line_error ("@%s not meaningful inside @%s block",
  474. command_name(cmd),
  475. command_name(parent->cmd)); // 4521
  476. }
  477. else
  478. { /* 4480 */
  479. int max_columns = 0;
  480. KEY_PAIR *prototypes;
  481. prototypes = lookup_extra_key (parent, "prototypes");
  482. if (prototypes)
  483. max_columns = prototypes->value->contents.number;
  484. else
  485. {
  486. prototypes = lookup_extra_key(parent, "columnfractions");
  487. if (prototypes)
  488. max_columns = prototypes->value->contents.number;
  489. }
  490. if (max_columns == 0)
  491. {
  492. line_warn ("@%s in empty multitable",
  493. command_name(cmd));
  494. }
  495. else if (cmd == CM_tab)
  496. { // 4484
  497. ELEMENT *row;
  498. row = last_contents_child (parent);
  499. if (row->type == ET_before_item)
  500. line_error ("@tab before @item");
  501. // 4489
  502. else if (counter_value (&count_cells, row)
  503. >= max_columns)
  504. {
  505. line_error ("too many columns in multitable item"
  506. " (max %d)", max_columns);
  507. }
  508. else // 4493
  509. {
  510. char *s;
  511. counter_inc (&count_cells);
  512. misc = new_element (ET_NONE);
  513. misc->cmd = cmd;
  514. add_to_element_contents (row, misc);
  515. current = misc;
  516. debug ("TAB");
  517. asprintf (&s, "%d",
  518. counter_value (&count_cells, row));
  519. add_extra_string (current, "cell_number", s);
  520. }
  521. }
  522. else /* 4505 @item or @headitem */
  523. {
  524. ELEMENT *row; char *s;
  525. debug ("ROW");
  526. row = new_element (ET_row);
  527. add_to_element_contents (parent, row);
  528. /* FIXME:The "row_number" extra value,
  529. isn't actually used anywhere. */
  530. asprintf (&s, "%d", parent->contents.number-1);
  531. add_extra_string (row, "row_number", s);
  532. misc = new_element (ET_NONE);
  533. misc->cmd = cmd;
  534. add_to_element_contents (row, misc);
  535. current = misc;
  536. if (counter_value (&count_cells, parent) != -1)
  537. counter_pop (&count_cells);
  538. counter_push (&count_cells, row, 1);
  539. asprintf (&s, "%d",
  540. counter_value (&count_cells, row));
  541. add_extra_string (current, "cell_number", s);
  542. }
  543. }
  544. current = begin_preformatted (current);
  545. } /* In @multitable */
  546. else if (cmd == CM_tab) // 4526
  547. {
  548. line_error ("ignoring @tab outside of multitable");
  549. current = begin_preformatted (current);
  550. }
  551. else
  552. {
  553. line_error ("@%s outside of table or list",
  554. command_name(cmd));
  555. current = begin_preformatted (current);
  556. }
  557. if (misc)
  558. misc->line_nr = line_nr; // 4535
  559. }
  560. /*************************************************************/
  561. else /* Not @item, @itemx, @headitem, nor @tab 4536 */
  562. {
  563. /* Add to contents */
  564. misc = new_element (ET_NONE);
  565. misc->cmd = cmd;
  566. misc->line_nr = line_nr;
  567. add_to_element_contents (current, misc);
  568. if (command_data(cmd).flags & CF_sectioning)
  569. {
  570. /* Store section level in 'extra' key. */
  571. /* TODO: @part? */
  572. /*add_extra_string (last_contents_child (current),
  573. "sections_level", "1"); */
  574. add_extra_string (misc, "level",
  575. &("0\0" "0\0" "1\0" "2\0" "3\0" "4\0"
  576. "5\0" "6\0" "7\0" "8\0" "9\0" + 2)
  577. [section_level (misc) * 2]);
  578. }
  579. /* 4546 - def*x */
  580. if (command_data(cmd).flags & CF_def)
  581. {
  582. enum command_id base_command;
  583. char *base_name;
  584. int base_len;
  585. int after_paragraph;
  586. /* Find the command with "x" stripped from the end, e.g.
  587. deffnx -> deffn. */
  588. base_name = command_name(cmd);
  589. add_extra_string (misc, "original_def_cmdname", base_name);
  590. base_name = strdup (base_name);
  591. base_len = strlen (base_name);
  592. if (base_name[base_len - 1] != 'x')
  593. abort ();
  594. base_name[base_len - 1] = '\0';
  595. base_command = lookup_command (base_name);
  596. if (base_command == CM_NONE)
  597. abort ();
  598. add_extra_string (misc, "def_command", base_name);
  599. after_paragraph = check_no_text (current);
  600. push_context (ct_def);
  601. misc->type = ET_def_line; // 4553
  602. if (current->cmd == base_command)
  603. {
  604. ELEMENT *e = pop_element_from_contents (current);
  605. /* e should be the same as misc */
  606. /* Gather an "inter_def_item" element. */
  607. gather_def_item (current, cmd);
  608. add_to_element_contents (current, e);
  609. }
  610. if (current->cmd != base_command || after_paragraph)
  611. {
  612. // error - deffnx not after deffn
  613. line_error ("must be after `@%s' to use `@%s'",
  614. command_name(base_command),
  615. command_name(cmd));
  616. add_extra_string (misc, "not_after_command", "1");
  617. }
  618. }
  619. } /* 4571 */
  620. // Rest of the line is the argument - true unless is MISC_skipspace. */
  621. if (line_arg)
  622. {
  623. ELEMENT *arg;
  624. /* 4576 - change 'current' to its last child. This is ELEMENT *misc
  625. above. */
  626. current = last_contents_child (current);
  627. arg = new_element (ET_misc_line_arg);
  628. add_to_element_args (current, arg);
  629. if (cmd == CM_node) // 4584
  630. {
  631. /* At most three comma-separated arguments to @node. This
  632. is the only (non-block) line command taking comma-separated
  633. arguments. Its arguments will be gathered the same as
  634. those of some block line commands and brace commands. */
  635. counter_push (&count_remaining_args, current, 3);
  636. }
  637. else if (cmd == CM_author)
  638. {
  639. ELEMENT *parent = current;
  640. int found = 0;
  641. while (parent->parent)
  642. {
  643. parent = parent->parent;
  644. if (parent->type == ET_brace_command_context)
  645. break;
  646. if (parent->cmd == CM_titlepage)
  647. {
  648. // TODO 4595 global author
  649. add_extra_element (current, "titlepage", parent);
  650. found = 1; break;
  651. }
  652. else if (parent->cmd == CM_quotation
  653. || parent->cmd == CM_smallquotation)
  654. {
  655. KEY_PAIR *k; ELEMENT *e;
  656. k = lookup_extra_key (parent, "authors");
  657. if (k)
  658. e = k->value;
  659. else
  660. {
  661. e = new_element (ET_NONE);
  662. add_extra_contents (parent, "authors", e);
  663. }
  664. add_to_contents_as_array (e, current);
  665. add_extra_element (current, "quotation", parent);
  666. found = 1; break;
  667. }
  668. }
  669. if (!found)
  670. line_warn ("@author not meaningful outside "
  671. "`@titlepage' and `@quotation' environments");
  672. }
  673. else if (cmd == CM_dircategory && current_node)
  674. line_warn ("@dircategory after first node");
  675. current = last_args_child (current); /* arg */
  676. /* add 'line' to context_stack (Parser.pm:141). This will be the
  677. case while we read the argument on this line. */
  678. if (!(command_data(cmd).flags & CF_def))
  679. push_context (ct_line);
  680. }
  681. start_empty_line_after_command (current, &line, misc); //4621
  682. if (cmd == CM_indent || cmd == CM_noindent)
  683. {
  684. /* Start a new paragraph if not in one already. */
  685. int spaces;
  686. enum element_type t;
  687. ELEMENT *paragraph;
  688. /* Check if if we should change an ET_empty_line_after_command
  689. element to ET_empty_spaces_after_command by looking ahead
  690. to see what comes next. */
  691. if (!strchr (line, '\n'))
  692. {
  693. char *line2;
  694. input_push_text (strdup (line), 0);
  695. line2 = new_line ();
  696. if (line2)
  697. line = line2;
  698. }
  699. spaces = strspn (line, whitespace_chars);
  700. if (spaces > 0)
  701. {
  702. char saved = line[spaces];
  703. line[spaces] = '\0';
  704. current = merge_text (current, line);
  705. line[spaces] = saved;
  706. line += spaces;
  707. }
  708. if (*line
  709. && last_contents_child(current)->type
  710. == ET_empty_line_after_command)
  711. {
  712. last_contents_child(current)->type
  713. = ET_empty_spaces_after_command;
  714. }
  715. paragraph = begin_paragraph (current);
  716. if (paragraph)
  717. current = paragraph;
  718. if (!*line)
  719. {
  720. *status = 1; /* Get a new line. */
  721. goto funexit;
  722. }
  723. }
  724. }
  725. // 4622
  726. mark_and_warn_invalid (cmd, invalid_parent, misc);
  727. if (misc)
  728. register_global_command (cmd, misc);
  729. funexit:
  730. *line_inout = line;
  731. return current;
  732. }
  733. /* Return numbered level of an element */
  734. static int
  735. section_level (ELEMENT *section)
  736. {
  737. int level;
  738. int min_level = 0, max_level = 5;
  739. switch (section->cmd)
  740. {
  741. case CM_top: level = 0; break;
  742. case CM_chapter: level = 1; break;
  743. case CM_unnumbered: level = 1; break;
  744. case CM_chapheading: level = 1; break;
  745. case CM_appendix: level = 1; break;
  746. case CM_section: level = 2; break;
  747. case CM_unnumberedsec: level = 2; break;
  748. case CM_heading: level = 2; break;
  749. case CM_appendixsec: level = 2; break;
  750. case CM_subsection: level = 3; break;
  751. case CM_unnumberedsubsec: level = 3; break;
  752. case CM_subheading: level = 3; break;
  753. case CM_appendixsubsec: level = 3; break;
  754. case CM_subsubsection: level = 4; break;
  755. case CM_unnumberedsubsubsec: level = 4; break;
  756. case CM_subsubheading: level = 4; break;
  757. case CM_appendixsubsubsec: level = 4; break;
  758. case CM_part: level = 0; break;
  759. case CM_appendixsection: level = 2; break;
  760. case CM_majorheading: level = 1; break;
  761. case CM_centerchap: level = 1; break;
  762. default: level = -1; break;
  763. }
  764. return level;
  765. /* then adjust according to raise-/lowersections. */
  766. }
  767. /* TODO: Allow user to change which formats are true. */
  768. struct expanded_format {
  769. char *format;
  770. int expandedp;
  771. };
  772. static struct expanded_format expanded_formats[] = {
  773. "html", 0,
  774. "docbook", 0,
  775. "plaintext", 1,
  776. "tex", 0,
  777. "xml", 0,
  778. "info", 1,
  779. };
  780. void
  781. clear_expanded_formats (void)
  782. {
  783. int i;
  784. for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
  785. i++)
  786. {
  787. expanded_formats[i].expandedp = 0;
  788. }
  789. }
  790. void
  791. add_expanded_format (char *format)
  792. {
  793. int i;
  794. for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
  795. i++)
  796. {
  797. if (!strcmp (format, expanded_formats[i].format))
  798. {
  799. expanded_formats[i].expandedp = 1;
  800. break;
  801. }
  802. }
  803. if (!strcmp (format, "plaintext"))
  804. add_expanded_format ("info");
  805. }
  806. int
  807. format_expanded_p (char *format)
  808. {
  809. int i;
  810. for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
  811. i++)
  812. {
  813. if (!strcmp (format, expanded_formats[i].format))
  814. return expanded_formats[i].expandedp;
  815. }
  816. return 0;
  817. }
  818. /* line 4632 */
  819. /* A command name has been read that starts a multiline block, which should
  820. end in @end <command name>. The block will be processed until
  821. "end_line_misc_line" in end_line.c processes the @end command. */
  822. ELEMENT *
  823. handle_block_command (ELEMENT *current, char **line_inout,
  824. enum command_id cmd, int *get_new_line,
  825. enum command_id invalid_parent)
  826. {
  827. char *line = *line_inout;
  828. unsigned long flags = command_data(cmd).flags;
  829. /* New macro being defined. */
  830. if (cmd == CM_macro || cmd == CM_rmacro)
  831. {
  832. ELEMENT *macro;
  833. macro = parse_macro_command_line (cmd, &line, current);
  834. add_to_element_contents (current, macro);
  835. mark_and_warn_invalid (cmd, invalid_parent,
  836. last_contents_child(current));
  837. current = macro;
  838. /* 4640 */
  839. /* A new line should be read immediately after this. */
  840. line = strchr (line, '\0');
  841. *get_new_line = 1;
  842. goto funexit;
  843. }
  844. else if (command_data(cmd).data == BLOCK_conditional) //4641
  845. {
  846. int iftrue = 0; /* Whether the conditional is true. */
  847. if (cmd == CM_ifclear || cmd == CM_ifset
  848. || cmd == CM_ifcommanddefined || cmd == CM_ifcommandnotdefined)
  849. {
  850. char *flag;
  851. char *p = line;
  852. p = line + strspn (line, whitespace_chars);
  853. if (!*p)
  854. line_error ("@%s requires a name", command_name(cmd));
  855. else
  856. {
  857. flag = read_command_name (&p);
  858. if (!flag)
  859. goto bad_value;
  860. else
  861. {
  862. p += strspn (p, whitespace_chars);
  863. /* Check for a comment at the end of the line. */
  864. if (memcmp (p, "@c", 2) == 0)
  865. {
  866. p += 2;
  867. if (memcmp (p, "omment", 6) == 0)
  868. p += 7;
  869. if (*p && *p != '@' && !strchr (whitespace_chars, *p))
  870. goto bad_value; /* @c or @comment not terminated. */
  871. }
  872. else if (*p)
  873. goto bad_value; /* Trailing characters on line. */
  874. }
  875. if (1)
  876. {
  877. // 4652
  878. if (cmd == CM_ifclear || cmd == CM_ifset)
  879. {
  880. char *val = fetch_value (flag, strlen (flag));
  881. if (val)
  882. iftrue = 1;
  883. if (cmd == CM_ifclear)
  884. iftrue = !iftrue;
  885. }
  886. else /* cmd == CM_ifcommanddefined
  887. || cmd == CM_ifcommandnotdefined */
  888. {
  889. enum command_id c = lookup_command (flag);
  890. if (c)
  891. iftrue = 1;
  892. if (cmd == CM_ifcommandnotdefined)
  893. iftrue = !iftrue;
  894. }
  895. }
  896. else if (0)
  897. {
  898. bad_value:
  899. line_error ("bad name for @%s", command_name(cmd));
  900. }
  901. }
  902. }
  903. else if (!memcmp (command_name(cmd), "if", 2)) //4687
  904. {
  905. int i; char *p;
  906. /* Handle @if* and @ifnot* */
  907. /* FIXME: Check @if and @ifnot* a nicer way, without memcmp. */
  908. p = command_name(cmd) + 2; /* After "if". */
  909. if (!memcmp (p, "not", 3))
  910. p += 3; /* After "not". */
  911. for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
  912. i++)
  913. {
  914. if (!strcmp (p, expanded_formats[i].format))
  915. {
  916. iftrue = expanded_formats[i].expandedp;
  917. break;
  918. }
  919. }
  920. if (!memcmp (command_name(cmd), "ifnot", 5))
  921. iftrue = !iftrue;
  922. }
  923. else
  924. abort (); // BUG
  925. // 4699 - If conditional true, push onto conditional stack. Otherwise
  926. // open a new element (which we shall later remove, in
  927. // process_remaining_on_line ("CLOSED conditional").
  928. debug ("CONDITIONAL %s %d", command_name(cmd), iftrue);
  929. if (iftrue)
  930. push_conditional_stack (cmd);
  931. else
  932. {
  933. // Ignored.
  934. ELEMENT *e;
  935. e = new_element (ET_NONE);
  936. e->cmd = cmd;
  937. add_to_element_contents (current, e);
  938. current = e;
  939. }
  940. // 4709 ("last;")
  941. line = strchr (line, '\0');
  942. *get_new_line = 1;
  943. goto funexit;
  944. }
  945. else /* line 4710 */
  946. {
  947. ELEMENT *block = 0;
  948. // 4715
  949. if (flags & CF_menu
  950. && (current->type == ET_menu_comment
  951. || current->type == ET_menu_entry_description))
  952. {
  953. /* This is for @detailmenu within @menu */
  954. ELEMENT *menu = current->parent;
  955. if (current->contents.number == 0)
  956. destroy_element (pop_element_from_contents (menu));
  957. if (pop_context () != ct_preformatted)
  958. abort ();
  959. if (menu->type == ET_menu_entry)
  960. menu = menu->parent;
  961. current = menu;
  962. }
  963. // 4740
  964. if (flags & CF_def)
  965. {
  966. ELEMENT *def_line;
  967. push_context (ct_def);
  968. block = new_element (ET_NONE);
  969. block->cmd = cmd;
  970. block->line_nr = line_nr;
  971. add_to_element_contents (current, block);
  972. current = block;
  973. def_line = new_element (ET_def_line);
  974. def_line->line_nr = line_nr;
  975. add_to_element_contents (current, def_line);
  976. current = def_line;
  977. add_extra_string (current, "def_command", command_name(cmd));
  978. add_extra_string (current, "original_def_cmdname",
  979. command_name(cmd));
  980. }
  981. else
  982. {
  983. /* line 4756 */
  984. block = new_element (ET_NONE);
  985. block->cmd = cmd;
  986. add_to_element_contents (current, block);
  987. current = block;
  988. }
  989. /* 4763 Check if 'block args command' */
  990. if (command_data(cmd).data != BLOCK_raw)
  991. {
  992. if (command_data(cmd).flags & CF_preformatted)
  993. push_context (ct_preformatted);
  994. else if (command_data(cmd).flags & CF_format_raw)
  995. {
  996. push_context (ct_rawpreformatted);
  997. if (!format_expanded_p (command_name(cmd)))
  998. {
  999. ELEMENT *e;
  1000. enum command_id dummy;
  1001. char *line_dummy;
  1002. e = new_element (ET_elided_block);
  1003. add_to_element_contents (current, e);
  1004. line_dummy = line;
  1005. while (!is_end_current_command (current,
  1006. &line_dummy, &dummy))
  1007. {
  1008. line = new_line ();
  1009. if (!line)
  1010. abort (); // TODO
  1011. line_dummy = line;
  1012. }
  1013. e = new_element (ET_empty_line_after_command);
  1014. text_append_n (&e->text, "\n", 1);
  1015. add_to_element_contents (current, e);
  1016. e = new_element (ET_empty_line);
  1017. add_to_element_contents (current, e);
  1018. goto funexit;
  1019. }
  1020. }
  1021. // 4775
  1022. if (command_data(cmd).flags & CF_region)
  1023. {
  1024. if (current_region_cmd ())
  1025. {
  1026. line_error ("region %s inside region %s is not allowed",
  1027. command_name(cmd),
  1028. command_name(current_region_cmd ()));
  1029. }
  1030. push_region (block);
  1031. }
  1032. // 4784 menu commands
  1033. if (command_data(cmd).flags & CF_menu)
  1034. {
  1035. if (current_context () == ct_preformatted)
  1036. push_context (ct_preformatted);
  1037. else
  1038. push_context (ct_menu);
  1039. // Record dir entry here
  1040. if (current_node) // 4793
  1041. {
  1042. if (cmd == CM_direntry && conf.show_menu)
  1043. {
  1044. line_warn ("@direntry after first node");
  1045. }
  1046. else if (cmd == CM_menu)
  1047. {
  1048. if (!(command_flags(current->parent) & CF_root))
  1049. line_warn ("@menu in invalid context");
  1050. /* Add to array of menus for current node. Currently
  1051. done in Perl code. */
  1052. }
  1053. }
  1054. else if (cmd != CM_direntry)
  1055. {
  1056. if (conf.show_menu)
  1057. {
  1058. line_error ("@%s seen before first @node",
  1059. command_name(cmd));
  1060. line_error ("perhaps your @top node should be "
  1061. "wrapped in @ifnottex rather than @ifinfo?");
  1062. }
  1063. // 4810 unassociated menus
  1064. }
  1065. }
  1066. if (cmd == CM_itemize || cmd == CM_enumerate)
  1067. counter_push (&count_items, current, 0);
  1068. /* Note that no equivalent thing is done in the Perl code, because
  1069. 'item_count' is assumed to start at 0. */
  1070. // 4816
  1071. {
  1072. ELEMENT *bla = new_element (ET_block_line_arg);
  1073. add_to_element_args (current, bla);
  1074. if (command_data (current->cmd).data > 1)
  1075. {
  1076. counter_push (&count_remaining_args,
  1077. current,
  1078. command_data (current->cmd).data - 1);
  1079. }
  1080. current = bla;
  1081. if (!(command_data(cmd).flags & CF_def))
  1082. push_context (ct_line);
  1083. /* Note that an ET_empty_line_after_command gets reparented in the
  1084. contents in 'end_line'. */
  1085. }
  1086. } /* 4827 */
  1087. block->line_nr = line_nr;
  1088. mark_and_warn_invalid (cmd, invalid_parent, block);
  1089. register_global_command (cmd, block);
  1090. start_empty_line_after_command (current, &line, block);
  1091. }
  1092. funexit:
  1093. *line_inout = line;
  1094. return current;
  1095. }
  1096. /* 4835 */
  1097. ELEMENT *
  1098. handle_brace_command (ELEMENT *current, char **line_inout,
  1099. enum command_id cmd,
  1100. enum command_id invalid_parent)
  1101. {
  1102. char *line = *line_inout;
  1103. ELEMENT *e;
  1104. e = new_element (ET_NONE);
  1105. e->cmd = cmd;
  1106. // 4841
  1107. // 258 keep_line_nr_brace_commands
  1108. // also 4989 sets line_nr.
  1109. /* The line number information is only ever used for brace commands
  1110. if the command is given with braces, but it's easier just to always
  1111. store the information. */
  1112. e->line_nr = line_nr;
  1113. add_to_element_contents (current, e);
  1114. current = e;
  1115. mark_and_warn_invalid (cmd, invalid_parent, e);
  1116. if (cmd == CM_click)
  1117. {
  1118. add_extra_string (e, "clickstyle", global_clickstyle);
  1119. }
  1120. else if (cmd == CM_kbd)
  1121. {
  1122. if (current_context () == ct_preformatted
  1123. && global_kbdinputstyle != kbd_distinct
  1124. || global_kbdinputstyle == kbd_code)
  1125. {
  1126. add_extra_string (e, "code", "1");
  1127. }
  1128. else if (global_kbdinputstyle == kbd_example)
  1129. {
  1130. // _in_code line 1277
  1131. // TODO: Understand what is going on here.
  1132. ELEMENT *tmp = current->parent;
  1133. while (tmp->parent
  1134. && (command_flags(tmp->parent) & CF_brace)
  1135. && command_data(tmp->parent->cmd).data != BRACE_context)
  1136. {
  1137. if (command_flags(tmp->parent) & CF_code_style)
  1138. {
  1139. add_extra_string (e, "code", "1");
  1140. break;
  1141. }
  1142. tmp = tmp->parent->parent;
  1143. }
  1144. }
  1145. }
  1146. else if (command_data(cmd).flags & CF_INFOENCLOSE)
  1147. {
  1148. INFO_ENCLOSE *ie = lookup_infoenclose (cmd);
  1149. if (ie)
  1150. {
  1151. add_extra_string (e, "begin", ie->begin);
  1152. add_extra_string (e, "end", ie->end);
  1153. }
  1154. e->type = ET_definfoenclose_command;
  1155. }
  1156. *line_inout = line;
  1157. return current;
  1158. }