PageRenderTime 60ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/src/wml_backend/p2_mp4h/src/builtin.c

https://bitbucket.org/shlomif/website-meta-language
C | 5049 lines | 3787 code | 642 blank | 620 comment | 918 complexity | 5d8c9d6158cf1d6e7a702cb8ec102c2a MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /* mp4h -- A macro processor for HTML documents
  2. Copyright 2000-2002, Denis Barbier
  3. All rights reserved.
  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 2, or (at your option)
  7. any later version.
  8. This program is a work based on GNU m4 version 1.4n. Below is the
  9. original copyright.
  10. */
  11. /* GNU m4 -- A simple macro processor
  12. Copyright (C) 1989, 90, 91, 92, 93, 94, 98 Free Software Foundation, Inc.
  13. This program is free software; you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation; either version 2, or (at your option)
  16. any later version.
  17. This program is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU General Public License for more details.
  21. You should have received a copy of the GNU General Public License
  22. along with this program; if not, write to the Free Software
  23. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. */
  25. /* Code for all builtin macros, initialisation of symbol table, and
  26. expansion of user defined macros. */
  27. #define MP4H_MODULE
  28. #include "mp4h.h"
  29. #undef MP4H_MODULE
  30. #include "builtin.h"
  31. #define CHECK_SAFETY_LEVEL(sl) \
  32. if (safety_level > sl) \
  33. { \
  34. MP4HERROR ((warning_status, 0, \
  35. _("Warning:%s:%d: `<%s>' ignored due to -S flag"), \
  36. CURRENT_FILE_LINE, ARG (0))); \
  37. return; \
  38. }
  39. /* Initialisation of builtin and predefined macros. The table
  40. "builtin_tab" is both used for initialisation, and by the "builtin"
  41. builtin. */
  42. DECLARE (mp4h_bp___file__);
  43. DECLARE (mp4h_bp___line__);
  44. DECLARE (mp4h_bp___version__);
  45. DECLARE (mp4h_bp_lb);
  46. DECLARE (mp4h_bp_rb);
  47. DECLARE (mp4h_bp_dq);
  48. DECLARE (mp4h_bp_bs);
  49. DECLARE (mp4h_bp_timer);
  50. #ifdef HAVE_LOCALE_H
  51. DECLARE (mp4h_bp_mp4h_l10n);
  52. #endif
  53. DECLARE (mp4h_bp_mp4h_output_radix);
  54. #if !defined(HAVE_FILE_FUNCS) || !defined (HAVE_LOCALE_H) || !defined(WITH_MODULES)
  55. DECLARE (mp4h_bp_unsupported);
  56. #endif
  57. /* debug functions */
  58. DECLARE (mp4h_bp_debugmode);
  59. DECLARE (mp4h_bp_debugfile);
  60. DECLARE (mp4h_bp_function_def);
  61. DECLARE (mp4h_bp_debugging_off);
  62. DECLARE (mp4h_bp_debugging_on);
  63. /* file functions */
  64. #ifdef HAVE_FILE_FUNCS
  65. DECLARE (mp4h_bp_get_file_properties);
  66. DECLARE (mp4h_bp_directory_contents);
  67. DECLARE (mp4h_bp_file_exists);
  68. DECLARE (mp4h_bp_real_path);
  69. #endif /* HAVE_FILE_FUNCS */
  70. DECLARE (mp4h_bp_date);
  71. /* flow functions */
  72. DECLARE (mp4h_bp_group);
  73. DECLARE (mp4h_bp_compound);
  74. DECLARE (mp4h_bp_disjoin);
  75. DECLARE (mp4h_bp_noexpand);
  76. DECLARE (mp4h_bp_expand);
  77. DECLARE (mp4h_bp_if);
  78. DECLARE (mp4h_bp_ifeq);
  79. DECLARE (mp4h_bp_ifneq);
  80. DECLARE (mp4h_bp_when);
  81. DECLARE (mp4h_bp_while);
  82. DECLARE (mp4h_bp_foreach);
  83. DECLARE (mp4h_bp_var_case);
  84. DECLARE (mp4h_bp_break);
  85. DECLARE (mp4h_bp_return);
  86. DECLARE (mp4h_bp_warning);
  87. DECLARE (mp4h_bp_exit);
  88. DECLARE (mp4h_bp_at_end_of_file);
  89. /* macro functions */
  90. DECLARE (mp4h_bp_define_tag);
  91. DECLARE (mp4h_bp_provide_tag);
  92. DECLARE (mp4h_bp_let);
  93. DECLARE (mp4h_bp_undef);
  94. DECLARE (mp4h_bp_set_hook);
  95. DECLARE (mp4h_bp_get_hook);
  96. DECLARE (mp4h_bp_attributes_quote);
  97. DECLARE (mp4h_bp_attributes_remove);
  98. DECLARE (mp4h_bp_attributes_extract);
  99. DECLARE (mp4h_bp_define_entity);
  100. /* math functions */
  101. DECLARE (mp4h_bp_add);
  102. DECLARE (mp4h_bp_substract);
  103. DECLARE (mp4h_bp_multiply);
  104. DECLARE (mp4h_bp_divide);
  105. DECLARE (mp4h_bp_modulo);
  106. DECLARE (mp4h_bp_min);
  107. DECLARE (mp4h_bp_max);
  108. DECLARE (mp4h_bp_gt);
  109. DECLARE (mp4h_bp_lt);
  110. DECLARE (mp4h_bp_eq);
  111. DECLARE (mp4h_bp_neq);
  112. /* page functions */
  113. DECLARE (mp4h_bp_include);
  114. DECLARE (mp4h_bp___include);
  115. DECLARE (mp4h_bp_use);
  116. #ifdef WITH_MODULES
  117. DECLARE (mp4h_bp_load);
  118. #endif
  119. DECLARE (mp4h_bp_comment);
  120. DECLARE (mp4h_bp_set_eol_comment);
  121. DECLARE (mp4h_bp_set_quotes);
  122. DECLARE (mp4h_bp_dnl);
  123. DECLARE (mp4h_bp_frozen_dump);
  124. /* relational operators */
  125. DECLARE (mp4h_bp_not);
  126. DECLARE (mp4h_bp_and);
  127. DECLARE (mp4h_bp_or);
  128. /* string functions */
  129. DECLARE (mp4h_bp_downcase);
  130. DECLARE (mp4h_bp_upcase);
  131. DECLARE (mp4h_bp_capitalize);
  132. DECLARE (mp4h_bp_string_length);
  133. DECLARE (mp4h_bp_substring);
  134. DECLARE (mp4h_bp_string_eq);
  135. DECLARE (mp4h_bp_string_neq);
  136. DECLARE (mp4h_bp_string_compare);
  137. DECLARE (mp4h_bp_char_offsets);
  138. DECLARE (mp4h_bp_printf);
  139. /* regexp functions */
  140. DECLARE (mp4h_bp_subst_in_string);
  141. DECLARE (mp4h_bp_subst_in_var);
  142. DECLARE (mp4h_bp_match);
  143. /* variable functions */
  144. DECLARE (mp4h_bp_get_var);
  145. DECLARE (mp4h_bp_get_var_once);
  146. DECLARE (mp4h_bp_set_var_x);
  147. DECLARE (mp4h_bp_set_var);
  148. DECLARE (mp4h_bp_unset_var);
  149. DECLARE (mp4h_bp_preserve);
  150. DECLARE (mp4h_bp_restore);
  151. DECLARE (mp4h_bp_var_exists);
  152. DECLARE (mp4h_bp_increment);
  153. DECLARE (mp4h_bp_decrement);
  154. DECLARE (mp4h_bp_symbol_info);
  155. DECLARE (mp4h_bp_copy_var);
  156. DECLARE (mp4h_bp_defvar);
  157. /* array functions */
  158. DECLARE (mp4h_bp_array_size);
  159. DECLARE (mp4h_bp_array_add_unique);
  160. DECLARE (mp4h_bp_array_member);
  161. DECLARE (mp4h_bp_array_push);
  162. DECLARE (mp4h_bp_array_pop);
  163. DECLARE (mp4h_bp_array_topvalue);
  164. DECLARE (mp4h_bp_array_shift);
  165. DECLARE (mp4h_bp_array_concat);
  166. DECLARE (mp4h_bp_sort);
  167. /* diversion functions */
  168. DECLARE (mp4h_bp_divert);
  169. DECLARE (mp4h_bp_divnum);
  170. DECLARE (mp4h_bp_undivert);
  171. #undef DECLARE
  172. static builtin
  173. builtin_tab[] =
  174. {
  175. /* name container expand function
  176. attributes */
  177. { "__file__", FALSE, TRUE, mp4h_bp___file__ },
  178. { "__line__", FALSE, TRUE, mp4h_bp___line__ },
  179. { "__version__", FALSE, TRUE, mp4h_bp___version__ },
  180. { "lb", FALSE, TRUE, mp4h_bp_lb },
  181. { "rb", FALSE, TRUE, mp4h_bp_rb },
  182. { "dq", FALSE, TRUE, mp4h_bp_dq },
  183. { "bs", FALSE, TRUE, mp4h_bp_bs },
  184. { "timer", FALSE, TRUE, mp4h_bp_timer },
  185. #ifdef HAVE_LOCALE_H
  186. { "mp4h-l10n", FALSE, TRUE, mp4h_bp_mp4h_l10n },
  187. #else
  188. { "mp4h-l10n", FALSE, TRUE, mp4h_bp_unsupported },
  189. #endif
  190. { "mp4h-output-radix",FALSE, TRUE, mp4h_bp_mp4h_output_radix },
  191. { "date", FALSE, TRUE, mp4h_bp_date },
  192. /* debug functions */
  193. { "debugmode", FALSE, TRUE, mp4h_bp_debugmode },
  194. { "debugfile", FALSE, TRUE, mp4h_bp_debugfile },
  195. { "function-def", FALSE, TRUE, mp4h_bp_function_def },
  196. { "debugging-off", FALSE, TRUE, mp4h_bp_debugging_off },
  197. { "debugging-on", FALSE, TRUE, mp4h_bp_debugging_on },
  198. /* file functions */
  199. #ifdef HAVE_FILE_FUNCS
  200. { "get-file-properties", FALSE, TRUE, mp4h_bp_get_file_properties },
  201. { "directory-contents", FALSE, TRUE, mp4h_bp_directory_contents },
  202. { "file-exists", FALSE, TRUE, mp4h_bp_file_exists },
  203. { "real-path", FALSE, TRUE, mp4h_bp_real_path },
  204. #else
  205. { "get-file-properties", FALSE, TRUE, mp4h_bp_unsupported },
  206. { "directory-contents", FALSE, TRUE, mp4h_bp_unsupported },
  207. { "file-exists", FALSE, TRUE, mp4h_bp_unsupported },
  208. { "real-path", FALSE, TRUE, mp4h_bp_unsupported },
  209. #endif /* HAVE_FILE_FUNCS */
  210. /* flow functions */
  211. { "group", FALSE, TRUE, mp4h_bp_group },
  212. { "compound", TRUE, TRUE, mp4h_bp_compound },
  213. { "disjoin", FALSE, TRUE, mp4h_bp_disjoin },
  214. { "noexpand", FALSE, FALSE, mp4h_bp_noexpand },
  215. { "expand", FALSE, TRUE, mp4h_bp_expand },
  216. { "if", FALSE, FALSE, mp4h_bp_if },
  217. { "ifeq", FALSE, FALSE, mp4h_bp_ifeq },
  218. { "ifneq", FALSE, FALSE, mp4h_bp_ifneq },
  219. { "when", TRUE, TRUE, mp4h_bp_when },
  220. { "while", TRUE, FALSE, mp4h_bp_while },
  221. { "foreach", TRUE, TRUE, mp4h_bp_foreach },
  222. { "var-case", FALSE, FALSE, mp4h_bp_var_case },
  223. { "break", FALSE, TRUE, mp4h_bp_break },
  224. { "return", FALSE, TRUE, mp4h_bp_return },
  225. { "warning", FALSE, TRUE, mp4h_bp_warning },
  226. { "exit", FALSE, TRUE, mp4h_bp_exit },
  227. { "at-end-of-file", TRUE, TRUE, mp4h_bp_at_end_of_file },
  228. /* macro functions */
  229. { "define-tag", TRUE, TRUE, mp4h_bp_define_tag },
  230. { "provide-tag", TRUE, TRUE, mp4h_bp_provide_tag },
  231. { "let", FALSE, TRUE, mp4h_bp_let },
  232. { "undef", FALSE, TRUE, mp4h_bp_undef },
  233. { "set-hook", TRUE, TRUE, mp4h_bp_set_hook },
  234. { "get-hook", FALSE, TRUE, mp4h_bp_get_hook },
  235. { "attributes-quote", FALSE, TRUE, mp4h_bp_attributes_quote },
  236. { "attributes-remove", FALSE, TRUE, mp4h_bp_attributes_remove },
  237. { "attributes-extract", FALSE, TRUE, mp4h_bp_attributes_extract },
  238. { "define-entity", TRUE, TRUE, mp4h_bp_define_entity },
  239. /* numerical relational operators */
  240. { "gt", FALSE, TRUE, mp4h_bp_gt },
  241. { "lt", FALSE, TRUE, mp4h_bp_lt },
  242. { "eq", FALSE, TRUE, mp4h_bp_eq },
  243. { "neq", FALSE, TRUE, mp4h_bp_neq },
  244. /* math functions */
  245. { "add", FALSE, TRUE, mp4h_bp_add },
  246. { "substract", FALSE, TRUE, mp4h_bp_substract },
  247. { "multiply", FALSE, TRUE, mp4h_bp_multiply },
  248. { "divide", FALSE, TRUE, mp4h_bp_divide },
  249. { "modulo", FALSE, TRUE, mp4h_bp_modulo },
  250. { "min", FALSE, TRUE, mp4h_bp_min },
  251. { "max", FALSE, TRUE, mp4h_bp_max },
  252. /* page functions */
  253. { "include", FALSE, FALSE, mp4h_bp_include },
  254. { "__include", TRUE, TRUE, mp4h_bp___include },
  255. { "use", FALSE, TRUE, mp4h_bp_use },
  256. #ifdef WITH_MODULES
  257. { "load", FALSE, TRUE, mp4h_bp_load },
  258. #else
  259. { "load", FALSE, TRUE, mp4h_bp_unsupported },
  260. #endif
  261. { "comment", TRUE, TRUE, mp4h_bp_comment },
  262. { "set-eol-comment", FALSE, TRUE, mp4h_bp_set_eol_comment },
  263. { "set-quotes", FALSE, TRUE, mp4h_bp_set_quotes },
  264. { "dnl", FALSE, TRUE, mp4h_bp_dnl },
  265. { "frozen-dump", FALSE, TRUE, mp4h_bp_frozen_dump },
  266. /* relational operators */
  267. { "not", FALSE, TRUE, mp4h_bp_not },
  268. { "and", FALSE, TRUE, mp4h_bp_and },
  269. { "or", FALSE, TRUE, mp4h_bp_or },
  270. /* string functions */
  271. { "downcase", FALSE, TRUE, mp4h_bp_downcase },
  272. { "upcase", FALSE, TRUE, mp4h_bp_upcase },
  273. { "capitalize", FALSE, TRUE, mp4h_bp_capitalize },
  274. { "string-length", FALSE, TRUE, mp4h_bp_string_length },
  275. { "substring", FALSE, TRUE, mp4h_bp_substring },
  276. { "string-eq", FALSE, TRUE, mp4h_bp_string_eq },
  277. { "string-neq", FALSE, TRUE, mp4h_bp_string_neq },
  278. { "string-compare", FALSE, TRUE, mp4h_bp_string_compare },
  279. { "char-offsets", FALSE, TRUE, mp4h_bp_char_offsets },
  280. { "printf", FALSE, TRUE, mp4h_bp_printf },
  281. /* regexp functions */
  282. { "subst-in-string", FALSE, TRUE, mp4h_bp_subst_in_string },
  283. { "subst-in-var", FALSE, TRUE, mp4h_bp_subst_in_var },
  284. { "match", FALSE, TRUE, mp4h_bp_match },
  285. /* variable functions */
  286. { "get-var", FALSE, TRUE, mp4h_bp_get_var },
  287. { "get-var-once", FALSE, TRUE, mp4h_bp_get_var_once },
  288. { "set-var-x", TRUE, TRUE, mp4h_bp_set_var_x },
  289. { "set-var", FALSE, TRUE, mp4h_bp_set_var },
  290. { "set-var-verbatim", FALSE, FALSE, mp4h_bp_set_var },
  291. { "unset-var", FALSE, TRUE, mp4h_bp_unset_var },
  292. { "preserve", FALSE, TRUE, mp4h_bp_preserve },
  293. { "restore", FALSE, TRUE, mp4h_bp_restore },
  294. { "var-exists", FALSE, TRUE, mp4h_bp_var_exists },
  295. { "increment", FALSE, TRUE, mp4h_bp_increment },
  296. { "decrement", FALSE, TRUE, mp4h_bp_decrement },
  297. { "symbol-info", FALSE, TRUE, mp4h_bp_symbol_info },
  298. { "copy-var", FALSE, TRUE, mp4h_bp_copy_var },
  299. { "defvar", FALSE, TRUE, mp4h_bp_defvar },
  300. /* array functions */
  301. { "array-size", FALSE, TRUE, mp4h_bp_array_size },
  302. { "array-add-unique", FALSE, TRUE, mp4h_bp_array_add_unique },
  303. { "array-member", FALSE, TRUE, mp4h_bp_array_member },
  304. { "array-push", FALSE, TRUE, mp4h_bp_array_push },
  305. { "array-pop", FALSE, TRUE, mp4h_bp_array_pop },
  306. { "array-topvalue", FALSE, TRUE, mp4h_bp_array_topvalue },
  307. { "array-shift", FALSE, TRUE, mp4h_bp_array_shift },
  308. { "array-concat", FALSE, TRUE, mp4h_bp_array_concat },
  309. { "sort", FALSE, TRUE, mp4h_bp_sort },
  310. /* diversion functions */
  311. { "divert", FALSE, TRUE, mp4h_bp_divert },
  312. { "divnum", FALSE, TRUE, mp4h_bp_divnum },
  313. { "undivert", FALSE, TRUE, mp4h_bp_undivert },
  314. { 0, FALSE, FALSE, 0 },
  315. };
  316. /* Local functions */
  317. static void push_builtin_table __P ((builtin *));
  318. static void set_trace __P ((symbol *, const char *));
  319. static void generic_set_hook __P ((MP4H_BUILTIN_PROTO, boolean, int));
  320. static void math_relation __P ((MP4H_BUILTIN_PROTO, mathrel_type));
  321. static void mathop_functions __P ((MP4H_BUILTIN_PROTO, mathop_type));
  322. static void updowncase __P ((struct obstack *, int, token_data **, boolean));
  323. static void varstack_check __P ((void));
  324. static boolean safe_strtod __P ((const char *, const char *, double *));
  325. static boolean safe_strtol __P ((const char *, const char *, long int *));
  326. static void quote_name_value __P ((struct obstack *, char *));
  327. static void matching_attributes __P ((struct obstack *, int, token_data **, boolean, char *));
  328. static char * utf8char_skip __P ((char *, int));
  329. static int utf8char_strlen __P ((char *));
  330. static int encoding_strlen __P ((char *));
  331. static void substitute __P ((struct obstack *, const char *, const char *, int *));
  332. static void string_regexp __P ((struct obstack *, int, token_data **, int, const char *));
  333. static void subst_in_string __P ((struct obstack *, int, token_data **, int));
  334. static void generic_variable_lookup __P ((MP4H_BUILTIN_PROTO, boolean));
  335. static int array_size __P ((symbol *));
  336. static char *array_value __P ((symbol *, int, int *));
  337. static int array_member __P ((const char *, symbol *, boolean));
  338. static int sort_function __P ((const void *, const void *));
  339. static void logical_to_physical_paths __P ((char **));
  340. /* This symbol controls breakings of flow statements. */
  341. static symbol varbreak;
  342. /* Stack preserve/restore variables. */
  343. static var_stack *vs = NULL;
  344. /* Global variables needed by sort algorithms. */
  345. static boolean sort_caseless;
  346. static boolean sort_sortorder;
  347. static boolean sort_numeric;
  348. /* Localization */
  349. struct lconv *my_locale;
  350. /* Table of characters used by PCRE with non-C locales */
  351. static const unsigned char *re_tableptr = NULL;
  352. /* Timer */
  353. static struct tms elapsed_time;
  354. /* Pointer to a string containig the decimal point used
  355. with locales. */
  356. #ifdef HAVE_LOCALE_H
  357. static const char *decimal_point;
  358. #else
  359. #define decimal_point "."
  360. #endif
  361. /* Output radix */
  362. static int output_radix = 6;
  363. /*------------------------------------------------------------------.
  364. | If dynamic modules are enabled, more builtin tables can be active |
  365. | at a time. This implements a list of tables of builtins. |
  366. `------------------------------------------------------------------*/
  367. struct builtin_table
  368. {
  369. struct builtin_table *next;
  370. builtin *table;
  371. };
  372. typedef struct builtin_table builtin_table;
  373. static builtin_table *builtin_tables = NULL;
  374. static void
  375. push_builtin_table (builtin *table)
  376. {
  377. builtin_table *bt;
  378. bt = (builtin_table *) xmalloc (sizeof (struct builtin_table));
  379. bt->next = builtin_tables;
  380. bt->table = table;
  381. builtin_tables = bt;
  382. }
  383. /*----------------------------------------.
  384. | Find the builtin, which lives on ADDR. |
  385. `----------------------------------------*/
  386. const builtin *
  387. find_builtin_by_addr (builtin_func *func)
  388. {
  389. const builtin_table *bt;
  390. const builtin *bp;
  391. for (bt = builtin_tables; bt != NULL; bt = bt->next)
  392. for (bp = bt->table; bp->name != NULL; bp++)
  393. if (bp->func == func)
  394. return bp;
  395. return NULL;
  396. }
  397. /*-----------------------------------.
  398. | Find the builtin, which has NAME. |
  399. `-----------------------------------*/
  400. const builtin *
  401. find_builtin_by_name (const char *name)
  402. {
  403. const builtin_table *bt;
  404. const builtin *bp;
  405. /* This is necessary to load frozen files */
  406. if (builtin_tables == NULL)
  407. push_builtin_table (builtin_tab);
  408. for (bt = builtin_tables; bt != NULL; bt = bt->next)
  409. for (bp = bt->table; bp->name != NULL; bp++)
  410. if (strcasecmp (bp->name, name) == 0)
  411. return bp;
  412. return NULL;
  413. }
  414. /*-----------------------.
  415. | Initialize a symbol. |
  416. `-----------------------*/
  417. void
  418. initialize_builtin (symbol *sym)
  419. {
  420. SYMBOL_TYPE (sym) = TOKEN_VOID;
  421. SYMBOL_TRACED (sym) = FALSE;
  422. SYMBOL_CONTAINER (sym) = FALSE;
  423. SYMBOL_EXPAND_ARGS (sym) = FALSE;
  424. SYMBOL_HOOK_BEGIN (sym) = NULL;
  425. SYMBOL_HOOK_END (sym) = NULL;
  426. }
  427. /*-------------------------------------------------------------------------.
  428. | Install a builtin macro with name NAME, bound to the C function given in |
  429. | BP. TRACED defines whether NAME is to be traced. |
  430. `-------------------------------------------------------------------------*/
  431. void
  432. define_builtin (const char *name, const builtin *bp, boolean traced)
  433. {
  434. symbol *sym;
  435. sym = lookup_symbol (name, SYMBOL_INSERT);
  436. if (SYMBOL_TYPE (sym) == TOKEN_TEXT)
  437. xfree ((voidstar) SYMBOL_TEXT (sym));
  438. SYMBOL_TYPE (sym) = TOKEN_FUNC;
  439. SYMBOL_FUNC (sym) = bp->func;
  440. SYMBOL_TRACED (sym) = traced;
  441. SYMBOL_CONTAINER (sym) = bp->container;
  442. SYMBOL_EXPAND_ARGS (sym) = bp->expand_args;
  443. SYMBOL_HOOK_BEGIN (sym) = NULL;
  444. SYMBOL_HOOK_END (sym) = NULL;
  445. }
  446. /*------------------------------.
  447. | Install a new builtin_table. |
  448. `------------------------------*/
  449. void
  450. install_builtin_table (builtin *table)
  451. {
  452. const builtin *bp;
  453. push_builtin_table (table);
  454. for (bp = table; bp->name != NULL; bp++)
  455. define_builtin (bp->name, bp, FALSE);
  456. }
  457. void
  458. break_init (void) {
  459. initialize_builtin (&varbreak);
  460. SYMBOL_TYPE (&varbreak) = TOKEN_TEXT;
  461. SYMBOL_TEXT (&varbreak) = xstrdup ("");
  462. }
  463. void
  464. break_deallocate (void) {
  465. xfree ((voidstar) SYMBOL_TEXT (&varbreak));
  466. SYMBOL_TYPE (&varbreak) = TOKEN_VOID;
  467. }
  468. /*-------------------------------------------------------------------------.
  469. | Define a predefined or user-defined macro, with name NAME, and expansion |
  470. | TEXT. MODE destinguishes between the "define" and the "pushdef" case. |
  471. | It is also used from main (). |
  472. `-------------------------------------------------------------------------*/
  473. void
  474. define_user_macro (const char *name, char *text, symbol_lookup mode,
  475. boolean container, boolean expand_args, boolean space_delete)
  476. {
  477. symbol *s;
  478. char *begin, *cp;
  479. int offset, bracket_level = 0;
  480. s = lookup_symbol (name, mode);
  481. xfree ((voidstar) SYMBOL_HOOK_BEGIN (s));
  482. xfree ((voidstar) SYMBOL_HOOK_END (s));
  483. if (SYMBOL_TYPE (s) == TOKEN_TEXT)
  484. xfree ((voidstar) SYMBOL_TEXT (s));
  485. initialize_builtin (s);
  486. SYMBOL_TYPE (s) = TOKEN_TEXT;
  487. if (space_delete)
  488. {
  489. for (begin=text; *begin != '\0' && IS_SPACE(*begin); begin++)
  490. ;
  491. SYMBOL_TEXT (s) = xstrdup (begin);
  492. offset = 0;
  493. for (cp=SYMBOL_TEXT (s); *cp != '\0'; cp++)
  494. {
  495. switch (*cp)
  496. {
  497. case '<':
  498. bracket_level++;
  499. *(cp-offset) = *cp;
  500. break;
  501. case '>':
  502. bracket_level--;
  503. *(cp-offset) = *cp;
  504. break;
  505. case '\\':
  506. *(cp-offset) = *cp;
  507. if (*(cp+1) != '\0')
  508. {
  509. cp++;
  510. *(cp-offset) = *cp;
  511. }
  512. break;
  513. case '\n':
  514. if (bracket_level>0)
  515. *(cp-offset) = *cp;
  516. else
  517. {
  518. offset++;
  519. while (IS_SPACE(*(cp+1)))
  520. {
  521. cp++;
  522. offset++;
  523. }
  524. }
  525. break;
  526. default:
  527. *(cp-offset) = *cp;
  528. break;
  529. }
  530. }
  531. *(cp-offset) = '\0';
  532. }
  533. else
  534. SYMBOL_TEXT (s) = xstrdup (text);
  535. SYMBOL_CONTAINER (s) = container;
  536. SYMBOL_EXPAND_ARGS (s) = expand_args;
  537. #ifdef DEBUG_INPUT
  538. fprintf (stderr, "Define: %s\nText: %s\nContainer: %d\n",
  539. SYMBOL_NAME (s), SYMBOL_TEXT (s), SYMBOL_CONTAINER (s));
  540. #endif
  541. }
  542. /*--------------------------------------------------------------------------.
  543. | Define a predefined or user-defined entity, with name NAME, and expansion |
  544. | TEXT. MODE destinguishes between the "define" and the "pushdef" case. |
  545. | It is also used from main (). |
  546. `--------------------------------------------------------------------------*/
  547. static void
  548. define_user_entity (const char *name, char *text, symbol_lookup mode)
  549. {
  550. symbol *s;
  551. s = lookup_entity (name, mode);
  552. if (SYMBOL_TYPE (s) == TOKEN_TEXT)
  553. {
  554. xfree ((voidstar) SYMBOL_HOOK_BEGIN (s));
  555. xfree ((voidstar) SYMBOL_HOOK_END (s));
  556. xfree ((voidstar) SYMBOL_TEXT (s));
  557. }
  558. initialize_builtin (s);
  559. SYMBOL_TYPE (s) = TOKEN_TEXT;
  560. SYMBOL_TEXT (s) = xstrdup (text);
  561. #ifdef DEBUG_INPUT
  562. fprintf (stderr, "Define: %s\nText: %s\n",
  563. SYMBOL_NAME (s), SYMBOL_TEXT (s));
  564. #endif
  565. }
  566. /*-----------------------------------------------.
  567. | Initialise all builtin and predefined macros. |
  568. `-----------------------------------------------*/
  569. void
  570. builtin_init (void)
  571. {
  572. install_builtin_table (builtin_tab);
  573. pcre_malloc = xmalloc;
  574. pcre_free = xfree;
  575. }
  576. /*-----------------------------------------------.
  577. | Deallocate all builtin and predefined macros. |
  578. `-----------------------------------------------*/
  579. void
  580. builtin_deallocate (void)
  581. {
  582. builtin_table *bt, *bt_next;
  583. for (bt = builtin_tables; bt != NULL; )
  584. {
  585. bt_next = bt->next;
  586. xfree ((voidstar) bt);
  587. bt = bt_next;
  588. }
  589. varstack_check ();
  590. }
  591. static pcre *
  592. xre_compile (const char *pattern, int cflags)
  593. {
  594. pcre *patcomp;
  595. const char *errbuf;
  596. int erroffset;
  597. if (document_encoding == ENCODING_UTF8)
  598. cflags |= PCRE_UTF8;
  599. patcomp = pcre_compile (pattern, cflags, &errbuf, &erroffset, re_tableptr);
  600. if (patcomp == 0)
  601. {
  602. MP4HERROR ((warning_status, 0,
  603. _("Warning:%s:%d: Bad regular expression `%s' at position %d: %s"),
  604. CURRENT_FILE_LINE, pattern, erroffset, errbuf));
  605. }
  606. return patcomp;
  607. }
  608. static boolean
  609. safe_strtod (const char *name, const char *nptr, double *value)
  610. {
  611. char *endp;
  612. double result;
  613. result = strtod (nptr, &endp);
  614. if (nptr == NULL || *endp != '\0')
  615. {
  616. if (nptr == NULL)
  617. nptr = endp;
  618. MP4HERROR ((warning_status, 0,
  619. _("Warning:%s:%d: Argument `%s' non-numeric in <%s>"),
  620. CURRENT_FILE_LINE, nptr, name));
  621. return FALSE;
  622. }
  623. *value = result;
  624. return TRUE;
  625. }
  626. static boolean
  627. safe_strtol (const char *name, const char *nptr, long int *value)
  628. {
  629. char *endp;
  630. long int result;
  631. result = strtol (nptr, &endp, 10);
  632. if (nptr == NULL || *endp != '\0')
  633. {
  634. if (nptr == NULL)
  635. nptr = endp;
  636. MP4HERROR ((warning_status, 0,
  637. _("Warning:%s:%d: Argument `%s' non-numeric in <%s>"),
  638. CURRENT_FILE_LINE, nptr, name));
  639. return FALSE;
  640. }
  641. *value = result;
  642. return TRUE;
  643. }
  644. /*----------------------------------------------------------------.
  645. | Quote name=value pair. This function must be called only when |
  646. | text is sent to output. |
  647. `----------------------------------------------------------------*/
  648. static void
  649. quote_name_value (struct obstack *obs, char *pair)
  650. {
  651. char *equal_ptr, *cp;
  652. int special_chars;
  653. boolean valid;
  654. equal_ptr = strchr (pair, '=');
  655. if (equal_ptr == NULL)
  656. {
  657. obstack_grow (obs, pair, strlen (pair));
  658. return;
  659. }
  660. /* Skip special characters */
  661. special_chars = 0;
  662. cp = pair;
  663. while (IS_GROUP (*cp))
  664. {
  665. cp++;
  666. special_chars++;
  667. }
  668. valid = TRUE;
  669. while (cp < equal_ptr)
  670. {
  671. if (IS_SPACE (*cp) || IS_CLOSE (*cp))
  672. {
  673. valid = FALSE;
  674. break;
  675. }
  676. cp++;
  677. }
  678. if (!valid)
  679. {
  680. obstack_grow (obs, pair, strlen (pair));
  681. return;
  682. }
  683. if (special_chars)
  684. obstack_grow (obs, pair, special_chars);
  685. *equal_ptr = '\0';
  686. obstack_grow (obs, pair+special_chars, strlen (pair)-special_chars);
  687. *equal_ptr = '=';
  688. obstack_1grow (obs, '=');
  689. if (*(equal_ptr+1) != '"' && *(equal_ptr+1) != CHAR_QUOTE)
  690. obstack_1grow (obs, CHAR_QUOTE);
  691. obstack_grow (obs, equal_ptr+1, strlen (equal_ptr+1)-special_chars);
  692. if (*(equal_ptr+1) != '"' && *(equal_ptr+1) != CHAR_QUOTE)
  693. obstack_1grow (obs, CHAR_QUOTE);
  694. if (special_chars)
  695. obstack_grow (obs, equal_ptr+1+strlen (equal_ptr+1)-special_chars,
  696. special_chars);
  697. }
  698. /*---------------------------------------------------------------.
  699. | Extract from ARGV attributes from a list of attributes names. |
  700. | When MATCH is true, matching attributes are printed, otherwise |
  701. | non matching attributes are printed. |
  702. | First argument is a comma-separated list of attributes names, |
  703. | which may contain regular expressions. |
  704. `---------------------------------------------------------------*/
  705. static void
  706. matching_attributes (struct obstack *obs, int argc, token_data **argv,
  707. boolean match, char *list)
  708. {
  709. register char *cp;
  710. char *name;
  711. int i, j, special_chars;
  712. pcre *re;
  713. pcre_extra *re_extra = NULL;
  714. const char *errptr = NULL;
  715. int rc, max_subexps;
  716. int *match_ptr = NULL;
  717. boolean first = TRUE;
  718. /* Replace comma-separated list by a regular expression */
  719. for (cp=list; *cp != '\0'; cp++)
  720. {
  721. if (*cp == ',')
  722. *cp = '|';
  723. }
  724. name = (char *) xmalloc (strlen (list) + 3);
  725. sprintf (name, "^%s$", list);
  726. /* Compile this expression once */
  727. re = xre_compile (name, PCRE_CASELESS);
  728. xfree ((voidstar) name);
  729. if (re == NULL)
  730. return;
  731. if (argc>2)
  732. {
  733. re_extra = pcre_study (re, 0, &errptr);
  734. if (errptr != NULL)
  735. {
  736. MP4HERROR ((warning_status, 0,
  737. _("Error:%s:%d: Bad regular expression `%s': %s"),
  738. CURRENT_FILE_LINE, list, errptr));
  739. return;
  740. }
  741. }
  742. for (i=1; i<argc; i++)
  743. {
  744. special_chars = 0;
  745. cp = ARG (i);
  746. while (IS_GROUP (*cp))
  747. {
  748. cp++;
  749. special_chars++;
  750. }
  751. if (*(ARG (i)+special_chars) != '\0')
  752. {
  753. cp = strchr (ARG (i)+special_chars, '=');
  754. if (cp)
  755. *cp = '\0';
  756. }
  757. /* Ensure that all subexpressions are stored */
  758. max_subexps = 0;
  759. do
  760. {
  761. max_subexps += 10;
  762. match_ptr = (int *)
  763. xrealloc ((voidstar) match_ptr, sizeof (int) * max_subexps * 3);
  764. rc = pcre_exec (re, re_extra, ARG (i)+special_chars,
  765. strlen (ARG (i)+special_chars), 0,
  766. 0, match_ptr, max_subexps * 3);
  767. }
  768. while (rc == PCRE_ERROR_NOMEMORY);
  769. max_subexps -= 10;
  770. if (rc > 0 && match)
  771. {
  772. if (!first)
  773. obstack_1grow (obs, ' ');
  774. first = FALSE;
  775. obstack_1grow (obs, CHAR_BGROUP);
  776. if (special_chars)
  777. obstack_grow (obs, ARG (i), special_chars);
  778. if (rc == 1)
  779. {
  780. obstack_grow (obs, ARG (i)+special_chars,
  781. strlen (ARG (i)+special_chars));
  782. }
  783. else
  784. {
  785. for (j=1; j<rc; j++)
  786. obstack_grow (obs, ARG (i)+special_chars+match_ptr[j*2],
  787. match_ptr[j*2+1] - match_ptr[j*2]);
  788. }
  789. if (cp)
  790. {
  791. obstack_1grow (obs, '=');
  792. obstack_grow (obs, cp+1, strlen (cp+1));
  793. }
  794. obstack_1grow (obs, CHAR_EGROUP);
  795. }
  796. else if (rc == PCRE_ERROR_NOMATCH && !match)
  797. {
  798. if (cp)
  799. *cp = '=';
  800. if (!first)
  801. obstack_1grow (obs, ' ');
  802. first = FALSE;
  803. obstack_1grow (obs, CHAR_BGROUP);
  804. obstack_grow (obs, ARG (i), strlen (ARG (i)));
  805. obstack_1grow (obs, CHAR_EGROUP);
  806. }
  807. }
  808. pcre_free (re);
  809. pcre_free (re_extra);
  810. xfree ((voidstar) match_ptr);
  811. }
  812. /*
  813. The rest of this file is the code for builtins and expansion of user
  814. defined macros. All the functions for builtins have a prototype as:
  815. void mp4h_bp_MACRONAME (
  816. struct obstack *obs,
  817. int argc,
  818. char *argv[],
  819. read_type expansion
  820. );
  821. The function are expected to leave their expansion on the obstack OBS,
  822. as an unfinished object. ARGV is a table of ARGC pointers to the
  823. individual arguments to the macro. Please note that in general
  824. argv[argc] != NULL.
  825. For container tags, argv[argc] contains the body function.
  826. */
  827. /* Notes for hackers :
  828. o Execution must not depend on argv[0]. Indeed, user may define
  829. synonyms with <let myfunc primitive>
  830. o Last argument is removed by collect_arguments () if it is empty.
  831. For this reason, it does not make sense to define a mimimal
  832. number of arguments.
  833. */
  834. /* Miscellaneous builtins -- "__file__" and "__line__". */
  835. static void
  836. mp4h_bp___file__ (MP4H_BUILTIN_ARGS)
  837. {
  838. if (argc == 1)
  839. shipout_string (obs, current_file, 0);
  840. else
  841. {
  842. xfree ((voidstar) current_file);
  843. current_file = xstrdup (ARG (1));
  844. }
  845. }
  846. static void
  847. mp4h_bp___line__ (MP4H_BUILTIN_ARGS)
  848. {
  849. if (argc == 1)
  850. shipout_int (obs, current_line);
  851. else
  852. numeric_arg (argv[0], ARG (1), FALSE, &current_line);
  853. }
  854. /*-----------------------------.
  855. | Initialize character table. |
  856. `-----------------------------*/
  857. void
  858. pcre_init (void)
  859. {
  860. re_tableptr = pcre_maketables ();
  861. }
  862. void
  863. pcre_deallocate (void)
  864. {
  865. pcre_free ((voidstar) re_tableptr);
  866. }
  867. /*---------------------.
  868. | Initialize locales. |
  869. `---------------------*/
  870. #ifdef HAVE_LOCALE_H
  871. void
  872. locale_init (int category, char *value)
  873. {
  874. setlocale (category, value);
  875. my_locale = localeconv ();
  876. decimal_point = my_locale->decimal_point;
  877. }
  878. /*---------------------------.
  879. | Change locale attributes. |
  880. `---------------------------*/
  881. static void
  882. mp4h_bp_mp4h_l10n (MP4H_BUILTIN_ARGS)
  883. {
  884. char *cp;
  885. int i;
  886. int category;
  887. for (i=1; i<argc; i++)
  888. {
  889. category = -1;
  890. cp = strchr (ARG (i), '=');
  891. if (cp)
  892. {
  893. *cp = '\0';
  894. if (strcmp (ARG (i), "LC_ALL") == 0)
  895. category = LC_ALL;
  896. else if (strcmp (ARG (i), "LC_COLLATE") == 0)
  897. category = LC_COLLATE;
  898. else if (strcmp (ARG (i), "LC_CTYPE") == 0)
  899. category = LC_CTYPE;
  900. else if (strcmp (ARG (i), "LC_MESSAGES") == 0)
  901. category = LC_MESSAGES;
  902. else if (strcmp (ARG (i), "LC_MONETARY") == 0)
  903. category = LC_MONETARY;
  904. else if (strcmp (ARG (i), "LC_NUMERIC") == 0)
  905. category = LC_NUMERIC;
  906. else if (strcmp (ARG (i), "LC_TIME") == 0)
  907. category = LC_TIME;
  908. }
  909. if (category == -1)
  910. MP4HERROR ((warning_status, 0,
  911. _("Warning:%s:%d: Unknown locale `%s'"), CURRENT_FILE_LINE, ARG (i)));
  912. else
  913. {
  914. locale_init (category, cp+1);
  915. pcre_deallocate ();
  916. pcre_init ();
  917. }
  918. }
  919. /* Compute syntax table */
  920. syntax_init ();
  921. }
  922. #endif /* HAVE_LOCALE_H */
  923. /*----------------------------------------------.
  924. | Set output radix used when printing numbers. |
  925. `----------------------------------------------*/
  926. static void
  927. mp4h_bp_mp4h_output_radix (MP4H_BUILTIN_ARGS)
  928. {
  929. if (bad_argc (argv[0], argc, 0, 2))
  930. return;
  931. safe_strtol (ARG (0), ARG (1), (long int *) &output_radix);
  932. }
  933. static void
  934. mp4h_bp_timer (MP4H_BUILTIN_ARGS)
  935. {
  936. char buf[128];
  937. times(&elapsed_time);
  938. sprintf (buf, "user %d\nsys %d\n", (int) elapsed_time.tms_utime,
  939. (int) elapsed_time.tms_stime);
  940. obstack_grow (obs, buf, strlen (buf));
  941. }
  942. #if !defined(HAVE_FILE_FUNCS) || !defined (HAVE_LOCALE_H) || !defined(WITH_MODULES)
  943. static void
  944. mp4h_bp_unsupported (MP4H_BUILTIN_ARGS)
  945. {
  946. MP4HERROR ((warning_status, 0,
  947. _("Warning:%s:%d: The <%s> tag is not implemented on your OS\n"),
  948. CURRENT_FILE_LINE, ARG (0)));
  949. }
  950. #endif
  951. static void
  952. mp4h_bp___version__ (MP4H_BUILTIN_ARGS)
  953. {
  954. obstack_grow (obs, PACKAGE_VERSION, strlen (PACKAGE_VERSION));
  955. }
  956. static void
  957. add_1char_protected (struct obstack *obs, char ch)
  958. {
  959. obstack_1grow (obs, CHAR_LQUOTE);
  960. obstack_1grow (obs, ch);
  961. obstack_1grow (obs, CHAR_RQUOTE);
  962. }
  963. static void
  964. mp4h_bp_lb (MP4H_BUILTIN_ARGS)
  965. {
  966. add_1char_protected (obs, '<');
  967. }
  968. static void
  969. mp4h_bp_rb (MP4H_BUILTIN_ARGS)
  970. {
  971. add_1char_protected (obs, '>');
  972. }
  973. static void
  974. mp4h_bp_dq (MP4H_BUILTIN_ARGS)
  975. {
  976. obstack_1grow (obs, CHAR_QUOTE);
  977. }
  978. static void
  979. mp4h_bp_bs (MP4H_BUILTIN_ARGS)
  980. {
  981. add_1char_protected (obs, '\\');
  982. }
  983. /* Enable tracing of all specified macros, or all, if none is specified.
  984. Tracing is disabled by default, when a macro is defined. This can be
  985. overridden by the "t" debug flag. */
  986. /*-----------------------------------------------------------------------.
  987. | Set_trace () is used by "debugging-on" and "debugging-off" to enable |
  988. | and disable tracing of a macro. It disables tracing if DATA is NULL, |
  989. | otherwise it enable tracing. |
  990. `-----------------------------------------------------------------------*/
  991. static void
  992. set_trace (symbol *sym, const char *data)
  993. {
  994. SYMBOL_TRACED (sym) = (boolean) (data != NULL);
  995. }
  996. static void
  997. mp4h_bp_debugging_on (MP4H_BUILTIN_ARGS)
  998. {
  999. symbol *s;
  1000. int i;
  1001. if (argc == 1)
  1002. hack_all_symbols (set_trace, (char *) obs);
  1003. else
  1004. for (i = 1; i < argc; i++)
  1005. {
  1006. s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
  1007. if (s != NULL)
  1008. set_trace (s, (char *) obs);
  1009. else
  1010. MP4HERROR ((warning_status, 0,
  1011. _("Warning:%s:%d: Undefined name %s"),
  1012. CURRENT_FILE_LINE, ARG (i)));
  1013. }
  1014. }
  1015. /*------------------------------------------------------------------------.
  1016. | Disable tracing of all specified macros, or all, if none is specified. |
  1017. `------------------------------------------------------------------------*/
  1018. static void
  1019. mp4h_bp_debugging_off (MP4H_BUILTIN_ARGS)
  1020. {
  1021. symbol *s;
  1022. int i;
  1023. if (argc == 1)
  1024. hack_all_symbols (set_trace, NULL);
  1025. else
  1026. for (i = 1; i < argc; i++)
  1027. {
  1028. s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
  1029. if (s != NULL)
  1030. set_trace (s, NULL);
  1031. else
  1032. MP4HERROR ((warning_status, 0,
  1033. _("Warning:%s:%d: Undefined name %s"),
  1034. CURRENT_FILE_LINE, ARG (i)));
  1035. }
  1036. }
  1037. /*----------------------------------------------------------------------.
  1038. | On-the-fly control of the format of the tracing output. It takes one |
  1039. | argument, which is a character string like given to the -d option, or |
  1040. | none in which case the debug_level is zeroed. |
  1041. `----------------------------------------------------------------------*/
  1042. static void
  1043. mp4h_bp_debugmode (MP4H_BUILTIN_ARGS)
  1044. {
  1045. int new_debug_level;
  1046. int change_flag;
  1047. if (bad_argc (argv[0], argc, 0, 2))
  1048. return;
  1049. if (argc == 1)
  1050. debug_level = 0;
  1051. else
  1052. {
  1053. if (ARG (1)[0] == '+' || ARG (1)[0] == '-')
  1054. {
  1055. change_flag = ARG (1)[0];
  1056. new_debug_level = debug_decode (ARG (1) + 1);
  1057. }
  1058. else
  1059. {
  1060. change_flag = 0;
  1061. new_debug_level = debug_decode (ARG (1));
  1062. }
  1063. if (new_debug_level < 0)
  1064. MP4HERROR ((warning_status, 0,
  1065. _("Warning:%s:%d: Bad debug flags: `%s'"),
  1066. CURRENT_FILE_LINE, ARG (1)));
  1067. else
  1068. {
  1069. switch (change_flag)
  1070. {
  1071. case 0:
  1072. debug_level = new_debug_level;
  1073. break;
  1074. case '+':
  1075. debug_level |= new_debug_level;
  1076. break;
  1077. case '-':
  1078. debug_level &= ~new_debug_level;
  1079. break;
  1080. }
  1081. }
  1082. }
  1083. }
  1084. /*-------------------------------------------------------------------------.
  1085. | Specify the destination of the debugging output. With one argument, the |
  1086. | argument is taken as a file name, with no arguments, revert to stderr. |
  1087. `-------------------------------------------------------------------------*/
  1088. static void
  1089. mp4h_bp_debugfile (MP4H_BUILTIN_ARGS)
  1090. {
  1091. if (bad_argc (argv[0], argc, 1, 2))
  1092. return;
  1093. if (argc == 1)
  1094. debug_set_output (NULL);
  1095. else if (!debug_set_output (ARG (1)))
  1096. MP4HERROR ((warning_status, errno,
  1097. _("Warning:%s:%d: Cannot set error file: %s"),
  1098. CURRENT_FILE_LINE, ARG (1)));
  1099. }
  1100. /*---------------------------------------------------------.
  1101. | Print the replacement text for a builtin or user macro. |
  1102. `---------------------------------------------------------*/
  1103. static void
  1104. mp4h_bp_function_def (MP4H_BUILTIN_ARGS)
  1105. {
  1106. symbol *s;
  1107. if (bad_argc (argv[0], argc, 2, 2))
  1108. return;
  1109. s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
  1110. if (s == NULL)
  1111. return;
  1112. switch (SYMBOL_TYPE (s))
  1113. {
  1114. case TOKEN_TEXT:
  1115. obstack_1grow (obs, CHAR_LQUOTE);
  1116. shipout_string (obs, SYMBOL_TEXT (s), strlen (SYMBOL_TEXT (s)));
  1117. obstack_1grow (obs, CHAR_RQUOTE);
  1118. break;
  1119. case TOKEN_FUNC:
  1120. push_macro (SYMBOL_FUNC (s), SYMBOL_TRACED (s));
  1121. break;
  1122. case TOKEN_VOID:
  1123. break;
  1124. default:
  1125. MP4HERROR ((warning_status, 0,
  1126. "INTERNAL ERROR: Bad symbol type in mp4h_bp_function_def ()"));
  1127. exit (1);
  1128. }
  1129. }
  1130. /* file functions */
  1131. #ifdef HAVE_FILE_FUNCS
  1132. /*-----------------------------------------------------------------.
  1133. | Informations on a file. A newline separated string is printed: |
  1134. | Line 1: file size |
  1135. | Line 2: file type |
  1136. | Line 3: time of last change |
  1137. | Line 4: time of last modification |
  1138. | Line 5: time of last modification |
  1139. | Line 6: time of last access |
  1140. | Line 7: name of the owner of this file |
  1141. | Line 8: name of the group of this file |
  1142. `-----------------------------------------------------------------*/
  1143. static void
  1144. mp4h_bp_get_file_properties (MP4H_BUILTIN_ARGS)
  1145. {
  1146. struct stat buf;
  1147. struct passwd *user;
  1148. struct group *group;
  1149. CHECK_SAFETY_LEVEL(1);
  1150. if (bad_argc (argv[0], argc, 2, 2))
  1151. return;
  1152. if (stat (ARG (1), &buf))
  1153. {
  1154. MP4HERROR ((warning_status, errno,
  1155. _("Warning:%s:%d: Could not stat `%s'"),
  1156. CURRENT_FILE_LINE, ARG (1)));
  1157. return;
  1158. }
  1159. shipout_long (obs, (long) buf.st_size);
  1160. obstack_1grow (obs, '\n');
  1161. if (S_ISLNK(buf.st_mode))
  1162. obstack_grow (obs, "LINK", 4);
  1163. else if (S_ISREG(buf.st_mode))
  1164. obstack_grow (obs, "FILE", 4);
  1165. else if (S_ISDIR(buf.st_mode))
  1166. obstack_grow (obs, "DIR", 3);
  1167. else
  1168. obstack_grow (obs, "UNKNOWN", 7);
  1169. obstack_1grow (obs, '\n');
  1170. shipout_long (obs, (long) buf.st_ctime);
  1171. obstack_1grow (obs, '\n');
  1172. shipout_long (obs, (long) buf.st_mtime);
  1173. obstack_1grow (obs, '\n');
  1174. shipout_long (obs, (long) buf.st_atime);
  1175. obstack_1grow (obs, '\n');
  1176. user = getpwuid (buf.st_uid);
  1177. if (user)
  1178. obstack_grow (obs, user->pw_name, strlen (user->pw_name));
  1179. else
  1180. obstack_grow (obs, "(UNKNOWN)", 9);
  1181. obstack_1grow (obs, '\n');
  1182. group = getgrgid (buf.st_gid);
  1183. if (group)
  1184. obstack_grow (obs, group->gr_name, strlen (group->gr_name));
  1185. else
  1186. obstack_grow (obs, "(UNKNOWN)", 9);
  1187. obstack_1grow (obs, '\n');
  1188. }
  1189. /*-----------------------------------------------------------------.
  1190. | Prints a directory contents. A pattern can be specified with |
  1191. | the ``matching'' attribute. This pattern is a regexp one, |
  1192. | not a shell expansion. |
  1193. `-----------------------------------------------------------------*/
  1194. static void
  1195. mp4h_bp_directory_contents (MP4H_BUILTIN_ARGS)
  1196. {
  1197. DIR *dir;
  1198. struct dirent *entry;
  1199. int length;
  1200. const char *matching;
  1201. pcre *re = NULL;
  1202. pcre_extra *re_extra = NULL;
  1203. const char *errptr = NULL;
  1204. int *match_ptr = NULL;
  1205. boolean first = TRUE;
  1206. CHECK_SAFETY_LEVEL(1);
  1207. matching = predefined_attribute ("matching", &argc, argv, FALSE);
  1208. if (bad_argc (argv[0], argc, 2, 2))
  1209. return;
  1210. /* First, opens directory. */
  1211. dir = opendir (ARG (1));
  1212. if (dir == NULL)
  1213. return;
  1214. if (matching)
  1215. {
  1216. re = xre_compile (matching, 0);
  1217. if (re == NULL)
  1218. return;
  1219. match_ptr = (int *)
  1220. xrealloc ((voidstar) match_ptr, sizeof (int) * 3);
  1221. re_extra = pcre_study (re, 0, &errptr);
  1222. if (errptr != NULL)
  1223. {
  1224. MP4HERROR ((warning_status, 0,
  1225. _("Error:%s:%d: Bad regular expression `%s': %s"),
  1226. CURRENT_FILE_LINE, matching, errptr));
  1227. return;
  1228. }
  1229. }
  1230. while ((entry = readdir (dir)) != (struct dirent *)NULL)
  1231. {
  1232. length = strlen (entry->d_name);
  1233. if (!matching ||
  1234. (pcre_exec (re, re_extra, entry->d_name, length, 0,
  1235. 0, match_ptr, 3) > 0
  1236. && match_ptr[1] - match_ptr[0] == length))
  1237. {
  1238. if (!first)
  1239. obstack_1grow (obs, '\n');
  1240. obstack_grow (obs, entry->d_name, length);
  1241. first = FALSE;
  1242. }
  1243. }
  1244. if (matching)
  1245. {
  1246. pcre_free (re);
  1247. pcre_free (re_extra);
  1248. xfree ((voidstar) match_ptr);
  1249. }
  1250. closedir (dir);
  1251. }
  1252. /*--------------------------------.
  1253. | Returns "true" if file exists. |
  1254. `--------------------------------*/
  1255. static void
  1256. mp4h_bp_file_exists (MP4H_BUILTIN_ARGS)
  1257. {
  1258. struct stat file;
  1259. CHECK_SAFETY_LEVEL(1);
  1260. if (bad_argc (argv[0], argc, 2, 2))
  1261. return;
  1262. if ((stat (ARG (1), &file)) != -1)
  1263. obstack_grow (obs, "true", 4);
  1264. }
  1265. /*------------------------------------.
  1266. | Returns a real (absolute) path name |
  1267. `------------------------------------*/
  1268. static void
  1269. mp4h_bp_real_path (MP4H_BUILTIN_ARGS)
  1270. {
  1271. const char *pathname;
  1272. char resolvedname[MAXPATHLEN];
  1273. CHECK_SAFETY_LEVEL(1);
  1274. pathname = predefined_attribute ("pathname", &argc, argv, FALSE);
  1275. if (!pathname)
  1276. MP4HERROR ((warning_status, 0,
  1277. _("Warning:%s:%d: In <%s>, required attribute `%s' is not specified"),
  1278. CURRENT_FILE_LINE, ARG (0), "pathname"));
  1279. else
  1280. if (!realpath(pathname, resolvedname))
  1281. MP4HERROR ((warning_status, errno,
  1282. _("Error:%s:%d: Cannot form real path for `%s'"),
  1283. CURRENT_FILE_LINE, pathname));
  1284. else
  1285. obstack_grow(obs, resolvedname, strlen(resolvedname));
  1286. }
  1287. #endif /* HAVE_FILE_FUNCS */
  1288. /*------------------------------------------------------------.
  1289. | Converts an epoch to a readable string. |
  1290. | If no argument is given, current date and time is printed. |
  1291. `------------------------------------------------------------*/
  1292. static void
  1293. mp4h_bp_date (MP4H_BUILTIN_ARGS)
  1294. {
  1295. time_t epoch_time = (time_t)0;
  1296. char *ascii_time;
  1297. const char *format, *timespec;
  1298. struct tm *timeptr;
  1299. char *endp = NULL;
  1300. format = predefined_attribute ("format", &argc, argv, FALSE);
  1301. timespec = predefined_attribute ("time", &argc, argv, FALSE);
  1302. if (!format && !timespec)
  1303. /* backwards compatible... */
  1304. if (argc > 1)
  1305. timespec = ARG (1);
  1306. if (timespec)
  1307. {
  1308. epoch_time = strtol (timespec, &endp, 10);
  1309. if (!endp)
  1310. {
  1311. MP4HERROR ((warning_status, 0,
  1312. _("Warning:%s:%d: Invalid value in date: %s"),
  1313. CURRENT_FILE_LINE, ARG (1)));
  1314. return;
  1315. }
  1316. }
  1317. else
  1318. epoch_time = time ((time_t *)NULL);
  1319. timeptr = (struct tm *) localtime (&epoch_time);
  1320. if (format)
  1321. {
  1322. ascii_time = (char *)xmalloc(1000);
  1323. strftime(ascii_time, 1000, format, timeptr);
  1324. obstack_grow (obs, ascii_time, strlen (ascii_time));
  1325. xfree((voidstar) ascii_time);
  1326. }
  1327. else
  1328. {
  1329. ascii_time = (char *) asctime (timeptr);
  1330. /* Remove newline. */
  1331. LAST_CHAR (ascii_time) = '\0';
  1332. obstack_grow (obs, ascii_time, strlen (ascii_time));
  1333. }
  1334. }
  1335. /* Flow functions: these functions allow complex structures
  1336. There are 2 different kinds of conditions : numerical and
  1337. string tests. A numerical test is false if result is null
  1338. and right if non null. String-based tests are false if
  1339. followed by a null string, and right otherwise. */
  1340. /*----------------------------------------------------------.
  1341. | Group multiple tags into one. This is useful when |
  1342. | combined with tests like <if>, <ifeq>, .... |
  1343. `----------------------------------------------------------*/
  1344. static void
  1345. mp4h_bp_group (MP4H_BUILTIN_ARGS)
  1346. {
  1347. const char *separator;
  1348. separator = predefined_attribute ("separator", &argc, argv, FALSE);
  1349. obstack_1grow (obs, CHAR_BGROUP);
  1350. /* separator = NULL is handled by dump_args */
  1351. dump_args (obs, argc, argv, separator);
  1352. obstack_1grow (obs, CHAR_EGROUP);
  1353. }
  1354. /*------------------------------------------------.
  1355. | Like <group>, but this one is a container tag. |
  1356. `------------------------------------------------*/
  1357. static void
  1358. mp4h_bp_compound (MP4H_BUILTIN_ARGS)
  1359. {
  1360. const char *separator;
  1361. separator = predefined_attribute ("separator", &argc, argv, FALSE);
  1362. obstack_1grow (obs, CHAR_BGROUP);
  1363. /* separator = NULL is handled by dump_args */
  1364. dump_args (obs, argc, argv, separator);
  1365. obstack_grow (obs, ARGBODY, strlen (ARGBODY));
  1366. obstack_1grow (obs, CHAR_EGROUP);
  1367. }
  1368. /*------------------------------------------------.
  1369. | Allow breaking an object into several pieces. |
  1370. `------------------------------------------------*/
  1371. static void
  1372. mp4h_bp_disjoin (MP4H_BUILTIN_ARGS)
  1373. {
  1374. obstack_1grow (obs, CHAR_EGROUP);
  1375. obstack_grow (obs, ARG(1), strlen (ARG(1)));
  1376. obstack_1grow (obs, CHAR_BGROUP);
  1377. }
  1378. /*-------------------------------------------.
  1379. | Prevent further expansion of attributes. |
  1380. `-------------------------------------------*/
  1381. static void
  1382. mp4h_bp_noexpand (MP4H_BUILTIN_ARGS)
  1383. {
  1384. obstack_1grow (obs, CHAR_LQUOTE);
  1385. dump_args (obs, argc, argv, NULL);
  1386. obstack_1grow (obs, CHAR_RQUOTE);
  1387. }
  1388. /*----------------------------------------------------------.
  1389. | Remove special characters which forbid expansion. |
  1390. `----------------------------------------------------------*/
  1391. static void
  1392. mp4h_bp_expand (MP4H_BUILTIN_ARGS)
  1393. {
  1394. int i, offset;
  1395. register char *cp;
  1396. for (i=1; i<argc; i++)
  1397. {
  1398. offset = 0;
  1399. for (cp=ARG (i); *cp != '\0'; cp++)
  1400. {
  1401. if (*cp == CHAR_LQUOTE || *cp == CHAR_RQUOTE)
  1402. offset++;
  1403. else
  1404. *(cp-offset) = *cp;
  1405. }
  1406. *(cp-offset) = '\0';
  1407. }
  1408. dump_args (obs, argc, argv, NULL);
  1409. }
  1410. /*--------------------------------------------------------------.
  1411. | If followed by a non-empty string, second argument is |
  1412. | expanded, otherwise 3rd argument is read. |
  1413. `--------------------------------------------------------------*/
  1414. static void
  1415. mp4h_bp_if (MP4H_BUILTIN_ARGS)
  1416. {
  1417. symbol *var;
  1418. if (bad_argc (argv[0], argc, 0, 4))
  1419. return;
  1420. if (argc == 1)
  1421. return;
  1422. /* The ``natural'' way to implement <if/> is with
  1423. obstack_grow (obs, "<when ", 6);
  1424. obstack_grow (obs, ARG (1), strlen (ARG (1)));
  1425. obstack_grow (obs, " >", 2);
  1426. obstack_grow (obs, ARG (2), strlen (ARG (2)));
  1427. obstack_grow (obs, "</when>", 7);
  1428. and a similar else-clause.
  1429. But this is broken, because ARG(2) may change the condition, and
  1430. then else-clause could be run too.
  1431. For this reason, the following implementation is preferred.
  1432. */
  1433. var = lookup_variable ("__cond_cnt", SYMBOL_LOOKUP);
  1434. if (var == NULL)
  1435. {
  1436. var = lookup_variable ("__cond_cnt", SYMBOL_INSERT);
  1437. SYMBOL_TEXT (var) = (char *) xstrdup ("0");
  1438. SYMBOL_TYPE (var) = TOKEN_TEXT;
  1439. }
  1440. obstack_grow (obs, "<increment __cond_cnt />", 24);
  1441. obstack_grow (obs, "<set-var __cond_var<get-var __cond_cnt />=", 42);
  1442. obstack_1grow (obs, CHAR_BGROUP);
  1443. obstack_grow (obs, ARG (1), strlen (ARG (1)));
  1444. obstack_1grow (obs, CHAR_EGROUP);
  1445. obstack_grow (obs, " />", 3);
  1446. obstack_grow (obs, "<when <get-var __cond_var<get-var __cond_cnt /> /> >", 52);
  1447. obstack_grow (obs, ARG (2), strlen (ARG (2)));
  1448. obstack_grow (obs, "</when>", 7);
  1449. if (argc>3)
  1450. {
  1451. obstack_grow (obs, "<when <not <get-var __cond_var<get-var __cond_cnt /> /> /> >", 60);
  1452. obstack_grow (obs, ARG (3), strlen (ARG (3)));
  1453. obstack_grow (obs, "</when>", 7);
  1454. }
  1455. obstack_grow (obs, "<decrement __cond_cnt />", 24);
  1456. }
  1457. /*------------------------------------------------------.
  1458. | String comparisons. |
  1459. | If 2nd and 3rd arguments are equal, 4th argumeā€¦

Large files files are truncated, but you can click here to view the full file