PageRenderTime 53ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/callweaver-1.2.1/corelib/callweaver_expr2.l

https://github.com/claymodel/voip-foip
LEX | 401 lines | 306 code | 49 blank | 46 comment | 0 complexity | adce5614a0c56e97592acb2f386227e8 MD5 | raw file
  1. %{
  2. /*
  3. * CallWeaver -- 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.callweaver.org for more information about
  10. * the CallWeaver 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 "callweaver.h"
  24. #include <sys/types.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <locale.h>
  29. #include <ctype.h>
  30. #if !defined(SOLARIS) && !defined(__CYGWIN__)
  31. #include <err.h>
  32. #else
  33. #define quad_t int64_t
  34. #endif
  35. #include <errno.h>
  36. #include <regex.h>
  37. #include <limits.h>
  38. #include "callweaver/callweaver_expr.h"
  39. #include "callweaver/logger.h"
  40. #include "callweaver/strings.h"
  41. enum valtype {
  42. CW_EXPR_integer, CW_EXPR_numeric_string, CW_EXPR_string
  43. } ;
  44. struct val {
  45. enum valtype type;
  46. union {
  47. char *s;
  48. quad_t i;
  49. } u;
  50. } ;
  51. #include "callweaver_expr2.h" /* the o/p of the bison on callweaver_expr2.y */
  52. #define SET_COLUMNS do { \
  53. yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
  54. yylloc_param->last_column += yyleng - 1; \
  55. yylloc_param->first_line = yylloc_param->last_line = 1; \
  56. } while (0)
  57. #define SET_STRING do { \
  58. yylval_param->val = calloc(1, sizeof(struct val)); \
  59. yylval_param->val->type = CW_EXPR_string; \
  60. yylval_param->val->u.s = strdup(yytext); \
  61. } while (0)
  62. #define SET_NUMERIC_STRING do { \
  63. yylval_param->val = calloc(1, sizeof(struct val)); \
  64. yylval_param->val->type = CW_EXPR_numeric_string; \
  65. yylval_param->val->u.s = strdup(yytext); \
  66. } while (0)
  67. struct parse_io
  68. {
  69. char *string;
  70. struct val *val;
  71. yyscan_t scanner;
  72. };
  73. void cw_yyset_column(int column_no, yyscan_t yyscanner);
  74. int cw_yyget_column(yyscan_t yyscanner);
  75. static int curlycount = 0;
  76. static char *expr2_token_subst(char *mess);
  77. %}
  78. %option prefix="cw_yy"
  79. %option batch
  80. %option outfile="callweaver_expr2f.c"
  81. %option reentrant
  82. %option bison-bridge
  83. %option bison-locations
  84. %option noyywrap
  85. %x var trail
  86. %%
  87. \| { SET_COLUMNS; SET_STRING; return TOK_OR;}
  88. \& { SET_COLUMNS; SET_STRING; return TOK_AND;}
  89. \= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
  90. \|\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
  91. \&\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
  92. \=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
  93. \=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
  94. \> { SET_COLUMNS; SET_STRING; return TOK_GT;}
  95. \< { SET_COLUMNS; SET_STRING; return TOK_LT;}
  96. \>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
  97. \<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
  98. \!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
  99. \+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
  100. \- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
  101. \* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
  102. \/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
  103. \% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
  104. \? { SET_COLUMNS; SET_STRING; return TOK_COND;}
  105. \! { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
  106. \: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
  107. \:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
  108. \( { SET_COLUMNS; SET_STRING; return TOK_LP;}
  109. \) { SET_COLUMNS; SET_STRING; return TOK_RP;}
  110. \$\{ {
  111. /* gather the contents of ${} expressions, with trailing stuff,
  112. * into a single TOKEN.
  113. * They are much more complex now than they used to be
  114. */
  115. curlycount = 0;
  116. BEGIN(var);
  117. yymore();
  118. }
  119. [ \t\r] {}
  120. \"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
  121. [\n] {/* what to do with eol */}
  122. [0-9]+ {
  123. SET_COLUMNS;
  124. /* the original behavior of the expression parser was
  125. * to bring in numbers as a numeric string
  126. */
  127. SET_NUMERIC_STRING;
  128. return TOKEN;
  129. }
  130. [a-zA-Z0-9,.';\\_^$#@]+ {
  131. SET_COLUMNS;
  132. SET_STRING;
  133. return TOKEN;
  134. }
  135. <var>[^{}]*\} {
  136. curlycount--;
  137. if (curlycount < 0) {
  138. BEGIN(trail);
  139. yymore();
  140. } else {
  141. yymore();
  142. }
  143. }
  144. <var>[^{}]*\{ {
  145. curlycount++;
  146. yymore();
  147. }
  148. <trail>[^-\t\r \n$():?%/+=*<>!|&]* {
  149. BEGIN(0);
  150. SET_COLUMNS;
  151. SET_STRING;
  152. return TOKEN;
  153. }
  154. <trail>[-\t\r \n$():?%/+=*<>!|&] {
  155. char c = yytext[yyleng-1];
  156. BEGIN(0);
  157. unput(c);
  158. SET_COLUMNS;
  159. SET_STRING;
  160. return TOKEN;
  161. }
  162. <trail>\$\{ {
  163. curlycount = 0;
  164. BEGIN(var);
  165. yymore();
  166. }
  167. <trail><<EOF>> {
  168. BEGIN(0);
  169. SET_COLUMNS;
  170. SET_STRING;
  171. return TOKEN;
  172. /*actually, if an expr is only a variable ref, this could happen a LOT */
  173. }
  174. %%
  175. /* I'm putting the interface routine to the whole parse here in the flexer input file
  176. mainly because of all the flexer initialization that has to be done. Shouldn't matter
  177. where it is, as long as it's somewhere. I didn't want to define a prototype for the
  178. cw_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
  179. UGH! that would be inappropriate. */
  180. int cw_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
  181. int cw_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
  182. int cw_expr(char *expr, char *buf, int length)
  183. {
  184. struct parse_io io;
  185. int return_value = 0;
  186. memset(&io, 0, sizeof(io));
  187. io.string = expr; /* to pass to the error routine */
  188. cw_yylex_init(&io.scanner);
  189. cw_yy_scan_string(expr, io.scanner);
  190. cw_yyparse ((void *) &io);
  191. cw_yylex_destroy(io.scanner);
  192. if (!io.val) {
  193. if (length > 1) {
  194. strcpy(buf, "0");
  195. return_value = 1;
  196. }
  197. } else {
  198. if (io.val->type == CW_EXPR_integer) {
  199. int res_length;
  200. res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
  201. return_value = (res_length <= length) ? res_length : length;
  202. } else {
  203. #ifdef STANDALONE
  204. strncpy(buf, io.val->u.s, length - 1);
  205. #else /* !STANDALONE */
  206. cw_copy_string(buf, io.val->u.s, length);
  207. #endif /* STANDALONE */
  208. return_value = strlen(buf);
  209. free(io.val->u.s);
  210. }
  211. free(io.val);
  212. }
  213. return return_value;
  214. }
  215. char extra_error_message[4095];
  216. int extra_error_message_supplied = 0;
  217. void cw_expr_register_extra_error_info(char *message);
  218. void cw_expr_clear_extra_error_info(void);
  219. void cw_expr_register_extra_error_info(char *message)
  220. {
  221. extra_error_message_supplied=1;
  222. strcpy(extra_error_message, message);
  223. }
  224. void cw_expr_clear_extra_error_info(void)
  225. {
  226. extra_error_message_supplied=0;
  227. extra_error_message[0] = 0;
  228. }
  229. static char *expr2_token_equivs1[] =
  230. {
  231. "TOKEN",
  232. "TOK_COND",
  233. "TOK_COLONCOLON",
  234. "TOK_OR",
  235. "TOK_AND",
  236. "TOK_EQ",
  237. "TOK_GT",
  238. "TOK_LT",
  239. "TOK_GE",
  240. "TOK_LE",
  241. "TOK_NE",
  242. "TOK_PLUS",
  243. "TOK_MINUS",
  244. "TOK_MULT",
  245. "TOK_DIV",
  246. "TOK_MOD",
  247. "TOK_COMPL",
  248. "TOK_COLON",
  249. "TOK_EQTILDE",
  250. "TOK_RP",
  251. "TOK_LP"
  252. };
  253. static char *expr2_token_equivs2[] =
  254. {
  255. "<token>",
  256. "?",
  257. "::",
  258. "|",
  259. "&",
  260. "=",
  261. ">",
  262. "<",
  263. ">=",
  264. "<=",
  265. "!=",
  266. "+",
  267. "-",
  268. "*",
  269. "/",
  270. "%",
  271. "!",
  272. ":",
  273. "=~",
  274. ")",
  275. "("
  276. };
  277. static char *expr2_token_subst(char *mess)
  278. {
  279. /* calc a length, malloc, fill, and return; yyerror had better free it! */
  280. int len=0,i;
  281. char *p;
  282. char *res, *s,*t;
  283. int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
  284. for (p=mess; *p; p++) {
  285. for (i=0; i<expr2_token_equivs_entries; i++) {
  286. if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
  287. {
  288. len+=strlen(expr2_token_equivs2[i])+2;
  289. p += strlen(expr2_token_equivs1[i])-1;
  290. break;
  291. }
  292. }
  293. len++;
  294. }
  295. res = (char*)malloc(len+1);
  296. res[0] = 0;
  297. s = res;
  298. for (p=mess; *p;) {
  299. int found = 0;
  300. for (i=0; i<expr2_token_equivs_entries; i++) {
  301. if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
  302. *s++ = '\'';
  303. for (t=expr2_token_equivs2[i]; *t;) {
  304. *s++ = *t++;
  305. }
  306. *s++ = '\'';
  307. p += strlen(expr2_token_equivs1[i]);
  308. found = 1;
  309. break;
  310. }
  311. }
  312. if( !found )
  313. *s++ = *p++;
  314. }
  315. *s++ = 0;
  316. return res;
  317. }
  318. int cw_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
  319. {
  320. struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
  321. char spacebuf[8000]; /* best safe than sorry */
  322. char spacebuf2[8000]; /* best safe than sorry */
  323. int i=0;
  324. char *s2 = expr2_token_subst((char *)s);
  325. spacebuf[0] = 0;
  326. for(i=0;i< (int)(yytext - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);i++) spacebuf2[i] = ' '; /* uh... assuming yyg is defined, then I can use the yycolumn macro,
  327. which is the same thing as... get this:
  328. yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
  329. I was tempted to just use yy_buf_pos in the STATE, but..., well:
  330. a. the yy_buf_pos is the current position in the buffer, which
  331. may not relate to the entire string/buffer because of the
  332. buffering.
  333. b. but, analysis of the situation is that when you use the
  334. yy_scan_string func, it creates a single buffer the size of
  335. string, so the two would be the same...
  336. so, in the end, the yycolumn macro is available, shorter, therefore easier. */
  337. spacebuf2[i++]='^';
  338. spacebuf2[i]= 0;
  339. #ifdef STANDALONE3
  340. /* easier to read in the standalone version */
  341. printf("cw_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
  342. (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
  343. #else
  344. cw_log(LOG_WARNING,"cw_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
  345. (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
  346. #endif
  347. #ifndef STANDALONE
  348. cw_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the callweaver source.\n");
  349. #endif
  350. free(s2);
  351. return(0);
  352. }