enum.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Version: MPL 1.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the sscanf 2.0 SA:MP plugin.
  15. *
  16. * The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  17. * Portions created by the Initial Developer are Copyright (C) 2010
  18. * the Initial Developer. All Rights Reserved.
  19. *
  20. * Contributor(s):
  21. *
  22. * Special Thanks to:
  23. *
  24. * SA:MP Team past, present and future
  25. */
  26. #include "SDK/amx/amx.h"
  27. #include <string.h>
  28. #include "utils.h"
  29. #include "specifiers.h"
  30. #include "data.h"
  31. #include "sscanf.h"
  32. extern logprintf_t
  33. logprintf;
  34. #define SAVE_VALUE(m) \
  35. if (doSave) \
  36. *cptr++ = m
  37. #define SAVE_VALUE_F(m) \
  38. if (doSave) { \
  39. float f = (float)m; \
  40. *cptr++ = amx_ftoc(f); }
  41. // Macros for the regular values.
  42. #define DO(m,n) \
  43. {m b; \
  44. if (Do##n(&string, &b)) { \
  45. SAVE_VALUE((cell)b); \
  46. break; } \
  47. *input = string; \
  48. return SSCANF_FAIL_RETURN; }
  49. #define DOV(m,n) \
  50. {m b; \
  51. Do##n(&string, &b); \
  52. SAVE_VALUE((cell)b); }
  53. #define DOF(m,n) \
  54. {m b; \
  55. if (Do##n(&string, &b)) { \
  56. SAVE_VALUE_F(b) \
  57. break; } \
  58. *input = string; \
  59. return SSCANF_FAIL_RETURN; }
  60. #define OPTIONAL_INVALID \
  61. logprintf("sscanf warning: Optional types invalid in enum specifiers, consider using 'E'.")
  62. #define DX(m,n) \
  63. OPTIONAL_INVALID;
  64. #define DXF(m,n) \
  65. OPTIONAL_INVALID;
  66. extern AMX *
  67. g_aCurAMX;
  68. extern int
  69. gOptions;
  70. bool
  71. DoK(AMX * amx, char ** defaults, char ** input, cell * cptr, bool optional);
  72. int
  73. DoEnumValues(char * format, char ** input, cell * cptr, bool defaults)
  74. {
  75. // If cptr is NULL we never save - regardless of quiet sections.
  76. bool
  77. doSave = cptr != NULL;
  78. char *
  79. string = *input;
  80. // Copied directly from the main loop, just with different macros.
  81. while (*string)
  82. {
  83. if (!*format)
  84. {
  85. // Happy with this return.
  86. *input = string;
  87. return SSCANF_TRUE_RETURN;
  88. }
  89. else if (IsWhitespace(*format))
  90. {
  91. ++format;
  92. }
  93. else
  94. {
  95. switch (*format++)
  96. {
  97. case 'L':
  98. DX(bool, L)
  99. // FALLTHROUGH
  100. case 'l':
  101. DOV(bool, L)
  102. break;
  103. case 'B':
  104. DX(int, B)
  105. // FALLTHROUGH
  106. case 'b':
  107. DO(int, B)
  108. case 'N':
  109. DX(int, N)
  110. // FALLTHROUGH
  111. case 'n':
  112. DO(int, N)
  113. case 'C':
  114. DX(char, C)
  115. // FALLTHROUGH
  116. case 'c':
  117. DO(char, C)
  118. case 'I':
  119. case 'D':
  120. DX(int, I)
  121. // FALLTHROUGH
  122. case 'i':
  123. case 'd':
  124. DO(int, I)
  125. case 'H':
  126. case 'X':
  127. DX(int, H)
  128. // FALLTHROUGH
  129. case 'h':
  130. case 'x':
  131. DO(int, H)
  132. case 'O':
  133. DX(int, O)
  134. // FALLTHROUGH
  135. case 'o':
  136. DO(int, O)
  137. case 'F':
  138. DXF(double, F)
  139. // FALLTHROUGH
  140. case 'f':
  141. DOF(double, F)
  142. case 'G':
  143. DXF(double, G)
  144. // FALLTHROUGH
  145. case 'g':
  146. DOF(double, G)
  147. case '{':
  148. if (doSave)
  149. {
  150. doSave = false;
  151. }
  152. else if (cptr)
  153. {
  154. // Already in a quiet section.
  155. logprintf("sscanf warning: Can't have nestled quiet sections.");
  156. }
  157. continue;
  158. case '}':
  159. if (doSave)
  160. {
  161. logprintf("sscanf warning: Not in a quiet section.");
  162. }
  163. else
  164. {
  165. if (cptr)
  166. {
  167. doSave = true;
  168. }
  169. else
  170. {
  171. logprintf("sscanf warning: Can't remove quiet in enum.");
  172. }
  173. }
  174. continue;
  175. case 'P':
  176. {
  177. ResetDelimiter();
  178. char *
  179. t = GetMultiType(&format);
  180. if (t) AddDelimiters(t);
  181. else return SSCANF_FAIL_RETURN;
  182. continue;
  183. }
  184. //logprintf("sscanf warning: You can't have an optional delimiter.");
  185. // FALLTHROUGH
  186. case 'p':
  187. // 'P' doesn't exist.
  188. // Theoretically, for compatibility, this should be:
  189. // p<delimiter>, but that will break backwards
  190. // compatibility with anyone doing "p<" to use '<' as a
  191. // delimiter (doesn't matter how rare that may be). Also,
  192. // writing deprecation code and both the new and old code
  193. // is more trouble than it's worth, and it's slow.
  194. // UPDATE: I wrote the "GetSingleType" code for 'a' and
  195. // figured out a way to support legacy and new code, while
  196. // still maintaining support for the legacy "p<" separator,
  197. // so here it is:
  198. ResetDelimiter();
  199. AddDelimiter(GetSingleType(&format));
  200. continue;
  201. case 'K':
  202. OPTIONAL_INVALID;
  203. // FALLTHROUGH
  204. case 'k':
  205. //DOF(double, K)
  206. if (defaults && !(gOptions & 16))
  207. {
  208. GetMultiType(&format);
  209. if (doSave)
  210. {
  211. int
  212. b;
  213. DoI(&string, &b);
  214. *cptr++ = b;
  215. }
  216. else
  217. {
  218. int
  219. b;
  220. DoI(&string, &b);
  221. }
  222. *(format - 1) = '>';
  223. break;
  224. }
  225. else if (doSave)
  226. {
  227. if (DoK(g_aCurAMX, &format, &string, cptr, false))
  228. {
  229. *(format - 1) = '>';
  230. ++cptr;
  231. break;
  232. }
  233. }
  234. else
  235. {
  236. if (DoK(g_aCurAMX, &format, &string, NULL, false))
  237. {
  238. *(format - 1) = '>';
  239. break;
  240. }
  241. }
  242. *input = string;
  243. return SSCANF_FAIL_RETURN;
  244. case 'Z':
  245. logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  246. // FALLTHROUGH
  247. case 'z':
  248. logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  249. // FALLTHROUGH
  250. case 'S':
  251. OPTIONAL_INVALID;
  252. // FALLTHROUGH
  253. case 's':
  254. {
  255. // Get the length.
  256. int
  257. lole = GetLength(&format, true);
  258. if (!lole)
  259. {
  260. return SSCANF_FAIL_RETURN;
  261. }
  262. char *
  263. dest;
  264. DoS(&string, &dest, lole, IsEnd(*format));
  265. // Send the string to PAWN.
  266. if (doSave)
  267. {
  268. // Save the string.
  269. amx_SetString(cptr, dest, 0, 0, lole);
  270. // Increase the pointer by the MAXIMUM length of
  271. // the string - that's how enum strings work.
  272. cptr += lole;
  273. }
  274. }
  275. break;
  276. case 'U':
  277. DX(int, U)
  278. // FALLTHROUGH
  279. case 'u':
  280. if (*format == '[')
  281. {
  282. logprintf("sscanf warning: User arrays are not supported in enums.");
  283. SkipLength(&format);
  284. }
  285. #define DoU(m,n) DoU(m,n,0)
  286. if (defaults && !(gOptions & 1))
  287. {
  288. DOV(int, I)
  289. }
  290. else
  291. {
  292. DOV(int, U)
  293. }
  294. #undef DoU
  295. break;
  296. case 'Q':
  297. DX(int, Q)
  298. // FALLTHROUGH
  299. case 'q':
  300. if (*format == '[')
  301. {
  302. logprintf("sscanf warning: User arrays are not supported in enums.");
  303. SkipLength(&format);
  304. }
  305. #define DoQ(m,n) DoQ(m,n,0)
  306. if (defaults && !(gOptions & 1))
  307. {
  308. DOV(int, I)
  309. }
  310. else
  311. {
  312. DOV(int, Q)
  313. }
  314. #undef DoQ
  315. break;
  316. case 'R':
  317. DX(int, R)
  318. // FALLTHROUGH
  319. case 'r':
  320. if (*format == '[')
  321. {
  322. logprintf("sscanf warning: User arrays are not supported in enums.");
  323. SkipLength(&format);
  324. }
  325. #define DoR(m,n) DoR(m,n,0)
  326. if (defaults && !(gOptions & 1))
  327. {
  328. DOV(int, I)
  329. }
  330. else
  331. {
  332. DOV(int, R)
  333. }
  334. #undef DoR
  335. break;
  336. case 'A':
  337. case 'a':
  338. logprintf("sscanf error: Arrays are not supported in enums.");
  339. *input = string;
  340. return SSCANF_FAIL_RETURN;
  341. case 'E':
  342. case 'e':
  343. logprintf("sscanf error: Enums are not supported in enums.");
  344. *input = string;
  345. return SSCANF_FAIL_RETURN;
  346. case '\'':
  347. // Find the end of the literal.
  348. {
  349. char
  350. * str = format,
  351. * write = format;
  352. bool
  353. escape = false;
  354. while (!IsEnd(*str) && (escape || *str != '\''))
  355. {
  356. if (*str == '\\')
  357. {
  358. if (escape)
  359. {
  360. // "\\" - Go back a step to write this
  361. // character over the last character (which
  362. // just happens to be the same character).
  363. --write;
  364. }
  365. escape = !escape;
  366. }
  367. else
  368. {
  369. if (*str == '\'')
  370. {
  371. // Overwrite the escape character with the
  372. // quote character. Must have been
  373. // preceeded by a slash or it wouldn't have
  374. // got to here in the loop.
  375. --write;
  376. }
  377. escape = false;
  378. }
  379. // Copy the string over itself to get rid of excess
  380. // escape characters.
  381. // Not sure if it's faster in the average case to
  382. // always do the copy or check if it's needed.
  383. // This write is always safe as it makes the string
  384. // shorter, so we'll never run out of space. It
  385. // will also not overwrite the original string.
  386. *write++ = *str++;
  387. }
  388. if (*str == '\'')
  389. {
  390. // Correct end. Make a shorter string to search
  391. // for.
  392. *write = '\0';
  393. // Find the current section of format in string.
  394. char *
  395. find = strstr(string, format);
  396. if (!find)
  397. {
  398. // Didn't find the string.
  399. *input = string;
  400. return SSCANF_FAIL_RETURN;
  401. }
  402. // Found the string. Update the current string
  403. // position to the length of the search term
  404. // further along from the start of the term. Use
  405. // "write" here as we want the escaped string
  406. // length.
  407. string = find + (write - format);
  408. // Move to after the end of the search string. Use
  409. // "str" here as we want the unescaped string
  410. // length.
  411. format = str + 1;
  412. }
  413. else
  414. {
  415. logprintf("sscanf warning: Unclosed string literal.");
  416. char *
  417. find = strstr(string, format);
  418. if (!find)
  419. {
  420. *input = string;
  421. return SSCANF_FAIL_RETURN;
  422. }
  423. string = find + (write - format);
  424. format = str;
  425. }
  426. }
  427. break;
  428. case '?':
  429. logprintf("sscanf error: Options are not supported in enums.");
  430. return SSCANF_FAIL_RETURN;
  431. case '%':
  432. logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  433. continue;
  434. case '-':
  435. {
  436. int
  437. len = 1;
  438. switch (*format++)
  439. {
  440. case 'i':
  441. case 'f':
  442. case 'l':
  443. case 'b':
  444. case 'n':
  445. case 'c':
  446. case 'd':
  447. case 'h':
  448. case 'x':
  449. case 'o':
  450. case 'g':
  451. break;
  452. case 'I':
  453. case 'F':
  454. case 'L':
  455. case 'B':
  456. case 'N':
  457. case 'C':
  458. case 'D':
  459. case 'H':
  460. case 'X':
  461. case 'O':
  462. case 'G':
  463. OPTIONAL_INVALID;
  464. break;
  465. case 'K':
  466. OPTIONAL_INVALID;
  467. case 'k':
  468. GetMultiType(&format);
  469. break;
  470. case 'P':
  471. case 'p':
  472. logprintf("sscanf warning: A minus delimiter makes no sense.");
  473. len = 0;
  474. break;
  475. case '{':
  476. case '}':
  477. logprintf("sscanf warning: A minus quiet section makes no sense.");
  478. len = 0;
  479. break;
  480. case 'U':
  481. case 'Q':
  482. case 'R':
  483. OPTIONAL_INVALID;
  484. case 'u':
  485. case 'q':
  486. case 'r':
  487. if (*format == '[')
  488. {
  489. len = GetLength(&format, true);
  490. }
  491. break;
  492. case 'A':
  493. OPTIONAL_INVALID;
  494. case 'a':
  495. len = GetLength(&format, true);
  496. break;
  497. case 'E':
  498. OPTIONAL_INVALID;
  499. case 'e':
  500. logprintf("sscanf error: Enums are not supported in enums.");
  501. *input = string;
  502. return SSCANF_FAIL_RETURN;
  503. case 'Z':
  504. logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  505. // FALLTHROUGH
  506. case 'z':
  507. logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  508. // FALLTHROUGH
  509. case 'S':
  510. OPTIONAL_INVALID;
  511. // FALLTHROUGH
  512. case 's':
  513. len = GetLength(&format, true);
  514. break;
  515. case '?':
  516. logprintf("sscanf warning: A minus option makes no sense.");
  517. len = 0;
  518. break;
  519. case '%':
  520. logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  521. len = 0;
  522. break;
  523. case '-':
  524. logprintf("sscanf warning: A minus minus makes no sense.");
  525. len = 0;
  526. break;
  527. default:
  528. logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  529. len = 0;
  530. break;
  531. }
  532. if (doSave)
  533. {
  534. cptr += len;
  535. }
  536. }
  537. break;
  538. default:
  539. logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  540. continue;
  541. }
  542. // Loop cleanup - only skip one spacer so that we can detect
  543. // multiple explicit delimiters in a row, for example:
  544. //
  545. // hi there
  546. //
  547. // is NOT multiple explicit delimiters in a row (they're
  548. // whitespace). This however is:
  549. //
  550. // hi , , , there
  551. //
  552. SkipOneSpacer(&string);
  553. }
  554. }
  555. // Save the end of the string.
  556. *input = string;
  557. if (*format)
  558. {
  559. if (*format == '}' && IsEnd(*(format + 1)))
  560. {
  561. return SSCANF_TRUE_RETURN;
  562. }
  563. // Ran out of values - check if this is an optional array at a higher
  564. // level.
  565. return SSCANF_CONT_RETURN;
  566. }
  567. return SSCANF_TRUE_RETURN;
  568. }
  569. bool
  570. DoE(char ** defaults, char ** input, cell * cptr, bool optional)
  571. {
  572. // First, get the type of the array.
  573. char *
  574. type = GetMultiType(defaults);
  575. if (!type)
  576. {
  577. return false;
  578. }
  579. if (optional)
  580. {
  581. // Optional parameters - just collect the data for
  582. // now and use it later.
  583. if (**defaults == '(')
  584. {
  585. ++(*defaults);
  586. SkipWhitespace(defaults);
  587. // Got the start of the values.
  588. char *
  589. opts = *defaults;
  590. // Skip the defaults for now, we don't know the length yet.
  591. bool
  592. escape = false;
  593. while (**defaults && (escape || **defaults != ')'))
  594. {
  595. if (**defaults == '\\')
  596. {
  597. escape = !escape;
  598. }
  599. else
  600. {
  601. escape = false;
  602. }
  603. ++(*defaults);
  604. }
  605. if (**defaults)
  606. {
  607. if (opts == *defaults)
  608. {
  609. // No defaults found.
  610. logprintf("sscanf warning: Empty default values.");
  611. optional = false;
  612. }
  613. // Found a valid end. Make it null for
  614. // later array getting (easy to detect a
  615. // null end and we'll never need to
  616. // backtrack to here in the specifiers).
  617. **defaults = '\0';
  618. ++(*defaults);
  619. }
  620. else
  621. {
  622. logprintf("sscanf warning: Unclosed default value.");
  623. }
  624. if (optional)
  625. {
  626. // Optional parameters are always separated by commans, not
  627. // whatever the coder may choose.
  628. TempDelimiter(",)");
  629. // We need to copy the old save value for optional parts. If
  630. // we don't and save gets set to false in the middle of the
  631. // enum then when the code is called for a second time for the
  632. // real values then save will already be false and they won't
  633. // get saved.
  634. switch (DoEnumValues(type, &opts, cptr, true))
  635. {
  636. case SSCANF_TRUE_RETURN:
  637. break;
  638. case SSCANF_CONT_RETURN:
  639. logprintf("sscanf error: Insufficient default values.");
  640. // FALLTHROUGH
  641. default:
  642. RestoreDelimiter();
  643. return false;
  644. }
  645. RestoreDelimiter();
  646. }
  647. }
  648. else
  649. {
  650. logprintf("sscanf warning: No default value found.");
  651. optional = false;
  652. }
  653. }
  654. if (input)
  655. {
  656. switch (DoEnumValues(type, input, cptr, false))
  657. {
  658. case SSCANF_TRUE_RETURN:
  659. return true;
  660. case SSCANF_CONT_RETURN:
  661. if (optional)
  662. {
  663. return true;
  664. }
  665. // FALLTHROUGH
  666. default:
  667. return false;
  668. }
  669. }
  670. return true;
  671. }