macro.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. /* Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016
  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. #define _GNU_SOURCE
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include "parser.h"
  17. #include "tree.h"
  18. #include "text.h"
  19. #include "input.h"
  20. #include "errors.h"
  21. #include "convert.h"
  22. static MACRO *macro_list;
  23. static size_t macro_number;
  24. static size_t macro_space;
  25. /* Macro definition. */
  26. void
  27. new_macro (char *name, ELEMENT *macro)
  28. {
  29. enum command_id new;
  30. MACRO *m = 0;
  31. ELEMENT tmp;
  32. /* Check for an existing definition first for us to overwrite. */
  33. new = lookup_command (name);
  34. if (new)
  35. m = lookup_macro (new);
  36. if (!m)
  37. {
  38. if (macro_number == macro_space)
  39. {
  40. macro_list = realloc (macro_list,
  41. (macro_space += 5) * sizeof (MACRO));
  42. if (!macro_list)
  43. abort ();
  44. }
  45. new = add_texinfo_command (name);
  46. m = &macro_list[macro_number];
  47. m->cmd = new;
  48. macro_number++;
  49. new &= ~USER_COMMAND_BIT;
  50. user_defined_command_data[new].flags |= CF_MACRO;
  51. }
  52. m->macro_name = strdup (name);
  53. m->element = macro;
  54. memset (&tmp, 0, sizeof (ELEMENT));
  55. tmp.contents = macro->contents;
  56. m->macrobody = convert_to_texinfo (&tmp);
  57. }
  58. // 1088
  59. /* CMD will be either CM_macro or CM_rmacro. Read the line defining a macro's
  60. name and the arguments it takes, and return this information in a new
  61. ELEMENT. */
  62. ELEMENT *
  63. parse_macro_command_line (enum command_id cmd, char **line_inout,
  64. ELEMENT *parent)
  65. {
  66. char *line = *line_inout;
  67. ELEMENT *macro, *macro_name;
  68. char *name, *args_ptr;
  69. int index;
  70. macro = new_element (ET_NONE);
  71. macro->cmd = cmd;
  72. macro->line_nr = line_nr;
  73. add_extra_string (macro, "arg_line", strdup (line));
  74. /* FIXME: This extra value isn't used much, so is a candidate for
  75. simplification. */
  76. line += strspn (line, whitespace_chars);
  77. name = read_command_name (&line);
  78. if (*line && *line != '{' && !strchr (whitespace_chars, *line))
  79. {
  80. line_error ("bad name for @%s", command_name (cmd));
  81. add_extra_string (macro, "invalid_syntax", "1");
  82. return macro;
  83. }
  84. else if (!name)
  85. {
  86. line_error ("@%s requires a name", command_name (cmd));
  87. add_extra_string (macro, "invalid_syntax", "1");
  88. return macro;
  89. }
  90. macro_name = new_element (ET_macro_name);
  91. text_append (&macro_name->text, name);
  92. free (name);
  93. add_to_element_args (macro, macro_name);
  94. args_ptr = line;
  95. args_ptr += strspn (args_ptr, whitespace_chars);
  96. if (*args_ptr != '{')
  97. {
  98. /* Either error or no args. */
  99. goto check_trailing;
  100. }
  101. args_ptr++;
  102. index = 0;
  103. while (1)
  104. {
  105. /* args_ptr is after a '{' or ','. INDEX holds the number of
  106. the macro argument */
  107. char *q, *q2;
  108. ELEMENT *arg;
  109. args_ptr += strspn (args_ptr, whitespace_chars);
  110. /* Find end of current argument. */
  111. q = args_ptr;
  112. while (*q != '\0' && *q != ',' && *q != '}')
  113. q++;
  114. if (!*q)
  115. {
  116. /* End of string reached before closing brace. */
  117. abort ();
  118. }
  119. /* Disregard trailing whitespace. */
  120. q2 = q;
  121. while (q2 > args_ptr && strchr (whitespace_chars, q2[-1]))
  122. q2--;
  123. if (q2 == args_ptr)
  124. {
  125. // 1126 - argument is completely whitespace
  126. if (*q == ',')
  127. {
  128. line_error ("bad or empty @%s formal argument: ",
  129. command_name(cmd));
  130. arg = new_element (ET_macro_arg);
  131. add_to_element_args (macro, arg);
  132. text_append_n (&arg->text, "", 0);
  133. add_extra_string (macro, "invalid_syntax", "1");
  134. }
  135. }
  136. else
  137. {
  138. arg = new_element (ET_macro_arg);
  139. text_append_n (&arg->text, args_ptr, q2 - args_ptr);
  140. add_to_element_args (macro, arg);
  141. /* Check the argument name. */
  142. {
  143. char *p;
  144. for (p = args_ptr; p < q2; p++)
  145. {
  146. if (!isalnum (*p) && *p != '_' && *p != '-')
  147. {
  148. char c = *q2; *q2 = 0;
  149. line_error ("bad or empty @%s formal argument: %s",
  150. command_name(cmd), args_ptr);
  151. *q2 = c;
  152. add_extra_string (macro, "invalid_syntax", "1");
  153. break;
  154. }
  155. }
  156. }
  157. }
  158. args_ptr = q + 1;
  159. if (*q == '}')
  160. break;
  161. index++;
  162. }
  163. check_trailing:
  164. line = args_ptr;
  165. line += strspn (line, whitespace_chars);
  166. if (*line && *line != '@')
  167. {
  168. line_error ("bad syntax for @%s argument: %s",
  169. command_name(cmd), line);
  170. add_extra_string (macro, "invalid_syntax", "1");
  171. }
  172. //line += strlen (line); /* Discard rest of line. */
  173. funexit:
  174. *line_inout = line;
  175. return macro;
  176. }
  177. /* Macro use. */
  178. /* Return index into given arguments to look for the value of NAME.
  179. Return -1 if not found. */
  180. int
  181. lookup_macro_parameter (char *name, ELEMENT *macro)
  182. {
  183. int i, pos;
  184. ELEMENT **args;
  185. /* Find 'arg' in MACRO parameters. */
  186. args = macro->args.list;
  187. pos = 0;
  188. for (i = 0; i < macro->args.number; i++)
  189. {
  190. if (args[i]->type == ET_macro_arg)
  191. {
  192. if (!strcmp (args[i]->text.text, name))
  193. return pos;
  194. pos++;
  195. }
  196. }
  197. return -1;
  198. }
  199. /* LINE points to after the opening brace in a macro invocation. CMD is the
  200. command identifier of the macro command. Return array of the arguments.
  201. Return value to be freed by caller. */
  202. // 1984
  203. char **
  204. expand_macro_arguments (ELEMENT *macro, char **line_inout, enum command_id cmd)
  205. {
  206. char *line = *line_inout;
  207. char *pline = line;
  208. TEXT arg;
  209. int braces_level = 1;
  210. int args_total;
  211. char **arg_list = 0;
  212. size_t arg_number = 0;
  213. size_t arg_space = 0;
  214. arg_list = malloc (sizeof (char *));
  215. args_total = macro->args.number - 1;
  216. text_init (&arg);
  217. while (braces_level > 0)
  218. {
  219. /* At the beginning of this loop pline is at the start
  220. of an argument. */
  221. char *sep;
  222. sep = pline + strcspn (pline, "\\,{}");
  223. if (!*sep)
  224. {
  225. debug ("MACRO ARG end of line");
  226. text_append (&arg, pline);
  227. line = new_line ();
  228. if (!line)
  229. {
  230. line_error ("@%s missing closing brace", command_name(cmd));
  231. line = "\n";
  232. goto funexit;
  233. }
  234. pline = line;
  235. continue;
  236. }
  237. text_append_n (&arg, pline, sep - pline);
  238. // 2002
  239. switch (*sep)
  240. {
  241. case '\\':
  242. if (!strchr ("\\{},", sep[1]))
  243. text_append_n (&arg, sep, 1);
  244. if (sep[1])
  245. {
  246. text_append_n (&arg, &sep[1], 1);
  247. pline = sep + 2;
  248. }
  249. else
  250. pline = sep + 1;
  251. break;
  252. case '{':
  253. braces_level++;
  254. text_append_n (&arg, sep, 1);
  255. pline = sep + 1;
  256. break;
  257. case '}':
  258. braces_level--;
  259. if (braces_level > 0)
  260. {
  261. text_append_n (&arg, sep, 1);
  262. pline = sep + 1;
  263. break;
  264. }
  265. /* Fall through to add argument. */
  266. case ',':
  267. if (braces_level > 1)
  268. {
  269. text_append_n (&arg, sep, 1);
  270. pline = sep + 1;
  271. break;
  272. }
  273. // 2021 check for too many args
  274. if (*sep == '}' || arg_number < args_total - 1)
  275. {
  276. /* Add the last argument read to the list. */
  277. if (arg_number == arg_space)
  278. {
  279. arg_list = realloc (arg_list,
  280. (1+(arg_space += 5)) * sizeof (char *));
  281. /* Include space for terminating null element. */
  282. if (!arg_list)
  283. abort ();
  284. }
  285. if (arg.space > 0)
  286. arg_list[arg_number++] = arg.text;
  287. else
  288. arg_list[arg_number++] = strdup ("");
  289. text_init (&arg);
  290. // TODO: is "@m { }" one empty argument or none?
  291. debug ("MACRO NEW ARG");
  292. pline = sep + 1;
  293. if (*sep == ',')
  294. pline += strspn (pline, whitespace_chars);
  295. }
  296. else
  297. {
  298. if (args_total != 1)
  299. line_error ("macro `%s' called with too many args",
  300. command_name(cmd));
  301. text_append_n (&arg, ",", 1);
  302. pline = sep + 1;
  303. }
  304. break;
  305. }
  306. }
  307. debug ("END MACRO ARGS EXPANSION");
  308. line = pline;
  309. funexit:
  310. *line_inout = line;
  311. arg_list[arg_number] = 0;
  312. return arg_list;
  313. }
  314. // 2063
  315. /* ARGUMENTS are the arguments used in the macro invocation. EXPANDED gets the
  316. result of the expansion. */
  317. static void
  318. expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
  319. {
  320. char *arg;
  321. int pos; /* Index into arguments. */
  322. int i; /* Index into macro contents. */
  323. ELEMENT *macro;
  324. char *macrobody;
  325. char *ptext;
  326. macro = macro_record->element;
  327. macrobody = macro_record->macrobody;
  328. /* Initialize TEXT object. */
  329. expanded->end = 0;
  330. if (!macrobody)
  331. return;
  332. ptext = macrobody;
  333. while (1)
  334. {
  335. /* At the start of this loop ptext is at the beginning or
  336. just after the last backslash sequence. */
  337. char *bs; /* Pointer to next backslash. */
  338. bs = strchrnul (ptext, '\\');
  339. text_append_n (expanded, ptext, bs - ptext);
  340. if (!*bs)
  341. break; /* End of line. */
  342. ptext = bs + 1;
  343. if (*ptext == '\\')
  344. {
  345. text_append_n (expanded, "\\", 1); /* Escaped backslash (\\). */
  346. ptext++;
  347. }
  348. else
  349. {
  350. bs = strchr (ptext, '\\');
  351. if (!bs)
  352. {
  353. // error - malformed
  354. return;
  355. abort ();
  356. }
  357. *bs = '\0';
  358. pos = lookup_macro_parameter (ptext, macro);
  359. if (pos == -1)
  360. {
  361. line_error ("\\ in @%s expansion followed `%s' instead of "
  362. "parameter name or \\",
  363. macro->args.list[0]->text.text,
  364. ptext);
  365. text_append (expanded, "\\");
  366. text_append (expanded, ptext);
  367. }
  368. else
  369. {
  370. if (arguments && arguments[pos])
  371. text_append (expanded, arguments[pos]);
  372. }
  373. *bs = '\\';
  374. ptext = bs + 1;
  375. }
  376. }
  377. }
  378. MACRO *
  379. lookup_macro (enum command_id cmd)
  380. {
  381. int i;
  382. for (i = 0; i < macro_number; i++)
  383. {
  384. if (macro_list[i].cmd == cmd)
  385. return &macro_list[i];
  386. }
  387. return 0;
  388. }
  389. void
  390. delete_macro (char *name)
  391. {
  392. enum command_id cmd;
  393. MACRO *m;
  394. cmd = lookup_command (name);
  395. if (!cmd)
  396. return;
  397. m = lookup_macro (cmd);
  398. if (!m)
  399. return;
  400. m->cmd = 0;
  401. m->macro_name = "";
  402. m->element = 0;
  403. remove_texinfo_command (cmd);
  404. }
  405. void
  406. wipe_macros (void)
  407. {
  408. macro_number = 0;
  409. }
  410. // 3898
  411. /* CMD is the macro command. */
  412. ELEMENT *
  413. handle_macro (ELEMENT *current, char **line_inout, enum command_id cmd)
  414. {
  415. char *line, *p;
  416. MACRO *macro_record;
  417. ELEMENT *macro;
  418. TEXT expanded;
  419. char **arguments = 0;
  420. int args_number;
  421. line = *line_inout;
  422. text_init (&expanded);
  423. macro_record = lookup_macro (cmd);
  424. if (!macro_record)
  425. abort ();
  426. macro = macro_record->element;
  427. // 3907 Get number of args. - 1 for the macro name.
  428. args_number = macro->args.number - 1;
  429. p = line + strspn (line, whitespace_chars);
  430. if (*p == '{')
  431. {
  432. line = p;
  433. line++;
  434. /* In the Perl version formfeed is excluded for some reason. */
  435. line += strspn (line, whitespace_chars);
  436. arguments = expand_macro_arguments (macro, &line, cmd);
  437. }
  438. /* Warning depending on the number of arguments this macro
  439. is supposed to take. */
  440. else if (args_number != 1)
  441. {
  442. if (args_number > 1)
  443. line_warn ("@%s defined with zero or more than one argument should "
  444. "be invoked with {}", command_name(cmd));
  445. /* As agreed on the bug-texinfo mailing list, no warn when zero
  446. arg and not called with {}. */
  447. }
  448. else
  449. {
  450. char *p;
  451. /* If it takes a single line of input, and we don't have a full line of
  452. input already, call new_line. */
  453. if (!strchr (line, '\n'))
  454. {
  455. line = new_line ();
  456. if (!line)
  457. line = "";
  458. }
  459. line += strspn (line, whitespace_chars);
  460. arguments = malloc (sizeof (char *) * 2);
  461. arguments[0] = strdup (line);
  462. arguments[1] = 0;
  463. p = strchr (arguments[0], '\n');
  464. if (p)
  465. {
  466. *p = '\0';
  467. line = "\n";
  468. }
  469. }
  470. expand_macro_body (macro_record, arguments, &expanded);
  471. debug ("MACROBODY: %s||||||", expanded.text);
  472. if (expanded.end > 0 && expanded.text[expanded.end - 1] == '\n')
  473. expanded.text[--expanded.end] = '\0';
  474. if (input_number >= 1000)
  475. {
  476. line_warn (
  477. "macro call nested too deeply "
  478. "(set MAX_NESTED_MACROS to override; current value %d)", 1000);
  479. goto funexit;
  480. }
  481. if (macro->cmd == CM_macro)
  482. {
  483. if (expanding_macro (command_name(cmd)))
  484. {
  485. line_error ("recursive call of macro %s is not allowed; "
  486. "use @rmacro if needed", command_name(cmd));
  487. goto funexit;
  488. }
  489. }
  490. /* Free arguments. */
  491. if (arguments)
  492. {
  493. char **s = arguments;
  494. while (*s)
  495. {
  496. free (*s);
  497. s++;
  498. }
  499. free (arguments);
  500. }
  501. // 3958 Pop macro stack
  502. // 3961
  503. /* Put expansion in front of the current line. */
  504. input_push_text (strdup (line), 0);
  505. line = strchr (line, '\0');
  506. input_push_text (expanded.text, command_name(cmd));
  507. funexit:
  508. *line_inout = line;
  509. return current;
  510. }
  511. /* @set and @value */
  512. typedef struct {
  513. char *name;
  514. char *value;
  515. } VALUE;
  516. static VALUE *value_list;
  517. static size_t value_number;
  518. static size_t value_space;
  519. void
  520. wipe_values (void)
  521. {
  522. size_t i;
  523. for (i = 0; i < value_number; i++)
  524. {
  525. free (value_list[i].name);
  526. free (value_list[i].value);
  527. }
  528. value_number = 0;
  529. }
  530. void
  531. store_value (char *name, char *value)
  532. {
  533. int i;
  534. VALUE *v = 0;
  535. int len;
  536. len = strlen (name);
  537. /* Check if already defined. */
  538. for (i = 0; i < value_number; i++)
  539. {
  540. if (!memcmp (value_list[i].name, name, len) && !value_list[i].name[len])
  541. {
  542. v = &value_list[i];
  543. free (v->name); free (v->value);
  544. break;
  545. }
  546. }
  547. if (!v)
  548. {
  549. if (value_number == value_space)
  550. {
  551. value_list = realloc (value_list, (value_space += 5) * sizeof (VALUE));
  552. }
  553. v = &value_list[value_number++];
  554. }
  555. v->name = strdup (name);
  556. v->value = strdup (value);
  557. }
  558. void
  559. clear_value (char *name, int len)
  560. {
  561. int i;
  562. for (i = 0; i < value_number; i++)
  563. {
  564. if (!memcmp (value_list[i].name, name, len) && !value_list[i].name[len])
  565. {
  566. value_list[i].name[0] = '\0';
  567. value_list[i].value[0] = '\0';
  568. }
  569. }
  570. }
  571. char *
  572. fetch_value (char *name, int len)
  573. {
  574. int i;
  575. for (i = 0; i < value_number; i++)
  576. {
  577. if (!memcmp (value_list[i].name, name, len) && !value_list[i].name[len])
  578. return value_list[i].value;
  579. }
  580. if (!strcmp (name, "txicommandconditionals"))
  581. return "1";
  582. return 0;
  583. }
  584. static INFO_ENCLOSE *infoencl_list;
  585. static size_t infoencl_number;
  586. static size_t infoencl_space;
  587. INFO_ENCLOSE *
  588. lookup_infoenclose (enum command_id cmd)
  589. {
  590. int i;
  591. for (i = 0; i < infoencl_number; i++)
  592. {
  593. if (infoencl_list[i].cmd == cmd)
  594. return &infoencl_list[i];
  595. }
  596. return 0;
  597. }
  598. void
  599. add_infoenclose (enum command_id cmd, char *begin, char *end)
  600. {
  601. int i;
  602. INFO_ENCLOSE *ie = 0;
  603. /* Check if already defined. */
  604. for (i = 0; i < infoencl_number; i++)
  605. {
  606. if (infoencl_list[i].cmd == cmd)
  607. {
  608. ie = &infoencl_list[i];
  609. free (ie->begin);
  610. free (ie->end);
  611. break;
  612. }
  613. }
  614. if (!ie)
  615. {
  616. if (infoencl_number == infoencl_space)
  617. {
  618. infoencl_list = realloc (infoencl_list,
  619. (infoencl_space += 5)
  620. * sizeof (INFO_ENCLOSE));
  621. }
  622. ie = &infoencl_list[infoencl_number++];
  623. }
  624. ie->cmd = cmd;
  625. ie->begin = strdup (begin);
  626. ie->end = strdup (end);
  627. }