Advertisement
KeiroD

RPGServ

Apr 1st, 2015
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 57.83 KB | None | 0 0
  1. #include "module.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <stack>
  8. #include <utility>
  9. #include <cctype>
  10. #include <limits.h>
  11. #ifdef _WIN32
  12. # include <float.h>
  13. #endif
  14. #include <cmath>
  15. #include "hashcomp.h"
  16. #ifdef tolower
  17. # undef tolower
  18. #endif
  19. #ifdef max
  20. # undef max
  21. #endif
  22. #ifdef min
  23. # undef min
  24. #endif
  25.  
  26. static const int DICE_MAX_TIMES = 25;
  27. static const unsigned DICE_MAX_DICE = 99999;
  28. static const unsigned DICE_MAX_SIDES = 99999;
  29. enum DICE_ERRS /* Error codes */
  30. {
  31. DICE_ERR_NONE,
  32. DICE_ERR_PARSE,
  33. DICE_ERR_DIV0,
  34. DICE_ERR_UNDEFINED,
  35. DICE_ERR_UNACCEPT_DICE,
  36. DICE_ERR_UNACCEPT_SIDES,
  37. DICE_ERR_OVERUNDERFLOW,
  38. DICE_ERR_STACK
  39. };
  40. enum DICE_TYPES /* Roll types */
  41. {
  42. DICE_TYPE_ROLL,
  43. DICE_TYPE_CALC,
  44. DICE_TYPE_EXROLL,
  45. DICE_TYPE_EXCALC,
  46. DICE_TYPE_DND3E,
  47. DICE_TYPE_EARTHDAWN
  48. };
  49.  
  50.  
  51.  
  52. static DICE_ERRS DiceErrCode; /* Error code, see DICE_ERRS above */
  53. static int DiceErrNum; /* Value that caused last error, if needed */
  54. static unsigned DiceErrPos; /* Position of last error, if needed */
  55. static Anope::string DiceExOutput, /* Extended output string */
  56. DiceShortExOutput, /* Shorter extended output string */
  57. RollSource, /* Source of the roll when SourceIsBot is set */
  58. DiceErrStr; /* Error string */
  59.  
  60.  
  61. int ran(int k)
  62. {
  63. double x = RAND_MAX + 1.0;
  64. int y;
  65. y = 1 + rand() * (k / x);
  66. return ( y );
  67. }
  68.  
  69. int Dice(int many, unsigned sides)
  70. {
  71. int i,q=0;
  72. if(many>10000)
  73. many=10000;
  74. if(sides>1000000)
  75. sides=1000000;
  76. for (i=0;i<many;i++) {
  77. q += ran(sides);;
  78. }
  79. return ( q );
  80. }
  81.  
  82. static const int MERS_N = 624;
  83. static const int MERS_M = 397;
  84. static const int MERS_R = 31;
  85. static const int MERS_U = 11;
  86. static const int MERS_S = 7;
  87. static const int MERS_T = 15;
  88. static const int MERS_L = 18;
  89. static const int MERS_A = 0x9908B0DF;
  90. static const int MERS_B = 0x9D2C5680;
  91. static const int MERS_C = 0xEFC60000;
  92.  
  93. static int mt[MERS_N]; /* State vector */
  94. static int mti; /* Index into mt */
  95.  
  96.  
  97. /** Determine if the double-precision floating point value is infinite or not.
  98. * @param num The double-precision floating point value to check
  99. * @return true if the value is infinite, false otherwise
  100. */
  101. static bool is_infinite(double num)
  102. {
  103. #ifdef _WIN32
  104. int fpc = _fpclass(num);
  105. return fpc == _FPCLASS_NINF || fpc == _FPCLASS_PINF;
  106. #else
  107. return std::isinf(num);
  108. #endif
  109. }
  110.  
  111. /** Determine if the double-precision floating point value is NaN (Not a Number) or not.
  112. * @param num The double-precision floating point value to check
  113. * @return true if the value is NaN, false otherwise
  114. */
  115. static bool is_notanumber(double num)
  116. {
  117. #ifdef _WIN32
  118. int fpc = _fpclass(num);
  119. return fpc == _FPCLASS_SNAN || fpc == _FPCLASS_QNAN;
  120. #else
  121. return std::isnan(num);
  122. #endif
  123. }
  124.  
  125. #ifdef _WIN32
  126. /** Calculate inverse hyperbolic cosine for Windows.
  127. * @param num The double-precision floating point value to calculate
  128. * @return The inverse hyperbolic cosine of the value
  129. */
  130. static double acosh(double num)
  131. {
  132. return log(num + sqrt(num - 1) * sqrt(num + 1));
  133. }
  134.  
  135. /** Calculate inverse hyperbolic sine for Windows.
  136. * @param num The double-precision floating point value to calculate
  137. * @return The inverse hyperbolic sine of the value
  138. */
  139. static double asinh(double num)
  140. {
  141. return log(num + sqrt(num * num + 1));
  142. }
  143.  
  144. /** Calculate inverse hyperbolic tangent for Windows.
  145. * @param num The double-precision floating point value to calculate
  146. * @return The inverse hyperbolic tangent of the value
  147. */
  148. static double atanh(double num)
  149. {
  150. return 0.5 * log((1 + num) / (1 - num));
  151. }
  152.  
  153. /** Calculate cube root for Windows.
  154. * @param num The double-percision floating point value to calculate
  155. * @return The cube root of the value
  156. */
  157. static double cbrt(double num)
  158. {
  159. return pow(num, 1.0 / 3.0);
  160. }
  161.  
  162. /** Truncate a double-precision floating point value for Windows.
  163. * @param num The double-precision floating point value to truncate
  164. * @return The truncated value
  165. */
  166. static double trunc(double num)
  167. {
  168. return static_cast<double>(static_cast<int>(num));
  169. }
  170. #endif
  171. /** Determine if the given character is a number.
  172. * @param chr Character to check
  173. * @return true if the character is a number, false otherwise
  174. */
  175. inline static bool is_number(char chr) { return (chr >= '0' && chr <= '9') || chr == '.'; }
  176. /** Determine if the given character is a multiplication or division operator.
  177. * @param chr Character to check
  178. * @return true if the character is a multiplication or division operator, false otherwise
  179. */
  180. inline static bool is_muldiv(char chr) { return chr == '%' || chr == '/' || chr == '*'; }
  181. /** Determine if the given character is an addition or subtraction operator.
  182. * @param chr Character to check
  183. * @return true if the character is an addition or subtraction operator, false otherwise
  184. */
  185. inline static bool is_plusmin(char chr) { return chr == '+' || chr == '-'; }
  186. /** Determine if the given character is an operator of any sort, except for parenthesis.
  187. * @param chr Character to check
  188. * @return true if the character is a non-parenthesis operator, false otherwise
  189. */
  190. inline static bool is_op_noparen(char chr) { return is_plusmin(chr) || is_muldiv(chr) || chr == '^' || chr == 'd'; }
  191. /** Determine if the given character is an operator of any sort.
  192. * @param chr Character to check
  193. * @return true if the character is an operator, false otherwise
  194. */
  195. inline static bool is_operator(char chr) { return chr == '(' || chr == ')' || is_op_noparen(chr); }
  196. /** Determine if the substring portion of the given string is a function.
  197. * @param str String to check
  198. * @param pos Starting position of the substring to check, defaults to 0
  199. * @return 0 if the string isn't a function, or a number corresponding to the length of the function name
  200. */
  201. inline static unsigned is_function(const Anope::string &str, unsigned pos = 0)
  202. {
  203. /* We only need a 5 character substring as that's the largest substring we will be looking at */
  204. Anope::string func = str.substr(pos, 5);
  205. /* acosh, asinh, atanh, floor, log10, round, trunc */
  206. Anope::string func_5 = func.substr(0, 5);
  207. if (func_5.equals_ci("acosh") || func_5.equals_ci("asinh") || func_5.equals_ci("atanh") || func_5.equals_ci("floor") || func_5.equals_ci("log10") || func_5.equals_ci("round") || func_5.equals_ci("trunc"))
  208. return 5;
  209. /* acos, asin, atan, cbrt, ceil, cosh, rand, sinh, sqrt, tanh */
  210. Anope::string func_4 = func.substr(0, 4);
  211. if (func_4.equals_ci("acos") || func_4.equals_ci("asin") ||
  212. func_4.equals_ci("atan") || func_4.equals_ci("cbrt") ||
  213. func_4.equals_ci("ceil") || func_4.equals_ci("cosh") ||
  214. func_4.equals_ci("rand") || func_4.equals_ci("sinh") ||
  215. func_4.equals_ci("sqrt") || func_4.equals_ci("tanh"))
  216. return 4;
  217. /* abs, cos, deg, exp, fac, log, max, min, rad, sin, tan */
  218. Anope::string func_3 = func.substr(0, 3);
  219. if (func_3.equals_ci("abs") || func_3.equals_ci("cos") || func_3.equals_ci("deg") ||
  220. func_3.equals_ci("exp") || func_3.equals_ci("fac") || func_3.equals_ci("log") ||
  221. func_3.equals_ci("max") || func_3.equals_ci("min") || func_3.equals_ci("rad") ||
  222. func_3.equals_ci("sin") || func_3.equals_ci("tan"))
  223. return 3;
  224. /* None of the above */
  225. return 0;
  226. }
  227. /** Determine the number of arguments that the given function needs.
  228. * @param str Function string to check
  229. * @return Returns 1 except for the min, max, and rand functions which return 2.
  230. */
  231. inline static unsigned function_argument_count(const Anope::string &str)
  232. {
  233. if (str.equals_ci("max") || str.equals_ci("min") || str.equals_ci("rand"))
  234. return 2;
  235. return 1;
  236. }
  237. /** Determine if the substring portion of the given string is a constant (currently only e and pi).
  238. * @param str String to check
  239. * @param pos Starting position of the substring to check, defaults to 0
  240. * @return 0 if the string isn't a constant, or a number corresponding to the length of the constant's name
  241. */
  242. inline static unsigned is_constant(const Anope::string &str, unsigned pos = 0)
  243. {
  244. /* We only need a 2 character substring as that's the largest substring we will be looking at */
  245. Anope::string constant = str.substr(pos, 2);
  246. /* pi */
  247. if (constant.substr(0, 2).equals_ci("pi"))
  248. return 2;
  249. /* e */
  250. if (constant.substr(0, 1).equals_ci("e"))
  251. return 1;
  252. /* None of the above */
  253. return 0;
  254. }
  255. /** Determine if the given operator has a higher precendence than the operator on the top of the stack during infix to postfix conversion.
  256. * @param adding The operator we are adding to the stack, or an empty string if nothing is being added and we just want to remove
  257. * @param topstack The operator that was at the top of the operator stack
  258. * @return 0 if the given operator has the same or lower precendence (and won't cause a pop), 1 if the operator has higher precendence (and will cause a pop)
  259. *
  260. * In addition to the above in regards to the return value, there are other situations. If the top of the stack is an open parenthesis,
  261. * or is empty, a 0 will be returned to stop the stack from popping anything else. If nothing is being added to the stack and the previous
  262. * sitation hasn't occurred, a 1 will be returned to signify to continue popping the stack until the previous sitation occurs. If the operator
  263. * being added is a function, we return 0 to signify we aren't popping. If the top of the stack is a function, we return 1 to signify we are
  264. * popping. A -1 is only returned if an invalid operator is given, hopefully that will never happen.
  265. */
  266. inline static int would_pop(const Anope::string &adding, const Anope::string &topstack)
  267. {
  268. if (adding.empty())
  269. return topstack.empty() || topstack == "(" ? 0 : 1;
  270. if (is_function(adding))
  271. return 0;
  272. if (topstack.empty() || topstack == "(")
  273. return 0;
  274. if (is_function(topstack))
  275. return 1;
  276. if (topstack == adding && adding != "^")
  277. return 1;
  278. switch (adding[0])
  279. {
  280. case 'd':
  281. return 0;
  282. case '^':
  283. return topstack == "^" || topstack.equals_ci("d") ? 1 : 0;
  284. case '%':
  285. case '/':
  286. case '*':
  287. return topstack == "^" || topstack.equals_ci("d") || is_muldiv(topstack[0]) ? 1 : 0;
  288. case '+':
  289. case '-':
  290. return is_op_noparen(topstack[0]) ? 1 : 0;
  291. }
  292. return -1;
  293. }
  294. /** Convert a double-precision floating point value to a string.
  295. * @param num The value to convert
  296. * @return A string containing the value
  297. */
  298. static Anope::string dtoa(double num)
  299. {
  300. char temp[33];
  301. snprintf(temp, sizeof(temp), "%.*g", static_cast<int>(sizeof(temp) - 7), num);
  302. return temp;
  303. }
  304.  
  305. /** Round a value to the given number of decimals, originally needed for Windows but also used for other OSes as well due to undefined references.
  306. * @param val The value to round
  307. * @param decimals The number of digits after the decimal point, defaults to 0
  308. * @return The rounded value
  309. *
  310. * NOTE: Function is a slightly modified form of the code from this page:
  311. * http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/a7d4bf31-6c32-4b25-bc76-21b29f5287a1/
  312. */
  313. static double my_round(double val, unsigned decimals = 0)
  314. {
  315. if (!val) /* val must be different from zero to avoid division by zero! */
  316. return 0;
  317. double sign = fabs(val) / val; /* we obtain the sign to calculate positive always */
  318. double tempval = fabs(val * pow(10.0, static_cast<double>(decimals))); /* shift decimal places */
  319. unsigned tempint = static_cast<unsigned>(tempval);
  320. double decimalpart = tempval - tempint; /* obtain just the decimal part */
  321. if (decimalpart >= 0.5)
  322. tempval = ceil(tempval); /* next integer number if greater or equal to 0.5 */
  323. else
  324. tempval = floor(tempval); /* otherwise stay in the current interger part */
  325. return (tempval * pow(10.0, static_cast<double>(-static_cast<int>(decimals)))) * sign; /* shift again to the normal decimal places */
  326. }
  327.  
  328. /** Structure to store the infix notation string as well as the positions each character is compared to the original input */
  329. struct Infix
  330. {
  331. Anope::string str;
  332. std::vector<unsigned> positions;
  333. Infix(const Anope::string &newStr, std::vector<unsigned> newPositions)
  334. {
  335. this->str = newStr;
  336. this->positions = newPositions;
  337. }
  338. Infix(const Anope::string &newStr, unsigned newPositions[], unsigned num)
  339. {
  340. this->str = newStr;
  341. this->positions = std::vector<unsigned>(newPositions, newPositions + sizeof(unsigned) * num);
  342. }
  343. };
  344. /** Fix an infix notation equation.
  345. * @param infix The original infix notation equation
  346. * @return A fixed infix notation equation
  347. *
  348. * This will convert a single % to 1d100, place a 1 in front of any d's that have no numbers before them, change all %'s after a d into 100,
  349. * add *'s for implicit multiplication, and convert unary -'s to _ for easier parsing later.
  350. */
  351. static Infix fix_infix(const Anope::string &infix)
  352. {
  353. if (infix == "%")
  354. {
  355. unsigned tmp[] = {0, 0, 0, 0, 0};
  356. Infix newinfix("1d100", tmp, 5);
  357. return newinfix;
  358. }
  359. bool prev_was_func = false, prev_was_const = false;
  360. Anope::string newinfix;
  361. std::vector<unsigned> positions;
  362. unsigned len = infix.length();
  363. for (unsigned x = 0; x < len; ++x)
  364. {
  365. /* Check for a function, and skip it if it exists */
  366. unsigned func = is_function(infix, x);
  367. if (func)
  368. {
  369. if (x && is_number(infix[x - 1]))
  370. {
  371. newinfix += '*';
  372. positions.push_back(x);
  373. }
  374. newinfix += infix.substr(x, func);
  375. for (unsigned y = 0; y < func; ++y)
  376. positions.push_back(x + y);
  377. x += func - 1;
  378. prev_was_func = true;
  379. continue;
  380. }
  381. /* Check for a constant, and skip it if it exists */
  382. unsigned constant = is_constant(infix, x);
  383. if (constant)
  384. {
  385. if (x && is_number(infix[x - 1]))
  386. {
  387. newinfix += '*';
  388. positions.push_back(x);
  389. }
  390. newinfix += infix.substr(x, constant);
  391. for (unsigned y = 0; y < constant; ++y)
  392. positions.push_back(x + y);
  393. if (x + constant < len && (is_number(infix[x + constant]) || is_constant(infix, x + constant) || is_function(infix, x + constant)))
  394. {
  395. newinfix += '*';
  396. positions.push_back(x + constant);
  397. }
  398. x += constant - 1;
  399. prev_was_const = true;
  400. continue;
  401. }
  402. char curr = std::tolower(infix[x]);
  403. if (curr == 'd')
  404. {
  405. positions.push_back(x);
  406. if (!x)
  407. {
  408. newinfix += "1d";
  409. positions.push_back(x);
  410. }
  411. else
  412. {
  413. if (!is_number(infix[x - 1]) && infix[x - 1] != ')' && !prev_was_const)
  414. {
  415. newinfix += '1';
  416. positions.push_back(x);
  417. }
  418. newinfix += 'd';
  419. }
  420. if (x != len - 1 && infix[x + 1] == '%')
  421. {
  422. newinfix += "100";
  423. ++x;
  424. positions.push_back(x);
  425. positions.push_back(x);
  426. }
  427. }
  428. else if (curr == '(')
  429. {
  430. if (x && !prev_was_func && (is_number(infix[x - 1]) || prev_was_const))
  431. {
  432. newinfix += '*';
  433. positions.push_back(x);
  434. }
  435. newinfix += '(';
  436. positions.push_back(x);
  437. }
  438. else if (curr == ')')
  439. {
  440. newinfix += ')';
  441. positions.push_back(x);
  442. if (x != len - 1 && (is_number(infix[x + 1]) || infix[x + 1] == '(' || is_constant(infix, x + 1)))
  443. {
  444. newinfix += '*';
  445. positions.push_back(x);
  446. }
  447. }
  448. else if (curr == '-')
  449. {
  450. positions.push_back(x);
  451. if (x != len - 1 && (!x ? 1 : is_op_noparen(std::tolower(infix[x - 1])) || infix[x - 1] == '(' || infix[x - 1] == ','))
  452. {
  453. if (infix[x + 1] == '(' || is_function(infix, x + 1))
  454. {
  455. newinfix += "0-";
  456. positions.push_back(x);
  457. }
  458. else if (is_number(infix[x + 1]) || is_constant(infix, x + 1))
  459. newinfix += '_';
  460. else
  461. newinfix += '-';
  462. }
  463. else
  464. newinfix += '-';
  465. }
  466. else
  467. {
  468. newinfix += curr;
  469. positions.push_back(x);
  470. }
  471. prev_was_func = prev_was_const = false;
  472. }
  473. positions.push_back(len);
  474. return Infix(newinfix, positions);
  475. }
  476. /** Validate an infix notation equation.
  477. * @param infix The infix notation equation to validate
  478. * @return false for an invalid equation, true for a valid one
  479. *
  480. * The validation is as follows:
  481. * - All functions must have an open parenthesis after them.
  482. * - A comma must be prefixed by a number or close parenthesis and must be suffixed by a number, open parenthesis, _ for unary minus, constant, or function.
  483. * - All non-parentheis operators must be prefixed by a number or close parenthesis and suffixed by a number, open parenthesis, _ for unary minus, constant, or function.
  484. * - All open parentheses must be prefixed by an operator, open parenthesis, or comma and suffixed by a number, an open parenthesis, _ for unary minus, constant, or function.
  485. * - All close parentheses must be prefixed by a number or close parenthesis and suffixed by an operator, close parenthesis, or comma.
  486. */
  487. static bool check_infix(const Infix &infix)
  488. {
  489. bool prev_was_func = false, prev_was_const = false;
  490. for (unsigned x = 0, len = infix.str.length(); x < len; ++x)
  491. {
  492. unsigned position = infix.positions[x];
  493. /* Check for a function, and skip it if it exists */
  494. unsigned func = is_function(infix.str, x);
  495. if (func)
  496. {
  497. if ((x + func < len && infix.str[x + func] != '(') || x + func >= len)
  498. {
  499. DiceErrPos = infix.positions[x + func >= len ? len : x + func];
  500. DiceErrCode = DICE_ERR_PARSE;
  501. DiceErrStr = _("No open parenthesis found after function.");
  502. return false;
  503. }
  504. x += func - 1;
  505. prev_was_func = true;
  506. continue;
  507. }
  508. /* Check for a constant, and skip it if it exists */
  509. unsigned constant = is_constant(infix.str, x);
  510. if (constant)
  511. {
  512. x += constant - 1;
  513. prev_was_const = true;
  514. continue;
  515. }
  516. if (infix.str[x] == ',')
  517. {
  518. if (!x ? 1 : !is_number(infix.str[x - 1]) && infix.str[x - 1] != ')' && !prev_was_const)
  519. {
  520. DiceErrPos = position;
  521. DiceErrCode = DICE_ERR_PARSE;
  522. DiceErrStr = _("No number or close parenthesis before comma.");
  523. return false;
  524. }
  525. if (x == len - 1 ? 1 : !is_number(infix.str[x + 1]) && infix.str[x + 1] != '(' && infix.str[x + 1] != '_' && !is_constant(infix.str, x + 1) && !is_function(infix.str, x + 1))
  526. {
  527. DiceErrPos = position;
  528. DiceErrCode = DICE_ERR_PARSE;
  529. DiceErrStr = _("No number or open parenthesis after comma.");
  530. return false;
  531. }
  532. }
  533. else if (is_op_noparen(infix.str[x]))
  534. {
  535. if (!x ? 1 : !is_number(infix.str[x - 1]) && infix.str[x - 1] != ')' && !prev_was_const)
  536. {
  537. DiceErrPos = position;
  538. DiceErrCode = DICE_ERR_PARSE;
  539. DiceErrStr = _("No number or close parenthesis before operator.");
  540. return false;
  541. }
  542. if (x == len - 1 ? 1 : !is_number(infix.str[x + 1]) && infix.str[x + 1] != '(' && infix.str[x + 1] != '_' && !is_constant(infix.str, x + 1) && !is_function(infix.str, x + 1))
  543. {
  544. DiceErrPos = position;
  545. DiceErrCode = DICE_ERR_PARSE;
  546. DiceErrStr = _("No number or open parenthesis after operator.");
  547. return false;
  548. }
  549. }
  550. else if (infix.str[x] == '(')
  551. {
  552. if (x && !is_op_noparen(infix.str[x - 1]) && infix.str[x - 1] != '(' && infix.str[x - 1] != ',' && !prev_was_func)
  553. {
  554. DiceErrPos = position;
  555. DiceErrCode = DICE_ERR_PARSE;
  556. DiceErrStr = _("No operator or open parenthesis found before current open\nparenthesis.");
  557. return false;
  558. }
  559. if (x != len - 1 && !is_number(infix.str[x + 1]) && infix.str[x + 1] != '(' && infix.str[x + 1] != '_' && !is_constant(infix.str, x + 1) && !is_function(infix.str, x + 1))
  560. {
  561. DiceErrPos = position;
  562. DiceErrCode = DICE_ERR_PARSE;
  563. DiceErrStr = _("No number after current open parenthesis.");
  564. return false;
  565. }
  566. }
  567. else if (infix.str[x] == ')')
  568. {
  569. if (x && !is_number(infix.str[x - 1]) && infix.str[x - 1] != ')' && !prev_was_const)
  570. {
  571. DiceErrPos = position;
  572. DiceErrCode = DICE_ERR_PARSE;
  573. DiceErrStr = _("No number found before current close parenthesis.");
  574. return false;
  575. }
  576. if (x != len - 1 && !is_op_noparen(infix.str[x + 1]) && infix.str[x + 1] != ')' && infix.str[x + 1] != ',')
  577. {
  578. DiceErrPos = position;
  579. DiceErrCode = DICE_ERR_PARSE;
  580. DiceErrStr = _("No operator or close parenthesis found after current close\nparenthesis.");
  581. return false;
  582. }
  583. }
  584. else if (!is_number(infix.str[x]) && !is_muldiv(infix.str[x]) && !is_plusmin(infix.str[x]) && !is_operator(infix.str[x]) && infix.str[x] != '_')
  585. {
  586. DiceErrPos = position;
  587. DiceErrCode = DICE_ERR_PARSE;
  588. DiceErrStr = _("An invalid character was encountered.");
  589. return false;
  590. }
  591. prev_was_func = prev_was_const = false;
  592. }
  593. return true;
  594. }
  595.  
  596.  
  597. /** Tokenize an infix notation equation by adding spaces between operators.
  598. * @param infix The original infix notation equation to tokenize
  599. * @return A new infix notation equation with spaces between operators
  600. */
  601. static Infix tokenize_infix(const Infix &infix)
  602. {
  603. Anope::string newinfix;
  604. std::vector<unsigned> positions;
  605. for (unsigned x = 0, len = infix.str.length(); x < len; ++x)
  606. {
  607. unsigned position = infix.positions[x], func = is_function(infix.str, x), constant = is_constant(infix.str, x);
  608. char curr = infix.str[x];
  609. if (func)
  610. {
  611. if (x && !newinfix.empty() && newinfix[newinfix.length() - 1] != ' ')
  612. {
  613. newinfix += ' ';
  614. positions.push_back(position);
  615. }
  616. newinfix += infix.str.substr(x, func);
  617. for (unsigned y = 0; y < func; ++y)
  618. positions.push_back(infix.positions[x + y]);
  619. if (x != len - 1)
  620. {
  621. newinfix += ' ';
  622. positions.push_back(infix.positions[x + func]);
  623. }
  624. x += func - 1;
  625. }
  626. else if (constant)
  627. {
  628. if (x && !newinfix.empty() && newinfix[newinfix.length() - 1] != ' ' && newinfix[newinfix.length() - 1] != '_')
  629. {
  630. newinfix += ' ';
  631. positions.push_back(position);
  632. }
  633. newinfix += infix.str.substr(x, constant);
  634. for (unsigned y = 0; y < constant; ++y)
  635. positions.push_back(infix.positions[x + y]);
  636. if (x != len - 1)
  637. {
  638. newinfix += ' ';
  639. positions.push_back(infix.positions[x + constant]);
  640. }
  641. x += constant - 1;
  642. }
  643. else if (curr == ',')
  644. {
  645. if (x && !newinfix.empty() && newinfix[newinfix.length() - 1] != ' ')
  646. {
  647. newinfix += ' ';
  648. positions.push_back(position);
  649. }
  650. newinfix += ',';
  651. positions.push_back(position);
  652. if (x != len - 1)
  653. {
  654. newinfix += ' ';
  655. positions.push_back(position);
  656. }
  657. }
  658. else if (is_operator(curr))
  659. {
  660. if (x && !newinfix.empty() && newinfix[newinfix.length() - 1] != ' ')
  661. {
  662. newinfix += ' ';
  663. positions.push_back(position);
  664. }
  665. newinfix += curr;
  666. positions.push_back(position);
  667. if (x != len - 1)
  668. {
  669. newinfix += ' ';
  670. positions.push_back(position);
  671. }
  672. }
  673. else
  674. {
  675. newinfix += curr;
  676. positions.push_back(position);
  677. }
  678. }
  679. return Infix(newinfix, positions);
  680. }
  681.  
  682.  
  683. /** Base class for values in a postfix equation */
  684. class PostfixValueBase
  685. {
  686. public:
  687. PostfixValueBase() { }
  688. virtual ~PostfixValueBase() { }
  689. virtual void Clear() = 0;
  690. };
  691.  
  692. /** Version of PostfixValue for double */
  693. class PostfixValueDouble : public PostfixValueBase
  694. {
  695. double *val;
  696. public:
  697. PostfixValueDouble() : PostfixValueBase(), val(NULL) { }
  698. PostfixValueDouble(double *Val) : PostfixValueBase(), val(Val) { }
  699. PostfixValueDouble(const PostfixValueDouble &Val) : PostfixValueBase(), val(Val.val) { }
  700. PostfixValueDouble &operator=(const PostfixValueDouble &Val)
  701. {
  702. if (this != &Val)
  703. *val = *Val.val;
  704. return *this;
  705. }
  706. const double *Get() const
  707. {
  708. return val;
  709. }
  710. void Clear()
  711. {
  712. delete val;
  713. }
  714. };
  715.  
  716. /** Version of PostfixValue for Anope::string */
  717. class PostfixValueString : public PostfixValueBase
  718. {
  719. Anope::string *val;
  720. public:
  721. PostfixValueString() : PostfixValueBase(), val(NULL) { }
  722. PostfixValueString(Anope::string *Val) : PostfixValueBase(), val(Val) { }
  723. PostfixValueString(const PostfixValueString &Val) : PostfixValueBase(), val(Val.val) { }
  724. PostfixValueString &operator=(const PostfixValueString &Val)
  725. {
  726. if (this != &Val)
  727. *val = *Val.val;
  728. return *this;
  729. }
  730. const Anope::string *Get() const
  731. {
  732. return val;
  733. }
  734. void Clear()
  735. {
  736. delete val;
  737. }
  738. };
  739.  
  740. /** Enumeration for PostfixValue to determine it's type */
  741. enum PostfixValueType
  742. {
  743. POSTFIX_VALUE_DOUBLE,
  744. POSTFIX_VALUE_STRING
  745. };
  746.  
  747. typedef std::vector<std::pair<PostfixValueBase *, PostfixValueType> > Postfix;
  748.  
  749. /** Clears the memory of the given Postfix vector.
  750. * @param postfix The Postfix vector to clean up
  751. */
  752. static void cleanup_postfix(Postfix &postfix)
  753. {
  754. for (unsigned y = 0, len = postfix.size(); y < len; ++y)
  755. {
  756. postfix[y].first->Clear();
  757. delete postfix[y].first;
  758. }
  759. postfix.clear();
  760. }
  761. /** Adds a double value to the Postfix vector.
  762. * @param postfix The Postfix vector to add to
  763. * @param dbl The double value we are adding
  764. */
  765. static void add_to_postfix(Postfix &postfix, double dbl)
  766. {
  767. double *dbl_ptr = new double(dbl);
  768. postfix.push_back(std::make_pair(new PostfixValueDouble(dbl_ptr), POSTFIX_VALUE_DOUBLE));
  769. }
  770. /** Adds an Anope::string value to the Postfix vector.
  771. * * @param postfix The Postfix vector to add to
  772. * * @param str The Anope::string value we are adding
  773. * */
  774. static void add_to_postfix(Postfix &postfix, const Anope::string &str)
  775. {
  776. Anope::string *str_ptr = new Anope::string(str);
  777. postfix.push_back(std::make_pair(new PostfixValueString(str_ptr), POSTFIX_VALUE_STRING));
  778. }
  779. /** Convert an infix notation equation to a postfix notation equation, using the shunting-yard algorithm.
  780. * @param infix The infix notation equation to convert
  781. * @return A postfix notation equation
  782. *
  783. * Numbers are always stored in the postfix notation equation immediately, and operators are kept on a stack until they are
  784. * needed to be added to the postfix notation equation.
  785. * The conversion process goes as follows:
  786. * - Firstly, verify that the end of the input is a number, ignoring close parentheses.
  787. * - Iterate through the infix notation equation, doing the following on each operation:
  788. * - When a _ is encountered, add the number following it to the postfix notation equation, but make sure it's negative.
  789. * - When a number is encountered, add it to the postfix notation equation.
  790. * - When a function is encountered, add it to the operator stack.
  791. * - When a constant is encountered, convert it to a number and add it to the postfix notation equation.
  792. * - When an operator is encountered:
  793. * - Check if we had any numbers prior to the operator, and fail if there were none.
  794. * - Always add open parentheses to the operator stack.
  795. * - When a close parenthesis is encountered, pop all operators until we get to an open parenthesis or the stack
  796. * becomes empty, failing on the latter.
  797. * - For all other operators, pop the stack if needed then add the operator to the stack.
  798. * - When a comma is encountered, do the same as above for when a close parenthesis is encountered, but also check
  799. * to make sure there was a function prior to the open parenthesis (if there is one).
  800. * - If anything else is encountered, fail as it is an invalid value.
  801. * - If there were operators left on the operator stack, pop all of them, failing if anything is left on the stack
  802. * (an open parenthesis will cause this).
  803. */
  804. static Postfix infix_to_postfix(const Infix &infix)
  805. {
  806. Postfix postfix;
  807. unsigned len = infix.str.length(), x = 0;
  808. bool prev_was_close = false, prev_was_number = false;
  809. std::stack<Anope::string> op_stack;
  810. spacesepstream tokens(infix.str);
  811. Anope::string token, lastone;
  812. while (tokens.GetToken(token))
  813. {
  814. if (token[0] == '_')
  815. {
  816. double number = 0.0;
  817. if (is_constant(token, 1))
  818. {
  819. if (token.substr(1).equals_ci("e"))
  820. number = -exp(1.0);
  821. else if (token.substr(1).equals_ci("pi"))
  822. number = -atan(1.0) * 4;
  823. }
  824. else
  825. number = -atof(token.substr(1).c_str());
  826. if (is_infinite(number) || is_notanumber(number))
  827. {
  828. DiceErrCode = is_infinite(number) ? DICE_ERR_OVERUNDERFLOW : DICE_ERR_UNDEFINED;
  829. cleanup_postfix(postfix);
  830. return postfix;
  831. }
  832. add_to_postfix(postfix, number);
  833. prev_was_number = true;
  834. }
  835. else if (is_number(token[0]))
  836. {
  837. double number = atof(token.c_str());
  838. if (is_infinite(number) || is_notanumber(number))
  839. {
  840. DiceErrCode = is_infinite(number) ? DICE_ERR_OVERUNDERFLOW : DICE_ERR_UNDEFINED;
  841. cleanup_postfix(postfix);
  842. return postfix;
  843. }
  844. add_to_postfix(postfix, number);
  845. prev_was_number = true;
  846. }
  847. else if (is_function(token))
  848. op_stack.push(token);
  849. else if (is_constant(token))
  850. {
  851. double number = 0.0;
  852. if (token.equals_ci("e"))
  853. number = exp(1.0);
  854. else if (token.equals_ci("pi"))
  855. number = atan(1.0) * 4;
  856. add_to_postfix(postfix, number);
  857. prev_was_number = true;
  858. }
  859. else if (is_operator(token[0]))
  860. {
  861. lastone = op_stack.empty() ? "" : op_stack.top();
  862. if (!prev_was_number && token != "(" && token != ")" && !prev_was_close)
  863. {
  864. DiceErrPos = infix.positions[x];
  865. DiceErrCode = DICE_ERR_PARSE;
  866. DiceErrStr = _("No numbers were found before the operator was encountered.");
  867. cleanup_postfix(postfix);
  868. return postfix;
  869. }
  870. prev_was_number = false;
  871. if (token == "(")
  872. {
  873. op_stack.push(token);
  874. prev_was_close = false;
  875. }
  876. else if (token == ")")
  877. {
  878. while (would_pop(token, lastone))
  879. {
  880. add_to_postfix(postfix, lastone);
  881. op_stack.pop();
  882. lastone = op_stack.empty() ? "" : op_stack.top();
  883. }
  884. if (lastone != "(")
  885. {
  886. DiceErrPos = infix.positions[x];
  887. DiceErrCode = DICE_ERR_PARSE;
  888. DiceErrStr = _("A close parenthesis was found but not enough open\nparentheses were found before it.");
  889. cleanup_postfix(postfix);
  890. return postfix;
  891. }
  892. else
  893. op_stack.pop();
  894. prev_was_close = true;
  895. }
  896. else
  897. {
  898. if (!would_pop(token, lastone))
  899. op_stack.push(token);
  900. else
  901. {
  902. while (would_pop(token, lastone))
  903. {
  904. add_to_postfix(postfix, lastone);
  905. op_stack.pop();
  906. lastone = op_stack.empty() ? "" : op_stack.top();
  907. }
  908. op_stack.push(token);
  909. }
  910. prev_was_close = false;
  911. }
  912. }
  913. else if (token[0] == ',')
  914. {
  915. lastone = op_stack.empty() ? "" : op_stack.top();
  916. while (would_pop(token, lastone))
  917. {
  918. add_to_postfix(postfix, lastone);
  919. op_stack.pop();
  920. lastone = op_stack.empty() ? "" : op_stack.top();
  921. }
  922. if (lastone != "(")
  923. {
  924. DiceErrPos = infix.positions[x];
  925. DiceErrCode = DICE_ERR_PARSE;
  926. DiceErrStr = _("A comma was encountered outside of a function.");
  927. cleanup_postfix(postfix);
  928. return postfix;
  929. }
  930. else
  931. {
  932. Anope::string paren = lastone;
  933. op_stack.pop();
  934. lastone = op_stack.empty() ? "" : op_stack.top();
  935. if (!is_function(lastone))
  936. {
  937. DiceErrPos = infix.positions[x];
  938. DiceErrCode = DICE_ERR_PARSE;
  939. DiceErrStr = _("A comma was encountered outside of a function.");
  940. cleanup_postfix(postfix);
  941. return postfix;
  942. }
  943. else
  944. op_stack.push(paren);
  945. }
  946. }
  947. else
  948. {
  949. DiceErrPos = infix.positions[x];
  950. DiceErrCode = DICE_ERR_PARSE;
  951. DiceErrStr = _("An invalid character was encountered.");
  952. cleanup_postfix(postfix);
  953. return postfix;
  954. }
  955. x += token.length() + (x ? 1 : 0);
  956. }
  957. if (!op_stack.empty())
  958. {
  959. lastone = op_stack.top();
  960. while (would_pop("", lastone))
  961. {
  962. add_to_postfix(postfix, lastone);
  963. op_stack.pop();
  964. if (op_stack.empty())
  965. break;
  966. else
  967. lastone = op_stack.top();
  968. }
  969. if (!op_stack.empty())
  970. {
  971. DiceErrPos = infix.positions[len];
  972. DiceErrCode = DICE_ERR_PARSE;
  973. DiceErrStr = _("There are more open parentheses than close parentheses.");
  974. cleanup_postfix(postfix);
  975. return postfix;
  976. }
  977. }
  978. return postfix;
  979. }
  980. /** Evaluate a postfix notation equation.
  981. * @param The postfix notation equation to evaluate
  982. * @return The final result after calcuation of the equation
  983. *
  984. * The evaluation pops a single value from the operand stack for a function, and 2 values from the
  985. * operand stack for an operator. The result of either one is placed back on the operand stack,
  986. * hopefully leaving a single result at the end.
  987. */
  988. double eval_postfix(const Postfix &postfix)
  989. {
  990. double val = 0.0;
  991. std::stack<double> num_stack;
  992. for (unsigned x = 0, len = postfix.size(); x < len; ++x)
  993. {
  994. if (postfix[x].second == POSTFIX_VALUE_STRING)
  995. {
  996. const PostfixValueString *str = dynamic_cast<const PostfixValueString *>(postfix[x].first);
  997. const Anope::string *token_ptr = str->Get();
  998. Anope::string token = token_ptr ? *token_ptr : "";
  999. if (token.empty())
  1000. {
  1001. DiceErrCode = DICE_ERR_STACK;
  1002. DiceErrStr = _("An empty token was found.");
  1003. return 0;
  1004. }
  1005. if (is_function(token))
  1006. {
  1007. unsigned function_arguments = function_argument_count(token);
  1008. if (num_stack.empty() || num_stack.size() < function_arguments)
  1009. {
  1010. DiceErrCode = DICE_ERR_STACK;
  1011. DiceErrStr = _("Not enough numbers for function.");
  1012. return 0;
  1013. }
  1014. double val1 = num_stack.top();
  1015. num_stack.pop();
  1016. if (token.equals_ci("abs"))
  1017. val = fabs(val1);
  1018. else if (token.equals_ci("acos"))
  1019. {
  1020. if (fabs(val1) > 1)
  1021. {
  1022. DiceErrCode = DICE_ERR_UNDEFINED;
  1023. return 0;
  1024. }
  1025. val = acos(val1);
  1026. }
  1027. else if (token.equals_ci("acosh"))
  1028. {
  1029. if (val1 < 1)
  1030. {
  1031. DiceErrCode = DICE_ERR_UNDEFINED;
  1032. return 0;
  1033. }
  1034. val = acosh(val1);
  1035. }
  1036. else if (token.equals_ci("asin"))
  1037. {
  1038. if (fabs(val1) > 1)
  1039. {
  1040. DiceErrCode = DICE_ERR_UNDEFINED;
  1041. return 0;
  1042. }
  1043. val = asin(val1);
  1044. }
  1045. else if (token.equals_ci("asinh"))
  1046. val = asinh(val1);
  1047. else if (token.equals_ci("atan"))
  1048. val = atan(val1);
  1049. else if (token.equals_ci("atanh"))
  1050. {
  1051. if (fabs(val1) >= 1)
  1052. {
  1053. DiceErrCode = fabs(val1) == 1 ? DICE_ERR_DIV0 : DICE_ERR_UNDEFINED;
  1054. return 0;
  1055. }
  1056. val = atanh(val1);
  1057. }
  1058. else if (token.equals_ci("cbrt"))
  1059. val = cbrt(val1);
  1060. else if (token.equals_ci("ceil"))
  1061. val = ceil(val1);
  1062. else if (token.equals_ci("cos"))
  1063. val = cos(val1);
  1064. else if (token.equals_ci("cosh"))
  1065. val = cosh(val1);
  1066. else if (token.equals_ci("deg"))
  1067. val = val1 * 45.0 / atan(1.0);
  1068. else if (token.equals_ci("exp"))
  1069. val = exp(val1);
  1070. else if (token.equals_ci("fac"))
  1071. {
  1072. if (static_cast<int>(val1) < 0)
  1073. {
  1074. DiceErrCode = DICE_ERR_UNDEFINED;
  1075. return 0;
  1076. }
  1077. val = 1;
  1078. for (unsigned n = 2; n <= static_cast<unsigned>(val1); ++n)
  1079. val *= n;
  1080. }
  1081. else if (token.equals_ci("floor"))
  1082. val = floor(val1);
  1083. else if (token.equals_ci("log"))
  1084. {
  1085. if (val1 <= 0)
  1086. {
  1087. DiceErrCode = DICE_ERR_DIV0;
  1088. return 0;
  1089. }
  1090. val = log(val1);
  1091. }
  1092. else if (token.equals_ci("log10"))
  1093. {
  1094. if (val1 <= 0)
  1095. {
  1096. DiceErrCode = DICE_ERR_DIV0;
  1097. return 0;
  1098. }
  1099. val = log10(val1);
  1100. }
  1101. else if (token.equals_ci("max"))
  1102. {
  1103. double val2 = val1;
  1104. val1 = num_stack.top();
  1105. num_stack.pop();
  1106. val = std::max(val1, val2);
  1107. }
  1108. else if (token.equals_ci("min"))
  1109. {
  1110. double val2 = val1;
  1111. val1 = num_stack.top();
  1112. num_stack.pop();
  1113. val = std::min(val1, val2);
  1114. }
  1115. else if (token.equals_ci("rad"))
  1116. val = val1 * atan(1.0) / 45.0;
  1117. else if (token.equals_ci("rand"))
  1118. {
  1119. double val2 = val1;
  1120. val1 = num_stack.top();
  1121. num_stack.pop();
  1122. if (val1 > val2)
  1123. {
  1124. double tmp = val2;
  1125. val2 = val1;
  1126. val1 = tmp;
  1127. }
  1128. val = Dice(static_cast<int>(val1), static_cast<int>(val2));
  1129. Anope::string buf = Anope::string("rand(") + stringify(static_cast<int>(val1)) + "," + stringify(static_cast<int>(val2)) + ")=(" + stringify(static_cast<int>(val)) + ") ";
  1130. DiceShortExOutput += buf;
  1131. DiceExOutput += buf;
  1132. }
  1133. else if (token.equals_ci("round"))
  1134. val = my_round(val1);
  1135. else if (token.equals_ci("sin"))
  1136. val = sin(val1);
  1137. else if (token.equals_ci("sinh"))
  1138. val = sinh(val1);
  1139. else if (token.equals_ci("sqrt"))
  1140. {
  1141. if (val1 < 0)
  1142. {
  1143. DiceErrCode = DICE_ERR_UNDEFINED;
  1144. return 0;
  1145. }
  1146. val = sqrt(val1);
  1147. }
  1148. else if (token.equals_ci("tan"))
  1149. {
  1150. if (!fmod(val1 + 2 * atan(1.0), atan(1.0) * 4))
  1151. {
  1152. DiceErrCode = DICE_ERR_UNDEFINED;
  1153. return 0;
  1154. }
  1155. val = tan(val1);
  1156. }
  1157. else if (token.equals_ci("tanh"))
  1158. val = tanh(val1);
  1159. else if (token.equals_ci("trunc"))
  1160. val = trunc(val1);
  1161. if (is_infinite(val) || is_notanumber(val))
  1162. {
  1163. DiceErrCode = is_infinite(val) ? DICE_ERR_OVERUNDERFLOW : DICE_ERR_UNDEFINED;
  1164. return 0;
  1165. }
  1166. num_stack.push(val);
  1167. } //end if(is_function)
  1168. else if (is_operator(token[0]) && token.length() == 1)
  1169. {
  1170. if (num_stack.empty() || num_stack.size() < 2)
  1171. {
  1172. DiceErrCode = DICE_ERR_STACK;
  1173. DiceErrStr = _("Not enough numbers for operator.");
  1174. return 0;
  1175. }
  1176. double val2 = num_stack.top();
  1177. num_stack.pop();
  1178. double val1 = num_stack.top();
  1179. num_stack.pop();
  1180. switch (token[0])
  1181. {
  1182. case '+':
  1183. val = val1 + val2;
  1184. break;
  1185. case '-':
  1186. val = val1 - val2;
  1187. break;
  1188. case '*':
  1189. val = val1 * val2;
  1190. break;
  1191. case '/':
  1192. if (!val2)
  1193. {
  1194. DiceErrCode = DICE_ERR_DIV0;
  1195. return 0;
  1196. }
  1197. val = val1 / val2;
  1198. break;
  1199. case '%':
  1200. if (!val2)
  1201. {
  1202. DiceErrCode = DICE_ERR_DIV0;
  1203. return 0;
  1204. }
  1205. val = fmod(val1, val2);
  1206. break;
  1207. case '^':
  1208. if (val1 < 0 && static_cast<double>(static_cast<int>(val2)) != val2)
  1209. {
  1210. DiceErrCode = DICE_ERR_UNDEFINED;
  1211. return 0;
  1212. }
  1213. if (!val1 && !val2)
  1214. {
  1215. DiceErrCode = DICE_ERR_DIV0;
  1216. return 0;
  1217. }
  1218. if (!val1 && val2 < 0)
  1219. {
  1220. DiceErrCode = DICE_ERR_OVERUNDERFLOW;
  1221. return 0;
  1222. }
  1223. val = pow(val1, val2);
  1224. break;
  1225. case 'd':
  1226. if (val1 < 1 || val1 > DICE_MAX_DICE)
  1227. {
  1228. DiceErrCode = DICE_ERR_UNACCEPT_DICE;
  1229. DiceErrNum = static_cast<int>(val1);
  1230. return 0;
  1231. }
  1232. if (val2 < 1 || val2 > DICE_MAX_SIDES)
  1233. {
  1234. DiceErrCode = DICE_ERR_UNACCEPT_SIDES;
  1235. DiceErrNum = static_cast<int>(val2);
  1236. return 0;
  1237. }
  1238. int ival1 = (int)(val1);
  1239. unsigned uval2 = (unsigned)(val2);
  1240. int ival = Dice(ival1, uval2);
  1241. val = (double)(ival);
  1242. break;
  1243. }
  1244. if (is_infinite(val) || is_notanumber(val))
  1245. {
  1246. DiceErrCode = is_infinite(val) ? DICE_ERR_OVERUNDERFLOW : DICE_ERR_UNDEFINED;
  1247. return 0;
  1248. }
  1249. num_stack.push(val);
  1250. }
  1251. }
  1252. else
  1253. {
  1254. const PostfixValueDouble *dbl = dynamic_cast<const PostfixValueDouble *>(postfix[x].first);
  1255. const double *val_ptr = dbl->Get();
  1256. if (!val_ptr)
  1257. {
  1258. DiceErrCode = DICE_ERR_STACK;
  1259. DiceErrStr = _("An empty number was found.");
  1260. return 0;
  1261. }
  1262. num_stack.push(*val_ptr);
  1263. }
  1264. }
  1265. val = num_stack.top();
  1266. num_stack.pop();
  1267. if (!num_stack.empty())
  1268. {
  1269. DiceErrCode = DICE_ERR_STACK;
  1270. DiceErrStr = _("Too many numbers were found as input.");
  1271. return 0;
  1272. }
  1273. return val;
  1274. }
  1275.  
  1276. /** Parse an infix notation expression and convert the expression to postfix notation.
  1277. * @param infix The original expression, in infix notation, to convert to postfix notation
  1278. * @return A postfix notation expression equivilent to the infix notation expression given, or an empty string if the infix notation expression could not be parsed or converted
  1279. */
  1280. Postfix DoParse(const Anope::string &infix)
  1281. {
  1282. Infix infixcpy = fix_infix(infix);
  1283. Postfix postfix;
  1284. if (infixcpy.str.empty())
  1285. return postfix;
  1286. if (!check_infix(infixcpy))
  1287. return postfix;
  1288. Infix tokenized_infix = tokenize_infix(infixcpy);
  1289. if (tokenized_infix.str.empty())
  1290. return postfix;
  1291. postfix = infix_to_postfix(tokenized_infix);
  1292. return postfix;
  1293. }
  1294.  
  1295. /** Evaluate a postfix notation expression.
  1296. * @param postfix The postfix notation expression to evaluate
  1297. * @return The final result after evaluation
  1298. */
  1299. double DoEvaluate(const Postfix &postfix)
  1300. {
  1301. double ret = 0.0;
  1302. DiceErrCode = DICE_ERR_NONE;
  1303. DiceErrPos = 0;
  1304. DiceExOutput.clear();
  1305. DiceShortExOutput.clear();
  1306. ret = eval_postfix(postfix);
  1307. if (ret > INT_MAX || ret < INT_MIN)
  1308. DiceErrCode = DICE_ERR_OVERUNDERFLOW;
  1309. return ret;
  1310. }
  1311.  
  1312. /** DiceServ's error handler, if any step along the way fails, this will display the cause of the error to the user.
  1313. * @param u The user that invoked DiceServ
  1314. * @param dice The dice expression that was used to invoke DiceServ
  1315. * @param ErrorPos The position of the error (usually the same DiceErrPos, but not always)
  1316. * @return true in almost every case to signify there was an error, false if an unknown error code was passed in or no error code was set
  1317. */
  1318. bool ErrorHandler(CommandSource &source, const Anope::string &dice, unsigned ErrorPos)
  1319. {
  1320. bool WasError = true;
  1321. switch (DiceErrCode)
  1322. {
  1323. case DICE_ERR_PARSE:
  1324. {
  1325. source.Reply(_("During parsing, an error was found in the following\nexpression:"));
  1326. source.Reply(" %s", dice.c_str());
  1327. Anope::string spaces(ErrorPos > dice.length() ? dice.length() : ErrorPos+1, '-');
  1328. source.Reply(">%s^", spaces.c_str());
  1329. source.Reply(_("Error description is as follows:"));
  1330. source.Reply("%s", DiceErrStr.c_str());
  1331. break;
  1332. }
  1333. case DICE_ERR_DIV0:
  1334. source.Reply(_("Division by 0 in following expression:"));
  1335. source.Reply(" %s", dice.c_str());
  1336. break;
  1337. case DICE_ERR_UNDEFINED:
  1338. source.Reply(_("Undefined result in following expression:"));
  1339. source.Reply(" %s", dice.c_str());
  1340. break;
  1341. case DICE_ERR_UNACCEPT_DICE:
  1342. if (DiceErrNum <= 0)
  1343. source.Reply(_("The number of dice that you entered (%d) was under\n1. Please enter a number between 1 and %d."), DiceErrNum, DICE_MAX_DICE);
  1344. else
  1345. source.Reply(_("The number of dice that you entered (%d) was over the\nlimit of %d. Please enter a lower number of dice."), DiceErrNum, DICE_MAX_DICE);
  1346. break;
  1347. case DICE_ERR_UNACCEPT_SIDES:
  1348. if (DiceErrNum <= 0)
  1349. source.Reply(_("The number of sides that you entered (%d) was under\n1. Please enter a number between 1 and %d."), DiceErrNum, DICE_MAX_SIDES);
  1350. else
  1351. source.Reply(_("The number of sides that you entered (%d) was over the\nlimit of %d. Please enter a lower number of sides."), DiceErrNum, DICE_MAX_SIDES);
  1352. break;
  1353. case DICE_ERR_OVERUNDERFLOW:
  1354. source.Reply(_("Dice results in following expression resulted in either\noverflow or underflow:"));
  1355. source.Reply(" %s", dice.c_str());
  1356. break;
  1357. case DICE_ERR_STACK:
  1358. source.Reply(_("The following roll expression could not be properly\nevaluated, please try again or let an administrator know."));
  1359. source.Reply(" %s", dice.c_str());
  1360. source.Reply(_("Error description is as follows:"));
  1361. source.Reply("%s", DiceErrStr.c_str());
  1362. break;
  1363. default:
  1364. WasError = false;
  1365. }
  1366. return WasError;
  1367. }
  1368.  
  1369.  
  1370.  
  1371. /*
  1372. * Handle RPGSERVs ROLL command
  1373. */
  1374.  
  1375. class CommandRSRoll : public Command
  1376. {
  1377. public:
  1378. CommandRSRoll(Module *creator) : Command(creator, "rpgserv/roll", 1, 3)
  1379. {
  1380. this->SetDesc(_("Calculates the resulting dice value, even when using advanced math functions.")) ;
  1381. this->SetSyntax(_("\002\037<dice equation>\037 \037[where]\037 \037[message]\037\002"));
  1382. this->AllowUnregistered(true);
  1383. }
  1384. void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
  1385. {
  1386. double dresult=0.0;
  1387. int X = 0;
  1388. int Y = 0;
  1389. const Anope::string &dice = params[0];
  1390. const Anope::string &chan = params.size() > 1 ? params[1] : "";
  1391. const Anope::string &message = params.size() > 2 ? params[2] : "";
  1392. Anope::string target = "";
  1393. Anope::string mydice = "";
  1394. BotInfo *bi = BotInfo::Find(source.service->nick.c_str());
  1395. User *u = source.GetUser();
  1396. User *u2 = NULL;
  1397. DiceErrCode=DICE_ERR_NONE;
  1398. DiceErrNum=0;
  1399. DiceErrPos=0;
  1400. Postfix result;
  1401.  
  1402. if(!chan.empty())
  1403. {
  1404. if (chan.c_str()[0] == '#')
  1405. {
  1406. if (!IRCD->IsChannelValid(chan))
  1407. source.Reply(CHAN_X_INVALID, chan.c_str());
  1408. else
  1409. {
  1410. ChannelInfo *ci = ChannelInfo::Find(chan);
  1411. if (!ci && u)
  1412. target = chan.c_str();
  1413. // source.Reply(CHAN_X_NOT_IN_USE, chan.c_str());
  1414. else
  1415. {
  1416. target = ci->name.c_str();
  1417. }
  1418. }
  1419. }
  1420. else
  1421. {
  1422. u2 = User::Find(chan, true);
  1423. if (!u2)
  1424. {
  1425. source.Reply(NICK_X_NOT_IN_USE, chan.c_str());
  1426. return;
  1427. }
  1428. else
  1429. {
  1430. target = u2->nick.c_str();
  1431. }
  1432. }
  1433. }
  1434. Log(LOG_COMMAND,source, this) << "with the paramaters of:" << dice << " " << chan << " " << message;
  1435. if (dice.equals_ci("joint"))
  1436. {
  1437. if (!target.empty())
  1438. {
  1439. IRCD->SendAction(bi, target.c_str(), "passes a \'cigarette\' to %s",u->nick.c_str());
  1440. IRCD->SendPrivmsg(bi, target.c_str(), "If you get busted I never saw you!");
  1441. }
  1442. else
  1443. {
  1444. u->SendMessage(bi, _(" Psst! If you get busted I never saw you!"));
  1445. u->SendMessage(bi, _("Here you go %s. One \'cigarette\'."),u->nick.c_str());
  1446. }
  1447. return;
  1448. }
  1449. else if (dice.equals_ci("eyes"))
  1450. {
  1451. if (!target.empty())
  1452. {
  1453. IRCD->SendPrivmsg(bi, target.c_str(), "%s rolls eyes.",u->nick.c_str());
  1454. IRCD->SendPrivmsg(bi, target.c_str(), "+-- 1 1 ... snake eyes!");
  1455. }
  1456. else
  1457. {
  1458. u->SendMessage(bi, _("%s rolls eyes."),u->nick.c_str());
  1459. u->SendMessage(bi, _("+-- 1 1 ... snake eyes!"));
  1460. }
  1461. return;
  1462. }
  1463. else if (dice.equals_ci("%d") || dice.equals_ci("percent") || dice.equals_ci("percentile") || dice.equals_ci("%") || dice.equals_ci("d%"))
  1464. {
  1465. X = 1;
  1466. Y = 100;
  1467. mydice = stringify(X) + "d" + stringify(Y);
  1468. }
  1469. else if (dice.equals_ci("save") || dice.equals_ci("check") || dice.equals_ci("hit") || dice.equals_ci("attack"))
  1470. {
  1471. X = 1;
  1472. Y = 20;
  1473. mydice = stringify(X) + "d" + stringify(Y);
  1474. }
  1475. else if (dice.equals_ci("init") || dice.equals_ci("initative"))
  1476. {
  1477. X = 1;
  1478. Y = 10;
  1479. mydice = stringify(X) + "d" + stringify(Y);
  1480. }
  1481. if(!mydice.empty())
  1482. {
  1483. result = DoParse(mydice);
  1484. if(ErrorHandler(source, mydice, DiceErrPos))
  1485. {
  1486. return;
  1487. }
  1488. }
  1489. else
  1490. {
  1491. result = DoParse(dice);
  1492. if(ErrorHandler(source, dice, DiceErrPos))
  1493. {
  1494. return;
  1495. }
  1496. }
  1497. dresult = DoEvaluate(result);
  1498. if (!target.empty())
  1499. {
  1500. if (!u2)
  1501. {
  1502. IRCD->SendPrivmsg(bi, target.c_str(), "%s rolled '%s': %s", u->nick.c_str(), dice.c_str(), message.c_str());
  1503. IRCD->SendPrivmsg(bi, target.c_str(), "+-- Result: %s ", stringify(dresult).c_str());
  1504. }
  1505. else
  1506. {
  1507. u2->SendMessage(bi, _("%s rolled '%s': %s"), u->nick.c_str(), dice.c_str(), message.c_str());
  1508. u2->SendMessage(bi, _("+-- Result: %s "), stringify(dresult).c_str());
  1509. }
  1510. source.Reply("%s rolled '%s': %s", u->nick.c_str(), dice.c_str(), message.c_str());
  1511. source.Reply("+-- Result: %s ", stringify(dresult).c_str());
  1512. }
  1513. else
  1514. {
  1515. u->SendMessage(bi, _("%s rolled '%s': %s"), u->nick.c_str(), dice.c_str(), message.c_str());
  1516. u->SendMessage(bi, _("+-- Result: %s "), stringify(dresult).c_str());
  1517. }
  1518. }
  1519.  
  1520. bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
  1521. {
  1522. if(subcommand.empty()) {
  1523. this->SendSyntax(source);
  1524. source.Reply(" ");
  1525. source.Reply(_("Calculate total, based on equation, including random dice.\n"
  1526. " \n"
  1527. "This command is to simulate the rolling of polyhedral\n"
  1528. "dice. it will handle dice with up to 1000 sides, &\n"
  1529. "quantities of dice up to 1000. \n"
  1530. " \n"
  1531. "The <equation> argument is required and specfies what\n"
  1532. "dice to roll and any additional functions which need\n"
  1533. "to be preformed with said dice. Dice format is in\n"
  1534. "common dice notation, or one of several keywords\n"
  1535. "which serve as alias to that notation. See '/msg rpgserv \n"
  1536. "help roll expressions' for more detaisl on dice notation. \n"
  1537. "See '/msg rpgserv help calc functions' for more details for\n"
  1538. "the mathmatical functions available.\n"
  1539. " \n"
  1540. "The [optional where] paramater is as implied an\n"
  1541. "optional paramater. It specifies a location in addition\n"
  1542. "to the user to which output is sent. This can be either\n"
  1543. "a channel or another username. No error checking is\n"
  1544. "performed on this parameter and if invalid information\n"
  1545. "is supplied it will simply output to the user alone.\n"
  1546. " \n"
  1547. "The [optional message] paramter is useful to record, \n"
  1548. "publicly, what your intent is or modifications to the \n"
  1549. "roll are.\n"
  1550. " \n"));
  1551. return true;
  1552. }
  1553. else if ( subcommand.equals_ci("expressions") || subcommand.equals_ci("syntax") )
  1554. {
  1555. source.Reply(_("dice expression must be in the form of: xdy\n"
  1556. " \n"
  1557. "x and y can support very complex forms of expressions. In\n"
  1558. "order to get an actual dice roll, you must use something in\n"
  1559. "the format of: [z]dw, where z is the number of dice to\n"
  1560. "be thrown, and w is the number of sides on each die. z is\n"
  1561. "optional, will default to 1 if not given. Please note that\n"
  1562. "the sides or number of dice can not be 0 or negative, and\n"
  1563. "both can not be greater than 9999.\n"
  1564. " \n"
  1565. "To roll what is called a \"percentile\" die, or a 100-sided\n"
  1566. "die, you can use %% as your roll expression, or include d%%\n"
  1567. "within your roll expression. For the former, the expression\n"
  1568. "will be replaced with 1d100, whereas for the latter, the\n"
  1569. "%% in the expression will be replaced with a 100. For all\n"
  1570. "other cases, the %% will signify modulus of the numbers\n"
  1571. "before and after it, the modulus being the remainder that\n"
  1572. "you'd get from dividing the first number by the second\n"
  1573. "number.\n"
  1574. " \n"
  1575. "The following math operators can be used in expressions:\n"
  1576. " \n"
  1577. "+ - * / ^ %% (in addition to 'd' for dice rolls and\n"
  1578. "parentheses to force order of operatons.)\n"
  1579. " \n"));
  1580. return true;
  1581. }
  1582. source.Reply(_("No help for roll %s."),subcommand.c_str());
  1583. return true;
  1584. }
  1585. };
  1586.  
  1587. /*
  1588. * Handle RPGSERV CALC command
  1589. */
  1590. class CommandRSCalc : public Command
  1591. {
  1592.  
  1593. public:
  1594. CommandRSCalc(Module *creator) : Command(creator, "rpgserv/calc", 1, 3)
  1595. {
  1596. this->SetDesc(_("Calculates a value, even when using random dice.")) ;
  1597. this->SetSyntax(_("\002\037<equation>\037 \037[where]\037 \037[message]\037\002"));
  1598. this->AllowUnregistered(true);
  1599. }
  1600. void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
  1601. {
  1602. double dresult=0.0;
  1603. const Anope::string &dice = params[0];
  1604. const Anope::string &chan = params.size() > 1 ? params[1] : "";
  1605. const Anope::string &message = params.size() > 2 ? params[2] : "";
  1606. Anope::string target = "";
  1607. BotInfo *bi = BotInfo::Find(source.service->nick.c_str());
  1608. User *u = source.GetUser();
  1609. User *u2 = NULL;
  1610. DiceErrCode=DICE_ERR_NONE;
  1611. DiceErrNum=0;
  1612. DiceErrPos=0;
  1613. if(!chan.empty())
  1614. {
  1615. if (chan.c_str()[0] == '#')
  1616. {
  1617. ChannelInfo *ci = ChannelInfo::Find(chan);
  1618. if (!IRCD->IsChannelValid(chan))
  1619. source.Reply(CHAN_X_INVALID, chan.c_str());
  1620. else if (!ci && u)
  1621. source.Reply(CHAN_X_NOT_IN_USE, chan.c_str());
  1622. else
  1623. {
  1624. target = ci->name.c_str();
  1625. }
  1626. }
  1627. else
  1628. {
  1629. u2 = User::Find(chan, true);
  1630. if (!u2)
  1631. {
  1632. source.Reply(NICK_X_NOT_IN_USE, chan.c_str());
  1633. return;
  1634. }
  1635. else
  1636. {
  1637. target = u2->nick.c_str();
  1638. }
  1639. }
  1640. }
  1641. Postfix result = DoParse(dice);
  1642. if(ErrorHandler(source, dice, DiceErrPos))
  1643. {
  1644. return;
  1645. }
  1646. dresult = DoEvaluate(result);
  1647. Log(LOG_COMMAND,source, this) << "to generate dice of " << dice.c_str() << " with a message of:" << message.c_str() << " to " << target.c_str();
  1648. if (!target.empty())
  1649. {
  1650. if (!u2)
  1651. {
  1652. IRCD->SendPrivmsg(bi, target.c_str(), "%s requested calculation of '%s': %s", u->nick.c_str(), dice.c_str(), message.c_str());
  1653. IRCD->SendPrivmsg(bi, target.c_str(), "+-- Result: %s ", stringify(dresult).c_str());
  1654. }
  1655. else
  1656. {
  1657. u2->SendMessage(bi, _("%s requested calculation of '%s': %s"), u->nick.c_str(), dice.c_str(), message.c_str());
  1658. u2->SendMessage(bi, _("+-- Result: %s "), stringify(dresult).c_str());
  1659. }
  1660. source.Reply("%s requested calculation of '%s': %s", u->nick.c_str(), dice.c_str(), message.c_str());
  1661. source.Reply("+-- Result: %s ", stringify(dresult).c_str());
  1662. }
  1663. else
  1664. {
  1665. u->SendMessage(bi, _("%s requested calculation of '%s': %s"), u->nick.c_str(), dice.c_str(), message.c_str());
  1666. u->SendMessage(bi, _("+-- Result: %s "), stringify(dresult).c_str());
  1667. }
  1668. }
  1669.  
  1670. bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
  1671. {
  1672. if(subcommand.empty())
  1673. {
  1674. this->SendSyntax(source);
  1675. source.Reply(" ");
  1676. source.Reply(_("Calculate total, based on equation, including dice.\n"
  1677. " \n"
  1678. "The <equation> argument is required and specfies what\n"
  1679. "dice to roll and any additional functions which need\n"
  1680. "to be preformed with said dice. Dice format is in\n"
  1681. "common dice notation, or one of several keywords\n"
  1682. "which serve as alias to that notation. See '/msg rpgserv \n"
  1683. "help calc functions' for more details. See '/msg rpgserv \n"
  1684. "help roll expressions' for more details on dice syntax.\n"
  1685. " \n"
  1686. "The [optional where] paramater is as implied an\n"
  1687. "optional paramater. It specifies a location in addition\n"
  1688. "to the user to which output is sent. This can be either\n"
  1689. "a channel or another username. No error checking is\n"
  1690. "performed on this parameter and if invalid information\n"
  1691. "is supplied it will simply output to the user alone.\n"
  1692. " \n"
  1693. "The [optional message] paramter is useful to record, \n"
  1694. "publicly, what your intent is or modifications to the \n"
  1695. "roll are.\n"
  1696. " \n"));
  1697. return true;
  1698. }
  1699. else if( subcommand.equals_ci("functions") || subcommand.equals_ci("syntax") )
  1700. {
  1701. source.Reply(" ");
  1702. source.Reply(_("Math functions rupported:\n"
  1703. " \n"
  1704. " abs(x) Absolute value of x\n"
  1705. " acos(x) Arc cosine of x\n"
  1706. " acosh(x) Inverse hyperbolic cosine of x\n"
  1707. " asin(x) Arc sine of x\n"
  1708. " asinh(x) Inverse hyperbolic sine of x\n"
  1709. " atan(x) Arc tangent of x\n"
  1710. " atanh(x) Inverse hyperbolic tangent of x\n"
  1711. " cbrt(x) Cube root of x\n"
  1712. " ceil(x) The next smallest integer greater than\n"
  1713. " or equal to x\n"
  1714. " cos(x) Cosine of x\n"
  1715. " cosh(x) Hyperbolic cosine of x\n"
  1716. " deg(x) Convert x from radians to degrees\n"
  1717. " exp(x) e (exponential value) to the power\n"
  1718. " of x\n"
  1719. " fac(x) Factorial of x\n"
  1720. " floor(x) The next largest integer less than or\n"
  1721. " equal to x\n"
  1722. " log(x) Natural logarithm of x\n"
  1723. " log10(x) Logarithm of x to base 10\n"
  1724. " max(x,y) Maximum of x and y\n"
  1725. " min(x,y) Minimum of x and y\n"
  1726. " rad(x) Convert x from degrees to radians\n"
  1727. " rand(x,y) Random value between x and y\n"
  1728. " round(x) Round x to the nearest integer\n"
  1729. " sin(x) Sine of x\n"
  1730. " sinh(x) Hyperbolic sine of x\n"
  1731. " sqrt(x) Square root of x\n"
  1732. " tan(x) Tangent of x\n"
  1733. " tanh(x) Hyperbolic tangent of x\n"
  1734. " trunc(x) The integral portion of x\n"
  1735. " \n"
  1736. "NOTE: All trigonometric functions above (sine, cosine and\n"
  1737. "tangent) return their values in radians.\n"
  1738. " \n"
  1739. "The following math operators can be used in expressions:\n"
  1740. " \n"
  1741. "+ - * / ^ %% (in addition to 'd' for dice rolls and\n"
  1742. "parentheses to force order of operatons.)\n"
  1743. " \n"
  1744. "The following math constants are\n"
  1745. "also recognized and will be filled in automatically:\n"
  1746. " \n"
  1747. " e Exponential growth constant\n"
  1748. " 2.7182818284590452354\n"
  1749. " pi Archimedes' constant\n"
  1750. " 3.14159265358979323846\n"
  1751. " \n"
  1752. "The dice roller will also recognize if you want to have a\n"
  1753. "negative number when prefixed with a -. This will not cause\n"
  1754. "problems even though it is also used for subtraction."
  1755. " \n"
  1756. ));
  1757. return true;
  1758. }
  1759. source.Reply(_("No help for calc %s"),subcommand.c_str());
  1760. return true;
  1761. }
  1762. };
  1763.  
  1764. class RpgServCore : public Module
  1765. {
  1766. Reference<BotInfo> RpgServ;
  1767. std::vector<Anope::string> defaults;
  1768. bool always_lower;
  1769. CommandRSCalc commandrscalc;
  1770. CommandRSRoll commandrsroll;
  1771.  
  1772. public:
  1773. RpgServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | EXTRA),
  1774. always_lower(false), commandrscalc(this), commandrsroll(this)
  1775. {
  1776. this->SetAuthor("Azander");
  1777. this->SetVersion("2.0");
  1778. }
  1779.  
  1780. void OnReload(Configuration::Conf *conf) anope_override
  1781. {
  1782. const Anope::string &rsnick = conf->GetModule(this)->Get<const Anope::string>("client");
  1783. if(rsnick.empty())
  1784. throw ConfigException(Module::name + ": <client> must be defined");
  1785.  
  1786. BotInfo *bi = BotInfo::Find(rsnick, true);
  1787. if (!bi)
  1788. throw ConfigException(Module::name + ": no bot named " + rsnick);
  1789.  
  1790. RpgServ = bi;
  1791. }
  1792.  
  1793. EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) anope_override
  1794. {
  1795. if (bi == RpgServ && Config->GetModule(this)->Get<bool>("opersonly") && !u->HasMode("OPER"))
  1796. {
  1797. u->SendMessage(bi, ACCESS_DENIED);
  1798. return EVENT_STOP;
  1799. }
  1800. return EVENT_CONTINUE;
  1801. }
  1802.  
  1803. EventReturn OnPreHelp(CommandSource &source, const std::vector<Anope::string> &params) anope_override
  1804. {
  1805. if (!params.empty() || source.c || source.service != *RpgServ)
  1806. {
  1807. return EVENT_CONTINUE;
  1808. }
  1809. source.Reply(_("%s commands:"), RpgServ->nick.c_str());
  1810. return EVENT_CONTINUE;
  1811. }
  1812. void OnLog(Log *l) anope_override
  1813. {
  1814. if (l->type == LOG_SERVER)
  1815. l->bi = RpgServ;
  1816. }
  1817. };
  1818.  
  1819. MODULE_INIT(RpgServCore)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement