ast_expr2.fl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. %{
  2. /*
  3. * Asterisk -- An open source telephony toolkit.
  4. *
  5. * Copyright (C) 1999 - 2006, Digium, Inc.
  6. *
  7. * Mark Spencer <markster@digium.com>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief Dialplan Expression Lexical Scanner
  22. */
  23. #include <sys/types.h>
  24. #include <stdio.h>
  25. #if !defined(STANDALONE)
  26. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  27. #else
  28. #ifndef __USE_ISOC99
  29. #define __USE_ISOC99 1
  30. #endif
  31. #endif
  32. #ifdef __USE_ISOC99
  33. #define FP___PRINTF "%.18Lg"
  34. #define FP___FMOD fmodl
  35. #define FP___STRTOD strtold
  36. #define FP___TYPE long double
  37. #else
  38. #define FP___PRINTF "%.16g"
  39. #define FP___FMOD fmod
  40. #define FP___STRTOD strtod
  41. #define FP___TYPE double
  42. #endif
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <locale.h>
  46. #include <ctype.h>
  47. #if !defined(SOLARIS) && !defined(__CYGWIN__)
  48. /* #include <err.h> */
  49. #else
  50. #define quad_t int64_t
  51. #endif
  52. #include <errno.h>
  53. #include <regex.h>
  54. #include <limits.h>
  55. #include "asterisk/ast_expr.h"
  56. #include "asterisk/logger.h"
  57. #ifndef STANDALONE
  58. #include "asterisk/strings.h"
  59. #include "asterisk/channel.h"
  60. #endif
  61. /* Conditionally redefine the macro from flex 2.5.35, in case someone uses flex <2.5.35 to regenerate this file. */
  62. #ifndef ECHO
  63. #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
  64. #endif
  65. enum valtype {
  66. AST_EXPR_number, AST_EXPR_numeric_string, AST_EXPR_string
  67. } ;
  68. struct val {
  69. enum valtype type;
  70. union {
  71. char *s;
  72. FP___TYPE i; /* long double or just double if it's a bad day */
  73. } u;
  74. } ;
  75. #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
  76. #define SET_COLUMNS do { \
  77. yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
  78. yylloc_param->last_column += yyleng - 1; \
  79. yylloc_param->first_line = yylloc_param->last_line = 1; \
  80. } while (0)
  81. #define SET_STRING do { \
  82. yylval_param->val = calloc(1, sizeof(struct val)); \
  83. yylval_param->val->type = AST_EXPR_string; \
  84. yylval_param->val->u.s = strdup(yytext); \
  85. } while (0)
  86. #define SET_NUMERIC_STRING do { \
  87. yylval_param->val = calloc(1, sizeof(struct val)); \
  88. yylval_param->val->type = AST_EXPR_numeric_string; \
  89. yylval_param->val->u.s = strdup(yytext); \
  90. } while (0)
  91. struct parse_io
  92. {
  93. char *string;
  94. struct val *val;
  95. yyscan_t scanner;
  96. struct ast_channel *chan;
  97. };
  98. void ast_yyset_column(int column_no, yyscan_t yyscanner);
  99. int ast_yyget_column(yyscan_t yyscanner);
  100. static int curlycount = 0;
  101. static char *expr2_token_subst(const char *mess);
  102. %}
  103. %option prefix="ast_yy"
  104. %option batch
  105. %option 8bit
  106. %option outfile="ast_expr2f.c"
  107. %option reentrant
  108. %option bison-bridge
  109. %option bison-locations
  110. %option noyywrap
  111. %option noyyfree
  112. %x var trail
  113. %%
  114. \| { SET_COLUMNS; SET_STRING; return TOK_OR;}
  115. \& { SET_COLUMNS; SET_STRING; return TOK_AND;}
  116. \= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
  117. \|\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
  118. \&\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
  119. \=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
  120. \=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
  121. \~~ { SET_COLUMNS; SET_STRING; return TOK_TILDETILDE;}
  122. \> { SET_COLUMNS; SET_STRING; return TOK_GT;}
  123. \< { SET_COLUMNS; SET_STRING; return TOK_LT;}
  124. \>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
  125. \<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
  126. \!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
  127. \+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
  128. \, { SET_COLUMNS; SET_STRING; return TOK_COMMA;}
  129. \- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
  130. \* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
  131. \/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
  132. \% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
  133. \? { SET_COLUMNS; SET_STRING; return TOK_COND;}
  134. \! { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
  135. \: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
  136. \:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
  137. \( { SET_COLUMNS; SET_STRING; return TOK_LP;}
  138. \) { SET_COLUMNS; SET_STRING; return TOK_RP;}
  139. \$\{ {
  140. /* gather the contents of ${} expressions, with trailing stuff,
  141. * into a single TOKEN.
  142. * They are much more complex now than they used to be
  143. */
  144. curlycount = 0;
  145. BEGIN(var);
  146. yymore();
  147. }
  148. [ \t\r] {}
  149. \"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
  150. [\n] {/* what to do with eol */}
  151. [0-9]+(\.[0-9]+)? {
  152. SET_COLUMNS;
  153. /* the original behavior of the expression parser was
  154. * to bring in numbers as a numeric string
  155. */
  156. SET_NUMERIC_STRING;
  157. return TOKEN;
  158. }
  159. ([a-zA-Z0-9\.';\\_^#@]|[\x80-\xff]|($[^{]))+ {
  160. SET_COLUMNS;
  161. SET_STRING;
  162. return TOKEN;
  163. }
  164. ([a-zA-Z0-9\.';\\_^#@]|[\x80-\xff]|($[^{]))+\$\{ {
  165. curlycount = 0;
  166. BEGIN(var);
  167. yymore();
  168. }
  169. <var>[^{}]*\} {
  170. curlycount--;
  171. if (curlycount < 0) {
  172. BEGIN(trail);
  173. yymore();
  174. } else {
  175. yymore();
  176. }
  177. }
  178. <var>[^{}]*\{ {
  179. curlycount++;
  180. yymore();
  181. }
  182. <trail>[^-\t\r \n$():?%/+=*<>!|&]* {
  183. BEGIN(0);
  184. SET_COLUMNS;
  185. SET_STRING;
  186. return TOKEN;
  187. }
  188. <trail>[^-\t\r \n$():?%/+=*<>!|&]*\$\{ {
  189. curlycount = 0;
  190. BEGIN(var);
  191. yymore();
  192. }
  193. <trail>[-\t\r \n$():?%/+=*<>!|&] {
  194. char c = yytext[yyleng-1];
  195. BEGIN(0);
  196. unput(c);
  197. SET_COLUMNS;
  198. SET_STRING;
  199. return TOKEN;
  200. }
  201. <trail><<EOF>> {
  202. BEGIN(0);
  203. SET_COLUMNS;
  204. SET_STRING;
  205. return TOKEN;
  206. /*actually, if an expr is only a variable ref, this could happen a LOT */
  207. }
  208. %%
  209. /* I'm putting the interface routine to the whole parse here in the flexer input file
  210. mainly because of all the flexer initialization that has to be done. Shouldn't matter
  211. where it is, as long as it's somewhere. I didn't want to define a prototype for the
  212. ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
  213. UGH! that would be inappropriate. */
  214. int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
  215. int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
  216. void ast_yyfree(void *ptr, yyscan_t yyscanner)
  217. {
  218. /* the normal generated yyfree func just frees its first arg;
  219. this get complaints on some systems, as sometimes this
  220. arg is a nil ptr! It's usually not fatal, but is irritating! */
  221. free( (char *) ptr );
  222. }
  223. int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
  224. {
  225. struct parse_io io = { .string = expr, .chan = chan };
  226. int return_value = 0;
  227. ast_yylex_init(&io.scanner);
  228. ast_yy_scan_string(expr, io.scanner);
  229. ast_yyparse ((void *) &io);
  230. ast_yylex_destroy(io.scanner);
  231. if (!io.val) {
  232. if (length > 1) {
  233. strcpy(buf, "0");
  234. return_value = 1;
  235. }
  236. } else {
  237. if (io.val->type == AST_EXPR_number) {
  238. int res_length;
  239. res_length = snprintf(buf, length, FP___PRINTF, io.val->u.i);
  240. return_value = (res_length <= length) ? res_length : length;
  241. } else {
  242. if (io.val->u.s)
  243. #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE)
  244. strncpy(buf, io.val->u.s, length - 1);
  245. #else /* !STANDALONE && !LOW_MEMORY */
  246. ast_copy_string(buf, io.val->u.s, length);
  247. #endif /* STANDALONE || LOW_MEMORY */
  248. else
  249. buf[0] = 0;
  250. return_value = strlen(buf);
  251. free(io.val->u.s);
  252. }
  253. free(io.val);
  254. }
  255. return return_value;
  256. }
  257. #ifndef STANDALONE
  258. int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
  259. {
  260. struct parse_io io = { .string = expr, .chan = chan };
  261. ast_yylex_init(&io.scanner);
  262. ast_yy_scan_string(expr, io.scanner);
  263. ast_yyparse ((void *) &io);
  264. ast_yylex_destroy(io.scanner);
  265. if (!io.val) {
  266. ast_str_set(str, maxlen, "0");
  267. } else {
  268. if (io.val->type == AST_EXPR_number) {
  269. ast_str_set(str, maxlen, FP___PRINTF, io.val->u.i);
  270. } else if (io.val->u.s) {
  271. ast_str_set(str, maxlen, "%s", io.val->u.s);
  272. free(io.val->u.s);
  273. }
  274. free(io.val);
  275. }
  276. return ast_str_strlen(*str);
  277. }
  278. #endif
  279. char extra_error_message[4095];
  280. int extra_error_message_supplied = 0;
  281. void ast_expr_register_extra_error_info(char *message);
  282. void ast_expr_clear_extra_error_info(void);
  283. void ast_expr_register_extra_error_info(char *message)
  284. {
  285. extra_error_message_supplied=1;
  286. strcpy(extra_error_message, message);
  287. }
  288. void ast_expr_clear_extra_error_info(void)
  289. {
  290. extra_error_message_supplied=0;
  291. extra_error_message[0] = 0;
  292. }
  293. static const char * const expr2_token_equivs1[] =
  294. {
  295. "TOKEN",
  296. "TOK_COND",
  297. "TOK_COLONCOLON",
  298. "TOK_OR",
  299. "TOK_AND",
  300. "TOK_EQ",
  301. "TOK_GT",
  302. "TOK_LT",
  303. "TOK_GE",
  304. "TOK_LE",
  305. "TOK_NE",
  306. "TOK_PLUS",
  307. "TOK_MINUS",
  308. "TOK_MULT",
  309. "TOK_DIV",
  310. "TOK_MOD",
  311. "TOK_COMPL",
  312. "TOK_COLON",
  313. "TOK_EQTILDE",
  314. "TOK_COMMA",
  315. "TOK_RP",
  316. "TOK_LP"
  317. };
  318. static const char * const expr2_token_equivs2[] =
  319. {
  320. "<token>",
  321. "?",
  322. "::",
  323. "|",
  324. "&",
  325. "=",
  326. ">",
  327. "<",
  328. ">=",
  329. "<=",
  330. "!=",
  331. "+",
  332. "-",
  333. "*",
  334. "/",
  335. "%",
  336. "!",
  337. ":",
  338. "=~",
  339. ",",
  340. ")",
  341. "("
  342. };
  343. static char *expr2_token_subst(const char *mess)
  344. {
  345. /* calc a length, malloc, fill, and return; yyerror had better free it! */
  346. int len=0,i;
  347. const char *p;
  348. char *res, *s;
  349. const char *t;
  350. int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
  351. for (p=mess; *p; p++) {
  352. for (i=0; i<expr2_token_equivs_entries; i++) {
  353. if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
  354. {
  355. len+=strlen(expr2_token_equivs2[i])+2;
  356. p += strlen(expr2_token_equivs1[i])-1;
  357. break;
  358. }
  359. }
  360. len++;
  361. }
  362. res = (char*)malloc(len+1);
  363. res[0] = 0;
  364. s = res;
  365. for (p=mess; *p;) {
  366. int found = 0;
  367. for (i=0; i<expr2_token_equivs_entries; i++) {
  368. if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
  369. *s++ = '\'';
  370. for (t=expr2_token_equivs2[i]; *t;) {
  371. *s++ = *t++;
  372. }
  373. *s++ = '\'';
  374. p += strlen(expr2_token_equivs1[i]);
  375. found = 1;
  376. break;
  377. }
  378. }
  379. if( !found )
  380. *s++ = *p++;
  381. }
  382. *s++ = 0;
  383. return res;
  384. }
  385. int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
  386. {
  387. struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
  388. char spacebuf[8000]; /* best safe than sorry */
  389. int i=0;
  390. char *s2 = expr2_token_subst(s);
  391. spacebuf[0] = 0;
  392. for (i = 0; i < (int)(yytext - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); i++) {
  393. spacebuf[i] = ' ';
  394. }
  395. /* uh... assuming yyg is defined, then I can use the yycolumn macro,
  396. which is the same thing as... get this:
  397. yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
  398. I was tempted to just use yy_buf_pos in the STATE, but..., well:
  399. a. the yy_buf_pos is the current position in the buffer, which
  400. may not relate to the entire string/buffer because of the
  401. buffering.
  402. b. but, analysis of the situation is that when you use the
  403. yy_scan_string func, it creates a single buffer the size of
  404. string, so the two would be the same...
  405. so, in the end, the yycolumn macro is available, shorter, therefore easier. */
  406. spacebuf[i++] = '^';
  407. spacebuf[i] = 0;
  408. #ifdef STANDALONE3
  409. /* easier to read in the standalone version */
  410. printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
  411. (extra_error_message_supplied ? extra_error_message : ""), s2, parseio->string, spacebuf);
  412. #else
  413. ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
  414. (extra_error_message_supplied ? extra_error_message : ""), s2, parseio->string, spacebuf);
  415. #endif
  416. #ifndef STANDALONE
  417. ast_log(LOG_WARNING,"If you have questions, please refer to https://wiki.asterisk.org/wiki/display/AST/Channel+Variables\n");
  418. #endif
  419. free(s2);
  420. return(0);
  421. }