data.cpp 18 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  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 "sscanf.h"
  28. #include "utils.h"
  29. extern unsigned int
  30. g_iTrueMax;
  31. extern logprintf_t
  32. logprintf,
  33. real_logprintf;
  34. void
  35. qlog(char *, ...);
  36. // Options:
  37. //
  38. // 1 = OLD_DEFAULT_NAME
  39. //
  40. // Parse values in "U(5)" as if they were a name that must be connected,
  41. // instead of just any number.
  42. //
  43. // 2 = MATCH_NAME_PARTIAL
  44. //
  45. // When searching for players, match any part of their name not just the
  46. // start.
  47. //
  48. // 4 = CELLMIN_ON_MATCHES
  49. //
  50. // If multiple player name matches are found, return 0x80000000.
  51. //
  52. // 8 = SSCANF_QUIET
  53. //
  54. // Disable all prints.
  55. //
  56. int
  57. gOptions = 0;
  58. void
  59. RestoreOpts(int opt)
  60. {
  61. gOptions = opt;
  62. if (gOptions & 8) logprintf = qlog;
  63. else logprintf = real_logprintf;
  64. }
  65. void
  66. DoOptions(char * name, cell value)
  67. {
  68. // Not the most flexible code I've ever written...
  69. if (!strincmp(name, "OLD_DEFAULT_NAME", 16))
  70. {
  71. switch (value)
  72. {
  73. case 1:
  74. gOptions |= 1;
  75. break;
  76. case 0:
  77. gOptions &= ~1;
  78. break;
  79. case -1:
  80. if (*(name + 16) == '=')
  81. {
  82. if (*(name + 17) == '0') gOptions &= ~1;
  83. else gOptions |= 1;
  84. }
  85. else
  86. {
  87. logprintf("sscanf error: No option value.");
  88. }
  89. }
  90. }
  91. else if (!strincmp(name, "MATCH_NAME_PARTIAL", 18))
  92. {
  93. switch (value)
  94. {
  95. case 1:
  96. gOptions |= 2;
  97. break;
  98. case 0:
  99. gOptions &= ~2;
  100. break;
  101. case -1:
  102. if (*(name + 18) == '=')
  103. {
  104. if (*(name + 19) == '0') gOptions &= ~2;
  105. else gOptions |= 2;
  106. }
  107. else
  108. {
  109. logprintf("sscanf error: No option value.");
  110. }
  111. }
  112. }
  113. else if (!strincmp(name, "CELLMIN_ON_MATCHES", 18))
  114. {
  115. switch (value)
  116. {
  117. case 1:
  118. gOptions |= 4;
  119. break;
  120. case 0:
  121. gOptions &= ~4;
  122. break;
  123. case -1:
  124. if (*(name + 18) == '=')
  125. {
  126. if (*(name + 19) == '0') gOptions &= ~4;
  127. else gOptions |= 4;
  128. }
  129. else
  130. {
  131. logprintf("sscanf error: No option value.");
  132. }
  133. }
  134. }
  135. else if (!strincmp(name, "SSCANF_QUIET", 12))
  136. {
  137. switch (value)
  138. {
  139. case 1:
  140. logprintf = qlog;
  141. gOptions |= 8;
  142. break;
  143. case 0:
  144. logprintf = real_logprintf;
  145. gOptions &= ~8;
  146. break;
  147. case -1:
  148. if (*(name + 12) == '=')
  149. {
  150. if (*(name + 13) == '0')
  151. {
  152. logprintf = real_logprintf;
  153. gOptions &= ~8;
  154. }
  155. else
  156. {
  157. logprintf = qlog;
  158. gOptions |= 8;
  159. }
  160. }
  161. else
  162. {
  163. logprintf("sscanf error: No option value.");
  164. }
  165. }
  166. }
  167. else if (!strincmp(name, "OLD_DEFAULT_KUSTOM", 18) || !strincmp(name, "OLD_DEFAULT_CUSTOM", 18))
  168. {
  169. switch (value)
  170. {
  171. case 1:
  172. gOptions |= 16;
  173. break;
  174. case 0:
  175. gOptions &= ~16;
  176. break;
  177. case -1:
  178. if (*(name + 18) == '=')
  179. {
  180. if (*(name + 19) == '0') gOptions &= ~16;
  181. else gOptions |= 16;
  182. }
  183. else
  184. {
  185. logprintf("sscanf error: No option value.");
  186. }
  187. }
  188. }
  189. else
  190. {
  191. logprintf("sscanf error: Unknown option name.");
  192. }
  193. }
  194. char
  195. GetSingleType(char ** format)
  196. {
  197. char
  198. * cur = *format,
  199. tmp = *cur;
  200. if (tmp == '<')
  201. {
  202. ++cur;
  203. char
  204. ret = *cur;
  205. if (ret)
  206. {
  207. ++cur;
  208. if (*cur == '>')
  209. {
  210. *format += 3;
  211. return ret;
  212. }
  213. else
  214. {
  215. logprintf("sscanf warning: Unclosed specifier parameter, assuming '<', consider using something like p<<>.");
  216. }
  217. }
  218. else
  219. {
  220. logprintf("sscanf warning: Unenclosed specifier parameters are deprecated, consider using something like p<<>.");
  221. }
  222. ++(*format);
  223. return '<';
  224. }
  225. else if (tmp)
  226. {
  227. // Legacy support.
  228. logprintf("sscanf warning: Unenclosed specifier parameters are deprecated, consider using something like p<%c>.", tmp);
  229. ++(*format);
  230. return tmp;
  231. }
  232. else
  233. {
  234. logprintf("sscanf warning: No specified parameter found.");
  235. return ' ';
  236. }
  237. }
  238. char *
  239. GetMultiType(char ** format)
  240. {
  241. char
  242. * cur = *format,
  243. * ret = cur;
  244. if (*cur == '<')
  245. {
  246. ++ret;
  247. bool
  248. reop = false,
  249. escape = false;
  250. do
  251. {
  252. if (*cur == '\\')
  253. {
  254. escape = !escape;
  255. }
  256. else
  257. {
  258. escape = false;
  259. }
  260. ++cur;
  261. if (!escape)
  262. {
  263. if (reop)
  264. {
  265. if (*cur == '>')
  266. {
  267. reop = false;
  268. ++cur;
  269. }
  270. }
  271. else
  272. {
  273. if (*cur == '<')
  274. {
  275. reop = true;
  276. ++cur;
  277. }
  278. }
  279. }
  280. }
  281. while (*cur && (reop || escape || *cur != '>'));
  282. if (*cur)
  283. {
  284. // Only gets here if there is a closing '>'.
  285. *cur = '\0';
  286. *format = cur + 1;
  287. return ret;
  288. }
  289. else
  290. {
  291. logprintf("sscanf error: Unclosed specifier parameters.");
  292. }
  293. }
  294. else
  295. {
  296. logprintf("sscanf error: No specified parameters found.");
  297. }
  298. *format = cur;
  299. return 0;
  300. }
  301. unsigned int
  302. GetUserString(char * string, char ** end)
  303. {
  304. unsigned int
  305. id = 0;
  306. char
  307. cur;
  308. // Get the full name, they can't contain spaces in this code. If a
  309. // player's name manages to contain spaces (e.g. via SetPlayerName), then
  310. // you can only do the part of the name up to the space.
  311. while ((cur = *string) && !IsSpacer(cur))
  312. {
  313. // Valid string item.
  314. ++string;
  315. if ((unsigned char)(cur - '0') >= 10)
  316. {
  317. // Invalid number, so not an ID.
  318. break;
  319. }
  320. // Still a valid ID, continue collecting.
  321. id = (id * 10) + (cur - '0');
  322. }
  323. *end = string;
  324. // Don't use extra checks every loop any more, just one will do.
  325. if (!IsSpacer(cur))
  326. {
  327. // Invalid ID, just find the end of the name.
  328. FindSpacer(end);
  329. // Save the ID as too large for detection later.
  330. id = g_iTrueMax;
  331. }
  332. return id;
  333. }
  334. int
  335. GetDecValue(char ** const input)
  336. {
  337. char *
  338. str = *input;
  339. int
  340. val = 0;
  341. unsigned char
  342. cur;
  343. // Convert to a number and test it.
  344. while ((cur = (unsigned char)(*str - '0')) < 10)
  345. {
  346. // Update the current value.
  347. val = (val * 10) + cur;
  348. // Update the current pointer.
  349. ++str;
  350. }
  351. // Save the pointer.
  352. *input = str;
  353. // Covert the sign and return without an if.
  354. return val;
  355. }
  356. int
  357. GetDec(char ** const input)
  358. {
  359. char *
  360. str = *input;
  361. int
  362. neg = 1;
  363. switch (*str)
  364. {
  365. case '-':
  366. neg = -1;
  367. // FALLTHROUGH
  368. case '+':
  369. // Check there is valid data after
  370. if (((unsigned char)(*(++str) - '0')) >= 10)
  371. {
  372. // Just return now, the caller will recognise this as bad.
  373. return 0;
  374. }
  375. }
  376. *input = str;
  377. return GetDecValue(input) * neg;
  378. }
  379. int
  380. GetOctValue(char ** const input)
  381. {
  382. char *
  383. str = *input;
  384. int
  385. val = 0;
  386. unsigned char
  387. cur;
  388. // Convert to a number and test it.
  389. while ((cur = (unsigned char)(*str - '0')) < 8)
  390. {
  391. // Update the current value.
  392. val = (val * 8) + cur;
  393. // Update the current pointer.
  394. ++str;
  395. }
  396. // Save the pointer.
  397. *input = str;
  398. // Covert the sign and return without an if.
  399. return val;
  400. }
  401. int
  402. GetOct(char ** const input)
  403. {
  404. char *
  405. str = *input;
  406. int
  407. neg = 1;
  408. switch (*str)
  409. {
  410. case '-':
  411. neg = -1;
  412. // FALLTHROUGH
  413. case '+':
  414. // Check there is valid data after
  415. if (((unsigned char)(*(++str) - '0')) >= 8)
  416. {
  417. // Just return now, the caller will recognise this as bad.
  418. return 0;
  419. }
  420. }
  421. *input = str;
  422. return GetOctValue(input) * neg;
  423. }
  424. int
  425. GetHexValue(char ** const input)
  426. {
  427. char *
  428. str = *input;
  429. int
  430. val = 0;
  431. // Rewrote it using a big switch.
  432. for ( ; ; )
  433. {
  434. switch (*str)
  435. {
  436. case '0':
  437. val = (val * 16) + 0x00;
  438. break;
  439. case '1':
  440. val = (val * 16) + 0x01;
  441. break;
  442. case '2':
  443. val = (val * 16) + 0x02;
  444. break;
  445. case '3':
  446. val = (val * 16) + 0x03;
  447. break;
  448. case '4':
  449. val = (val * 16) + 0x04;
  450. break;
  451. case '5':
  452. val = (val * 16) + 0x05;
  453. break;
  454. case '6':
  455. val = (val * 16) + 0x06;
  456. break;
  457. case '7':
  458. val = (val * 16) + 0x07;
  459. break;
  460. case '8':
  461. val = (val * 16) + 0x08;
  462. break;
  463. case '9':
  464. val = (val * 16) + 0x09;
  465. break;
  466. case 'a':
  467. case 'A':
  468. val = (val * 16) + 0x0A;
  469. break;
  470. case 'b':
  471. case 'B':
  472. val = (val * 16) + 0x0B;
  473. break;
  474. case 'c':
  475. case 'C':
  476. val = (val * 16) + 0x0C;
  477. break;
  478. case 'd':
  479. case 'D':
  480. val = (val * 16) + 0x0D;
  481. break;
  482. case 'e':
  483. case 'E':
  484. val = (val * 16) + 0x0E;
  485. break;
  486. case 'f':
  487. case 'F':
  488. val = (val * 16) + 0x0F;
  489. break;
  490. default:
  491. // UGLY UGLY UGLY!
  492. goto sscanf_hex_switch;
  493. }
  494. ++str;
  495. }
  496. // UGLY UGLY UGLY - Needed for the double level break, which isn't native
  497. // in C.
  498. sscanf_hex_switch:
  499. // Save the pointer.
  500. *input = str;
  501. // Covert the sign and return without an if.
  502. return val;
  503. }
  504. int
  505. GetHex(char ** const input)
  506. {
  507. char *
  508. str = *input;
  509. int
  510. neg = 1;
  511. switch (*str)
  512. {
  513. case '-':
  514. neg = -1;
  515. // FALLTHROUGH
  516. case '+':
  517. // Check there is valid data after
  518. if (((unsigned char)(*(++str) - '0')) >= 10)
  519. {
  520. // Just return now, the caller will recognise this as bad.
  521. return 0;
  522. }
  523. }
  524. if (*str == '0')
  525. {
  526. if (*(str + 1) == 'x' || *(str + 1) == 'X')
  527. {
  528. // Check there is real data, otherwise it's bad.
  529. str += 2;
  530. if ((*str < '0') || ((*str > '9') && ((*str | 0x20) < 'a')) || ((*str | 0x20) > 'f'))
  531. {
  532. *input = str - 1;
  533. return 0;
  534. }
  535. }
  536. }
  537. else if ((*str < '0') || ((*str > '9') && ((*str | 0x20) < 'a')) || ((*str | 0x20) > 'f'))
  538. {
  539. *input = str;
  540. return 0;
  541. }
  542. *input = str;
  543. return GetHexValue(input) * neg;
  544. // Convert to a number and test it. Horribly manually optimised - one of
  545. // these days I'll try write an ASM hex reader and see how well that works.
  546. // Actually I think I have written one before, but I don't know where it is
  547. // and I'm not sure how optimised it is. Anyway, this version works and
  548. // avoids loads of big switches (although a single large switch may be more
  549. // efficient thinking about it).
  550. /*while ((cur = (unsigned char)((*str | 0x20) - '0')))
  551. {
  552. if (cur < 10)
  553. {
  554. // 0 - 9
  555. val = (val * 16) + cur;
  556. }
  557. else
  558. {
  559. cur -= ('a' - '0');
  560. if (cur < 6)
  561. {
  562. // A - F, a - f
  563. val = (val * 16) + cur + 10;
  564. }
  565. else
  566. {
  567. // End of the number.
  568. // Save the pointer.
  569. *input = str;
  570. // Covert the sign and return without an if.
  571. return val * neg;
  572. }
  573. }
  574. }*/
  575. }
  576. unsigned int
  577. GetBoolValue(char ** const input)
  578. {
  579. char *
  580. str = *input;
  581. unsigned int
  582. val = 0;
  583. for ( ; ; ++str)
  584. {
  585. if (*str == '0')
  586. {
  587. val <<= 1;
  588. }
  589. else if (*str == '1')
  590. {
  591. val = (val << 1) | 1;
  592. }
  593. else
  594. {
  595. break;
  596. }
  597. }
  598. // Save the pointer.
  599. *input = str;
  600. return val;
  601. }
  602. int
  603. GetBool(char ** const input)
  604. {
  605. char *
  606. str = *input;
  607. if (*str == '0')
  608. {
  609. if (*(str + 1) == 'b' || *(str + 1) == 'B')
  610. {
  611. // Check there is real data, otherwise it's bad.
  612. str += 2;
  613. if (*str != '0' && *str != '1')
  614. {
  615. *input = str - 1;
  616. return 0;
  617. }
  618. }
  619. }
  620. else if (*str != '1')
  621. {
  622. *input = str;
  623. return 0;
  624. }
  625. *input = str;
  626. return (int)GetBoolValue(input);
  627. }
  628. int
  629. GetNumber(char ** const input)
  630. {
  631. char *
  632. str = *input;
  633. int
  634. neg = 1;
  635. switch (*str)
  636. {
  637. case '-':
  638. neg = -1;
  639. // FALLTHROUGH
  640. case '+':
  641. // Check there is valid data after
  642. if (((unsigned char)(*(++str) - '0')) >= 10)
  643. {
  644. // Just return now, the caller will recognise this as bad.
  645. return 0;
  646. }
  647. }
  648. if (*str == '0')
  649. {
  650. ++str;
  651. switch (*str)
  652. {
  653. case 'x':
  654. case 'X':
  655. // Hex.
  656. ++str;
  657. if (((*str >= '0') && (*str <= '9')) || (((*str | 0x20) >= 'a') && ((*str | 0x20) <= 'f')))
  658. {
  659. *input = str;
  660. return GetHexValue(input) * neg;
  661. }
  662. else
  663. {
  664. *input = str - 1;
  665. return 0;
  666. }
  667. case 'b':
  668. case 'B':
  669. // Bool.
  670. if (neg == -1)
  671. {
  672. // Can't have negative booleans.
  673. *input = str;
  674. return 0;
  675. }
  676. else
  677. {
  678. ++str;
  679. if ((*str == '0') || (*str == '1'))
  680. {
  681. *input = str;
  682. return (int)GetBoolValue(input);
  683. }
  684. else
  685. {
  686. *input = str - 1;
  687. return 0;
  688. }
  689. }
  690. case '0':
  691. case '1':
  692. case '2':
  693. case '3':
  694. case '4':
  695. case '5':
  696. case '6':
  697. case '7':
  698. // Octal.
  699. *input = str;
  700. return GetOctValue(input) * neg;
  701. case '8':
  702. case '9':
  703. // Decimal.
  704. break;
  705. default:
  706. *input = str;
  707. return 0;
  708. }
  709. }
  710. else if ((*str < '0') || (*str > '9'))
  711. {
  712. *input = str;
  713. return 0;
  714. }
  715. *input = str;
  716. return GetDecValue(input) * neg;
  717. }
  718. bool
  719. GetLogical(char ** const input)
  720. {
  721. // Boolean values - if it's not '0' or 'false' then it's true. I could be
  722. // strict and make them enter '1' or 'true' for true, but I'm not going to.
  723. char *
  724. string = *input;
  725. bool
  726. ret;
  727. switch (*string++)
  728. {
  729. case '0':
  730. // Set the value to false till we decide otherwise.
  731. ret = false;
  732. while (!IsSpacer(*string))
  733. {
  734. if (*string++ != '0')
  735. {
  736. // Value is not false, thus is true.
  737. ret = true;
  738. break;
  739. }
  740. }
  741. // Let the cleanup code below handle excess chars.
  742. break;
  743. case 'f':
  744. case 'F':
  745. // Default to true unless we find "false" exactly.
  746. ret = true;
  747. if ((*string | 0x20) == 'a')
  748. {
  749. ++string;
  750. if ((*string | 0x20) == 'l')
  751. {
  752. ++string;
  753. if ((*string | 0x20) == 's')
  754. {
  755. ++string;
  756. if ((*string | 0x20) == 'e')
  757. {
  758. ++string;
  759. // We have the whole word, check that it's on its
  760. // own, i.e. is followed by a space or delimiter
  761. // Note that if your delimiter is in the word
  762. // "false", you may have a bug here but they seem
  763. // like odd delimiter characters tbh.
  764. if (IsSpacer(*string))
  765. {
  766. // Exact word found on its own so save the fact
  767. // that it's false.
  768. ret = false;
  769. }
  770. }
  771. }
  772. }
  773. }
  774. break;
  775. default:
  776. ret = true;
  777. break;
  778. }
  779. // Skip the rest of the data.
  780. *input = string;
  781. FindSpacer(input);
  782. return ret;
  783. }
  784. bool
  785. FindDefaultStart(char ** const str)
  786. {
  787. // Skip the default value passed for optional parameters.
  788. if (**str == '(')
  789. {
  790. ++(*str);
  791. SkipWhitespace(str);
  792. return true;
  793. }
  794. else
  795. {
  796. logprintf("sscanf warning: No default value found.");
  797. }
  798. return false;
  799. }
  800. void
  801. SkipDefault(char ** const str)
  802. {
  803. if (FindDefaultStart(str))
  804. {
  805. // Default value found - skip it.
  806. do
  807. {
  808. ++(*str);
  809. }
  810. while (**str && **str != ')');
  811. if (**str)
  812. {
  813. // Current pointer points to the close bracket, skip it.
  814. ++(*str);
  815. }
  816. else
  817. {
  818. logprintf("sscanf warning: Unclosed default value.");
  819. }
  820. }
  821. }
  822. void
  823. SkipDefaultEx(char ** const data)
  824. {
  825. // Skip the default value passed for optional parameters.
  826. char *
  827. str = *data;
  828. if (*str == '(')
  829. {
  830. // Default value found - skip it.
  831. bool
  832. escape = false;
  833. while (*str && (escape || *str != ')'))
  834. {
  835. if (*str == '\\')
  836. {
  837. // Invert the escape, they may do:
  838. // S(a\)
  839. // Where the default string is "a\", in which case we need a
  840. // way to tell the system not to include the close bracket,
  841. // which would be:
  842. // S(a\\)
  843. // Or, in real PAWN terms:
  844. // S(a\\\\)
  845. // Of course, they can also do:
  846. // S(\\\\\\\\\\))
  847. // To get a final string of "\\)". Yes, you need FOUR slashes
  848. // in a PAWN string to get just one in the output string.
  849. escape = !escape;
  850. }
  851. else
  852. {
  853. escape = false;
  854. }
  855. ++str;
  856. }
  857. if (*str)
  858. {
  859. // Current pointer points to the close bracket, skip it.
  860. ++str;
  861. }
  862. else
  863. {
  864. logprintf("sscanf warning: Unclosed default value.");
  865. }
  866. }
  867. else
  868. {
  869. logprintf("sscanf warning: No default value found.");
  870. }
  871. *data = str;
  872. }
  873. void
  874. SkipLength(char ** const input)
  875. {
  876. // Get an easy pointer to the data to manipulate.
  877. char *
  878. str = *input;
  879. if (*str == '[')
  880. {
  881. while (*(++str))
  882. {
  883. // Don't check the length is valid, that's effort and slow.
  884. if (*str == ']')
  885. {
  886. *input = str + 1;
  887. return;
  888. }
  889. }
  890. // If we get here then the end of the string was reached before the
  891. // valid end of the length.
  892. *input = str;
  893. logprintf("sscanf warning: Missing string length end.");
  894. }
  895. else
  896. {
  897. logprintf("sscanf warning: Arrays without a length are deprecated, please add a destination size.");
  898. }
  899. }
  900. int
  901. GetLength(char ** const input, bool error)
  902. {
  903. if (**input == '[')
  904. {
  905. ++(*input);
  906. int
  907. length = GetDec(input);
  908. char *
  909. str = *input;
  910. if (length <= 0)
  911. {
  912. if (error)
  913. {
  914. length = 0;
  915. logprintf("sscanf error: Invalid data length.");
  916. }
  917. else
  918. {
  919. length = SSCANF_MAX_LENGTH;
  920. logprintf("sscanf warning: Invalid data length.");
  921. }
  922. }
  923. if (*str == ']')
  924. {
  925. // Valid end: [number]
  926. *input = str + 1;
  927. return length;
  928. }
  929. else if (*str)
  930. {
  931. // Invalid character: [numberX]
  932. logprintf("sscanf warning: Invalid character in data length.");
  933. // Loop through the string till we find an end to the size.
  934. while (*(++str))
  935. {
  936. if (*str == ']')
  937. {
  938. // Valid end: [numberX]
  939. *input = str + 1;
  940. return length;
  941. }
  942. }
  943. }
  944. // Invalid end: [number
  945. logprintf("sscanf warning: Missing length end.");
  946. *input = str;
  947. return length;
  948. }
  949. else if (error)
  950. {
  951. logprintf("sscanf error: String/array must include a length, please add a destination size.");
  952. return 0;
  953. }
  954. else
  955. {
  956. logprintf("sscanf warning: Strings without a length are deprecated, please add a destination size.");
  957. return SSCANF_MAX_LENGTH;
  958. }
  959. }
  960. void
  961. GetJaggedSlot(cell * start, int count, int size, int slot, cell ** rs, int * rl)
  962. {
  963. // Get the start of the real data after the header.
  964. cell
  965. * cur,
  966. * dstart = start + count,
  967. * dend = dstart + (count * size),
  968. * sstart = (cell *)((char *)(start + slot) + *(start + slot));
  969. while (start < dstart)
  970. {
  971. cur = (cell *)((char *)start + *start);
  972. // Use "<" not "<=" to avoid assigning 0-length slots.
  973. if (sstart < cur && cur < dend)
  974. {
  975. dend = cur;
  976. }
  977. // else if (sstart == cur && slot--)
  978. //{
  979. // // Do something about the fact that we just found a 0 length slot.
  980. //}
  981. ++start;
  982. }
  983. *rs = sstart;
  984. *rl = (dend - sstart);
  985. }