sscanf.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537
  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. * SA:MP team - plugin framework.
  23. *
  24. * Special Thanks to:
  25. *
  26. * SA:MP Team past, present and future
  27. */
  28. #include <malloc.h>
  29. #include <string.h>
  30. #include "sscanf.h"
  31. #include "specifiers.h"
  32. #include "utils.h"
  33. #include "data.h"
  34. #include "array.h"
  35. #include "enum.h"
  36. #include "SDK/amx/amx.h"
  37. #include "SDK/plugincommon.h"
  38. //----------------------------------------------------------
  39. logprintf_t
  40. logprintf,
  41. real_logprintf;
  42. AMX_NATIVE
  43. SetPlayerName;
  44. //GetServer_t
  45. // GetServer;
  46. extern void *
  47. pAMXFunctions;
  48. //extern int
  49. // g_iServerVersion;
  50. extern unsigned int
  51. g_iTrueMax,
  52. g_iInvalid,
  53. g_iMaxPlayerName;
  54. extern int *
  55. g_iConnected;
  56. extern int *
  57. g_iNPC;
  58. extern char *
  59. g_szPlayerNames;
  60. extern int
  61. gOptions;
  62. AMX *
  63. g_aCurAMX;
  64. //extern char
  65. // ** g_pServer;
  66. #define SAVE_VALUE(m) \
  67. if (doSave) \
  68. amx_GetAddr(amx, params[paramPos++], &cptr), *cptr = m
  69. #define SAVE_VALUE_F(m) \
  70. if (doSave) { \
  71. float f = (float)m; \
  72. amx_GetAddr(amx, params[paramPos++], &cptr), *cptr = amx_ftoc(f); }
  73. // Based on amx_StrParam but using 0 length strings. This can't be inline as
  74. // it uses alloca - it could be written to use malloc instead, but that would
  75. // require memory free code all over the place!
  76. #define STR_PARAM(amx,param,result) \
  77. do { \
  78. cell * amx_cstr_; int amx_length_; \
  79. amx_GetAddr((amx), (param), &amx_cstr_); \
  80. amx_StrLen(amx_cstr_, &amx_length_); \
  81. if (amx_length_ > 0) { \
  82. if (((result) = (char *)alloca((amx_length_ + 1) * sizeof (*(result)))) != NULL) \
  83. amx_GetString((result), amx_cstr_, sizeof (*(result)) > 1, amx_length_ + 1); \
  84. else { \
  85. logprintf("sscanf error: Unable to allocate memory."); \
  86. return SSCANF_FAIL_RETURN; } } \
  87. else (result) = ""; } \
  88. while (false)
  89. // Macros for the regular values.
  90. #define DO(m,n) \
  91. {m b; \
  92. if (Do##n(&string, &b)) { \
  93. SAVE_VALUE((cell)b); \
  94. break; } \
  95. RestoreOpts(defaultOpts); \
  96. return SSCANF_FAIL_RETURN; }
  97. #define DOV(m,n) \
  98. {m b; \
  99. Do##n(&string, &b); \
  100. SAVE_VALUE((cell)b); }
  101. #define DOF(m,n) \
  102. {m b; \
  103. if (Do##n(&string, &b)) { \
  104. SAVE_VALUE_F(b) \
  105. break; } \
  106. RestoreOpts(defaultOpts); \
  107. return SSCANF_FAIL_RETURN; }
  108. // Macros for the default values. None of these have ifs as the return value
  109. // of GetReturnDefault is always true - we don't penalise users for the
  110. // mistakes of the coder - they will get warning messages if they get the
  111. // format wrong, and I don't know of any mistkes which aren't warned about
  112. // (admittedly a silly statement as if I did I would have fixed them).
  113. #define DE(m,n) \
  114. {m b; \
  115. Do##n##D(&format, &b); \
  116. SAVE_VALUE((cell)b); \
  117. break; }
  118. #define DEF(m,n) \
  119. {m b; \
  120. Do##n##D(&format, &b); \
  121. SAVE_VALUE_F(b) \
  122. break; }
  123. // Macros for the default values in the middle of a string so you can do:
  124. //
  125. // sscanf("hello, , 10", "p<,>sI(42)i", str, var0, var1);
  126. //
  127. // Note that optional parameters in the middle of a string only work with
  128. // explicit (i.e. not whitespace) delimiters.
  129. #define DX(m,n) \
  130. if (IsDelimiter(*string)) { \
  131. m b; \
  132. Do##n##D(&format, &b); \
  133. SAVE_VALUE((cell)b); \
  134. break; } \
  135. SkipDefault(&format);
  136. #define DXF(m,n) \
  137. if (IsDelimiter(*string)) { \
  138. m b; \
  139. Do##n##D(&format, &b); \
  140. SAVE_VALUE_F(b) \
  141. break; } \
  142. SkipDefault(&format);
  143. bool
  144. DoK(AMX * amx, char ** defaults, char ** input, cell * cptr, bool optional);
  145. void
  146. DoOptions(char *, cell);
  147. // native sscanf(const data[], const format[], (Float,_}:...);
  148. static cell AMX_NATIVE_CALL
  149. n_sscanf(AMX * amx, cell * params)
  150. {
  151. if (g_iTrueMax == 0)
  152. {
  153. logprintf("sscanf error: System not initialised.");
  154. return SSCANF_FAIL_RETURN;
  155. }
  156. // Friendly note, the most complex set of specifier additions is:
  157. //
  158. // A<i>(10, 11)[5]
  159. //
  160. // In that exact order - type, default, size. It's very opposite to how
  161. // it's done in code, where you would do the eqivalent to:
  162. //
  163. // <i>[5] = {10, 11}
  164. //
  165. // But this method is vastly simpler to parse in this context! Technically
  166. // you can, due to legacy support for 'p', do:
  167. //
  168. // Ai(10, 11)[5]
  169. //
  170. // But you will get an sscanf warning, and I may remove that ability from
  171. // the start - that will mean a new function, but an easy to write one.
  172. // In fact the most complex will probably be something like:
  173. //
  174. // E<ifs[32]s[8]d>(10, 12.3, Hello there, Hi, 42)
  175. //
  176. // Get the number of parameters passed. We add one as the indexes are out
  177. // by one (OBOE - Out By One Error) due to params[0] being the parameter
  178. // count, not an actual parameter.
  179. const int
  180. paramCount = ((int)params[0] / 4) + 1;
  181. // Could add a check for only 3 parameters here - I can't think of a time
  182. // when you would not want any return values at all, but that doesn't mean
  183. // they don't exist - you could just want to check but not save the format.
  184. // Update - that is now a possibility with the '{...}' specifiers.
  185. if (paramCount < (2 + 1))
  186. {
  187. logprintf("sscanf error: Missing required parameters.");
  188. return SSCANF_FAIL_RETURN;
  189. }
  190. //else if (paramCount == (2 + 1))
  191. //{
  192. // Only have an input and a specifier - better hope the whole specifier
  193. // is quite (i.e. enclosed in '{...}').
  194. //}
  195. // Set up function wide values.
  196. // Get and check the main data.
  197. // Pointer to the current input data.
  198. char *
  199. string;
  200. STR_PARAM(amx, params[1], string);
  201. // Pointer to the current format specifier.
  202. char *
  203. format;
  204. STR_PARAM(amx, params[2], format);
  205. // Check for CallRemoteFunction style null strings and correct.
  206. if (string[0] == '\1' && string[1] == '\0')
  207. {
  208. string[0] = '\0';
  209. }
  210. // Save the default options so we can have local modifications.
  211. int
  212. defaultOpts = gOptions;
  213. // Current parameter to save data to.
  214. int
  215. paramPos = 3;
  216. cell *
  217. cptr;
  218. InitialiseDelimiter();
  219. // Skip leading space.
  220. SkipWhitespace(&string);
  221. bool
  222. doSave;
  223. // Code for the rare cases where the WHOLE format is quiet.
  224. if (*format == '{')
  225. {
  226. ++format;
  227. doSave = false;
  228. }
  229. else
  230. {
  231. doSave = true;
  232. }
  233. g_aCurAMX = amx;
  234. // Now do the main loop as long as there are variables to store the data in
  235. // and input string remaining to get the data from.
  236. while (*string && (paramPos < paramCount || !doSave))
  237. {
  238. if (!*format)
  239. {
  240. // End of the format string - if we're here we've got all the
  241. // parameters but there is extra string or variables, which may
  242. // indicate their code needs fixing, for example:
  243. // sscanf(data, "ii", var0, var1, var3, var4);
  244. // There is only two format specifiers, but four returns. This may
  245. // also be reached if there is too much input data, but that is
  246. // considered OK as that is likely a user's fault.
  247. if (paramPos < paramCount)
  248. {
  249. logprintf("sscanf warning: Format specifier does not match parameter count.");
  250. }
  251. if (!doSave)
  252. {
  253. // Started a quiet section but never explicitly ended it.
  254. logprintf("sscanf warning: Unclosed quiet section.");
  255. }
  256. RestoreOpts(defaultOpts);
  257. return SSCANF_TRUE_RETURN;
  258. }
  259. else if (IsWhitespace(*format))
  260. {
  261. ++format;
  262. }
  263. else
  264. {
  265. switch (*format++)
  266. {
  267. case 'L':
  268. DX(bool, L)
  269. // FALLTHROUGH
  270. case 'l':
  271. DOV(bool, L)
  272. break;
  273. case 'B':
  274. DX(int, B)
  275. // FALLTHROUGH
  276. case 'b':
  277. DO(int, B)
  278. case 'N':
  279. DX(int, N)
  280. // FALLTHROUGH
  281. case 'n':
  282. DO(int, N)
  283. case 'C':
  284. DX(char, C)
  285. // FALLTHROUGH
  286. case 'c':
  287. DO(char, C)
  288. case 'I':
  289. case 'D':
  290. DX(int, I)
  291. // FALLTHROUGH
  292. case 'i':
  293. case 'd':
  294. DO(int, I)
  295. case 'H':
  296. case 'X':
  297. DX(int, H)
  298. // FALLTHROUGH
  299. case 'h':
  300. case 'x':
  301. DO(int, H)
  302. case 'O':
  303. DX(int, O)
  304. // FALLTHROUGH
  305. case 'o':
  306. DO(int, O)
  307. case 'F':
  308. DXF(double, F)
  309. // FALLTHROUGH
  310. case 'f':
  311. DOF(double, F)
  312. case 'G':
  313. DXF(double, G)
  314. // FALLTHROUGH
  315. case 'g':
  316. DOF(double, G)
  317. case '{':
  318. if (doSave)
  319. {
  320. doSave = false;
  321. }
  322. else
  323. {
  324. // Already in a quiet section.
  325. logprintf("sscanf warning: Can't have nestled quiet sections.");
  326. }
  327. continue;
  328. case '}':
  329. if (doSave)
  330. {
  331. logprintf("sscanf warning: Not in a quiet section.");
  332. }
  333. else
  334. {
  335. doSave = true;
  336. }
  337. continue;
  338. case 'P':
  339. {
  340. ResetDelimiter();
  341. char *
  342. t = GetMultiType(&format);
  343. if (t) AddDelimiters(t);
  344. else return SSCANF_FAIL_RETURN;
  345. continue;
  346. }
  347. // FALLTHROUGH
  348. case 'p':
  349. // 'P' doesn't exist.
  350. // Theoretically, for compatibility, this should be:
  351. // p<delimiter>, but that will break backwards
  352. // compatibility with anyone doing "p<" to use '<' as a
  353. // delimiter (doesn't matter how rare that may be). Also,
  354. // writing deprecation code and both the new and old code
  355. // is more trouble than it's worth, and it's slow.
  356. // UPDATE: I wrote the "GetSingleType" code for 'a' and
  357. // figured out a way to support legacy and new code, while
  358. // still maintaining support for the legacy "p<" separator,
  359. // so here it is:
  360. ResetDelimiter();
  361. AddDelimiter(GetSingleType(&format));
  362. continue;
  363. case 'Z':
  364. logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  365. // FALLTHROUGH
  366. case 'z':
  367. logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  368. // FALLTHROUGH
  369. case 'S':
  370. if (IsDelimiter(*string))
  371. {
  372. char *
  373. dest;
  374. int
  375. length;
  376. if (DoSD(&format, &dest, &length))
  377. {
  378. // Send the string to PAWN.
  379. if (doSave)
  380. {
  381. amx_GetAddr(amx, params[paramPos++], &cptr);
  382. amx_SetString(cptr, dest, 0, 0, length);
  383. }
  384. }
  385. break;
  386. }
  387. // Implicit "else".
  388. SkipDefaultEx(&format);
  389. // FALLTHROUGH
  390. case 's':
  391. {
  392. // Get the length.
  393. int
  394. length = GetLength(&format, false);
  395. char *
  396. dest;
  397. DoS(&string, &dest, length, IsEnd(*format) || (!doSave && *format == '}' && IsEnd(*(format + 1))));
  398. // Send the string to PAWN.
  399. if (doSave)
  400. {
  401. amx_GetAddr(amx, params[paramPos++], &cptr);
  402. amx_SetString(cptr, dest, 0, 0, length);
  403. }
  404. }
  405. break;
  406. case 'U':
  407. if (IsDelimiter(*string))
  408. {
  409. int
  410. b;
  411. DoUD(&format, &b);
  412. if (*format == '[')
  413. {
  414. int
  415. len = GetLength(&format, true);
  416. if (gOptions & 1)
  417. {
  418. // Incompatible combination.
  419. logprintf("sscanf error: 'U(name)[len]' is incompatible with OLD_DEFAULT_NAME.");
  420. return SSCANF_FAIL_RETURN;
  421. }
  422. else if (len < 2)
  423. {
  424. logprintf("sscanf error: 'U(num)[len]' length under 2.");
  425. return SSCANF_FAIL_RETURN;
  426. }
  427. else if (doSave)
  428. {
  429. amx_GetAddr(amx, params[paramPos++], &cptr);
  430. *cptr++ = b;
  431. *cptr = g_iInvalid;
  432. }
  433. }
  434. else
  435. {
  436. SAVE_VALUE((cell)b);
  437. }
  438. break;
  439. }
  440. SkipDefault(&format);
  441. // FALLTHROUGH
  442. case 'u':
  443. if (*format == '[')
  444. {
  445. int
  446. len = GetLength(&format, true);
  447. if (len < 2)
  448. {
  449. logprintf("sscanf error: 'u[len]' length under 2.");
  450. return SSCANF_FAIL_RETURN;
  451. }
  452. else
  453. {
  454. int
  455. b = -1,
  456. od = gOptions;
  457. if (doSave)
  458. {
  459. char *
  460. tstr;
  461. // Don't detect multiple results.
  462. gOptions &= ~4;
  463. amx_GetAddr(amx, params[paramPos++], &cptr);
  464. while (--len)
  465. {
  466. tstr = string;
  467. if (!DoU(&tstr, &b, b + 1))
  468. {
  469. *cptr++ = b;
  470. b = g_iInvalid;
  471. break;
  472. }
  473. if (b == g_iInvalid) break;
  474. *cptr++ = b;
  475. }
  476. if (b == g_iInvalid)
  477. {
  478. *cptr = g_iInvalid;
  479. }
  480. else
  481. {
  482. tstr = string;
  483. DoU(&tstr, &b, b + 1);
  484. if (b == g_iInvalid) *cptr = g_iInvalid;
  485. else *cptr = 0x80000000;
  486. }
  487. // Restore results detection.
  488. gOptions = od;
  489. string = tstr;
  490. }
  491. else
  492. {
  493. DoU(&string, &b, 0);
  494. }
  495. }
  496. }
  497. else
  498. {
  499. int
  500. b;
  501. DoU(&string, &b, 0);
  502. SAVE_VALUE((cell)b);
  503. }
  504. break;
  505. case 'Q':
  506. if (IsDelimiter(*string))
  507. {
  508. int
  509. b;
  510. DoQD(&format, &b);
  511. if (*format == '[')
  512. {
  513. int
  514. len = GetLength(&format, true);
  515. if (gOptions & 1)
  516. {
  517. // Incompatible combination.
  518. logprintf("sscanf error: 'Q(name)[len]' is incompatible with OLD_DEFAULT_NAME.");
  519. return SSCANF_FAIL_RETURN;
  520. }
  521. else if (len < 2)
  522. {
  523. logprintf("sscanf error: 'Q(num)[len]' length under 2.");
  524. return SSCANF_FAIL_RETURN;
  525. }
  526. else if (doSave)
  527. {
  528. amx_GetAddr(amx, params[paramPos++], &cptr);
  529. *cptr++ = b;
  530. *cptr = g_iInvalid;
  531. }
  532. }
  533. else
  534. {
  535. SAVE_VALUE((cell)b);
  536. }
  537. break;
  538. }
  539. SkipDefault(&format);
  540. // FALLTHROUGH
  541. case 'q':
  542. if (*format == '[')
  543. {
  544. int
  545. len = GetLength(&format, true);
  546. if (len < 2)
  547. {
  548. logprintf("sscanf error: 'q[len]' length under 2.");
  549. return SSCANF_FAIL_RETURN;
  550. }
  551. else
  552. {
  553. int
  554. b = -1,
  555. od = gOptions;
  556. if (doSave)
  557. {
  558. char *
  559. tstr;
  560. // Don't detect multiple results.
  561. gOptions &= ~4;
  562. amx_GetAddr(amx, params[paramPos++], &cptr);
  563. while (--len)
  564. {
  565. tstr = string;
  566. if (!DoQ(&tstr, &b, b + 1))
  567. {
  568. *cptr++ = b;
  569. b = g_iInvalid;
  570. break;
  571. }
  572. if (b == g_iInvalid) break;
  573. *cptr++ = b;
  574. }
  575. if (b == g_iInvalid)
  576. {
  577. *cptr = g_iInvalid;
  578. }
  579. else
  580. {
  581. tstr = string;
  582. DoQ(&tstr, &b, b + 1);
  583. if (b == g_iInvalid) *cptr = g_iInvalid;
  584. else *cptr = 0x80000000;
  585. }
  586. // Restore results detection.
  587. gOptions = od;
  588. string = tstr;
  589. }
  590. else
  591. {
  592. DoQ(&string, &b, 0);
  593. }
  594. }
  595. }
  596. else
  597. {
  598. int
  599. b;
  600. DoQ(&string, &b, 0);
  601. SAVE_VALUE((cell)b);
  602. }
  603. break;
  604. case 'R':
  605. if (IsDelimiter(*string))
  606. {
  607. int
  608. b;
  609. DoRD(&format, &b);
  610. if (*format == '[')
  611. {
  612. int
  613. len = GetLength(&format, true);
  614. if (gOptions & 1)
  615. {
  616. // Incompatible combination.
  617. logprintf("sscanf error: 'R(name)[len]' is incompatible with OLD_DEFAULT_NAME.");
  618. return SSCANF_FAIL_RETURN;
  619. }
  620. else if (len < 2)
  621. {
  622. logprintf("sscanf error: 'R(num)[len]' length under 2.");
  623. return SSCANF_FAIL_RETURN;
  624. }
  625. else if (doSave)
  626. {
  627. amx_GetAddr(amx, params[paramPos++], &cptr);
  628. *cptr++ = b;
  629. *cptr = g_iInvalid;
  630. }
  631. }
  632. else
  633. {
  634. SAVE_VALUE((cell)b);
  635. }
  636. break;
  637. }
  638. SkipDefault(&format);
  639. // FALLTHROUGH
  640. case 'r':
  641. if (*format == '[')
  642. {
  643. int
  644. len = GetLength(&format, true);
  645. if (len < 2)
  646. {
  647. logprintf("sscanf error: 'r[len]' length under 2.");
  648. return SSCANF_FAIL_RETURN;
  649. }
  650. else
  651. {
  652. int
  653. b = -1,
  654. od = gOptions;
  655. if (doSave)
  656. {
  657. char *
  658. tstr;
  659. // Don't detect multiple results.
  660. gOptions &= ~4;
  661. amx_GetAddr(amx, params[paramPos++], &cptr);
  662. while (--len)
  663. {
  664. tstr = string;
  665. if (!DoR(&tstr, &b, b + 1))
  666. {
  667. *cptr++ = b;
  668. b = g_iInvalid;
  669. break;
  670. }
  671. if (b == g_iInvalid) break;
  672. *cptr++ = b;
  673. }
  674. if (b == g_iInvalid)
  675. {
  676. *cptr = g_iInvalid;
  677. }
  678. else
  679. {
  680. tstr = string;
  681. DoR(&tstr, &b, b + 1);
  682. if (b == g_iInvalid) *cptr = g_iInvalid;
  683. else *cptr = 0x80000000;
  684. }
  685. // Restore results detection.
  686. gOptions = od;
  687. string = tstr;
  688. }
  689. else
  690. {
  691. DoR(&string, &b, 0);
  692. }
  693. }
  694. }
  695. else
  696. {
  697. int
  698. b;
  699. DoR(&string, &b, 0);
  700. SAVE_VALUE((cell)b);
  701. }
  702. break;
  703. case 'A':
  704. // We need the default values here.
  705. if (doSave)
  706. {
  707. amx_GetAddr(amx, params[paramPos++], &cptr);
  708. if (DoA(&format, &string, cptr, true))
  709. {
  710. break;
  711. }
  712. }
  713. else
  714. {
  715. // Pass a NULL pointer so data isn't saved anywhere.
  716. if (DoA(&format, &string, NULL, true))
  717. {
  718. break;
  719. }
  720. }
  721. RestoreOpts(defaultOpts);
  722. return SSCANF_FAIL_RETURN;
  723. case 'a':
  724. if (doSave)
  725. {
  726. amx_GetAddr(amx, params[paramPos++], &cptr);
  727. if (DoA(&format, &string, cptr, false))
  728. {
  729. break;
  730. }
  731. }
  732. else
  733. {
  734. // Pass a NULL pointer so data isn't saved anywhere.
  735. if (DoA(&format, &string, NULL, false))
  736. {
  737. break;
  738. }
  739. }
  740. RestoreOpts(defaultOpts);
  741. return SSCANF_FAIL_RETURN;
  742. case 'E':
  743. // We need the default values here.
  744. if (doSave)
  745. {
  746. amx_GetAddr(amx, params[paramPos++], &cptr);
  747. if (DoE(&format, &string, cptr, true))
  748. {
  749. break;
  750. }
  751. }
  752. else
  753. {
  754. // Pass a NULL pointer so data isn't saved anywhere.
  755. if (DoE(&format, &string, NULL, true))
  756. {
  757. break;
  758. }
  759. }
  760. RestoreOpts(defaultOpts);
  761. return SSCANF_FAIL_RETURN;
  762. case 'e':
  763. if (doSave)
  764. {
  765. amx_GetAddr(amx, params[paramPos++], &cptr);
  766. if (DoE(&format, &string, cptr, false))
  767. {
  768. break;
  769. }
  770. }
  771. else
  772. {
  773. // Pass a NULL pointer so data isn't saved anywhere.
  774. if (DoE(&format, &string, NULL, false))
  775. {
  776. break;
  777. }
  778. }
  779. RestoreOpts(defaultOpts);
  780. return SSCANF_FAIL_RETURN;
  781. case 'K':
  782. // We need the default values here.
  783. if (doSave)
  784. {
  785. amx_GetAddr(amx, params[paramPos++], &cptr);
  786. if (DoK(amx, &format, &string, cptr, true))
  787. {
  788. break;
  789. }
  790. }
  791. else
  792. {
  793. // Pass a NULL pointer so data isn't saved anywhere.
  794. if (DoK(amx, &format, &string, NULL, true))
  795. {
  796. break;
  797. }
  798. }
  799. RestoreOpts(defaultOpts);
  800. return SSCANF_FAIL_RETURN;
  801. case 'k':
  802. if (doSave)
  803. {
  804. amx_GetAddr(amx, params[paramPos++], &cptr);
  805. if (DoK(amx, &format, &string, cptr, false))
  806. {
  807. break;
  808. }
  809. }
  810. else
  811. {
  812. // Pass a NULL pointer so data isn't saved anywhere.
  813. if (DoK(amx, &format, &string, NULL, false))
  814. {
  815. break;
  816. }
  817. }
  818. RestoreOpts(defaultOpts);
  819. return SSCANF_FAIL_RETURN;
  820. case '\'':
  821. // Find the end of the literal.
  822. {
  823. char
  824. * str = format,
  825. * write = format;
  826. bool
  827. escape = false;
  828. while (!IsEnd(*str) && (escape || *str != '\''))
  829. {
  830. if (*str == '\\')
  831. {
  832. if (escape)
  833. {
  834. // "\\" - Go back a step to write this
  835. // character over the last character (which
  836. // just happens to be the same character).
  837. --write;
  838. }
  839. escape = !escape;
  840. }
  841. else
  842. {
  843. if (*str == '\'')
  844. {
  845. // Overwrite the escape character with the
  846. // quote character. Must have been
  847. // preceeded by a slash or it wouldn't have
  848. // got to here in the loop.
  849. --write;
  850. }
  851. escape = false;
  852. }
  853. // Copy the string over itself to get rid of excess
  854. // escape characters.
  855. // Not sure if it's faster in the average case to
  856. // always do the copy or check if it's needed.
  857. // This write is always safe as it makes the string
  858. // shorter, so we'll never run out of space. It
  859. // will also not overwrite the original string.
  860. *write++ = *str++;
  861. }
  862. if (*str == '\'')
  863. {
  864. // Correct end. Make a shorter string to search
  865. // for.
  866. *write = '\0';
  867. // Find the current section of format in string.
  868. char *
  869. find = strstr(string, format);
  870. if (!find)
  871. {
  872. // Didn't find the string
  873. RestoreOpts(defaultOpts);
  874. return SSCANF_FAIL_RETURN;
  875. }
  876. // Found the string. Update the current string
  877. // position to the length of the search term
  878. // further along from the start of the term. Use
  879. // "write" here as we want the escaped string
  880. // length.
  881. string = find + (write - format);
  882. // Move to after the end of the search string. Use
  883. // "str" here as we want the unescaped string
  884. // length.
  885. format = str + 1;
  886. }
  887. else
  888. {
  889. logprintf("sscanf warning: Unclosed string literal.");
  890. char *
  891. find = strstr(string, format);
  892. if (!find)
  893. {
  894. RestoreOpts(defaultOpts);
  895. return SSCANF_FAIL_RETURN;
  896. }
  897. string = find + (write - format);
  898. format = str;
  899. }
  900. }
  901. break;
  902. case '?':
  903. {
  904. char *
  905. t = GetMultiType(&format);
  906. if (t) DoOptions(t, -1);
  907. else return SSCANF_FAIL_RETURN;
  908. continue;
  909. }
  910. case '%':
  911. logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  912. continue;
  913. default:
  914. logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  915. continue;
  916. }
  917. // Loop cleanup - only skip one spacer so that we can detect
  918. // multiple explicit delimiters in a row, for example:
  919. //
  920. // hi there
  921. //
  922. // is NOT multiple explicit delimiters in a row (they're
  923. // whitespace). This however is:
  924. //
  925. // hi , , , there
  926. //
  927. SkipOneSpacer(&string);
  928. }
  929. }
  930. // Temporary to the end of the code.
  931. ResetDelimiter();
  932. AddDelimiter(')');
  933. // We don't need code here to handle the case where paramPos was reached,
  934. // but the end of the string wasn't - if that's the case there's no
  935. // problem as we just ignore excess string data.
  936. while (paramPos < paramCount || !doSave)
  937. {
  938. // Loop through if there's still parameters remaining.
  939. if (!*format)
  940. {
  941. logprintf("sscanf warning: Format specifier does not match parameter count.");
  942. if (!doSave)
  943. {
  944. // Started a quiet section but never explicitly ended it.
  945. logprintf("sscanf warning: Unclosed quiet section.");
  946. }
  947. RestoreOpts(defaultOpts);
  948. return SSCANF_TRUE_RETURN;
  949. }
  950. else if (IsWhitespace(*format))
  951. {
  952. ++format;
  953. }
  954. else
  955. {
  956. // Do the main switch again.
  957. switch (*format++)
  958. {
  959. case 'L':
  960. DE(bool, L)
  961. case 'B':
  962. DE(int, B)
  963. case 'N':
  964. DE(int, N)
  965. case 'C':
  966. DE(char, C)
  967. case 'I':
  968. case 'D':
  969. DE(int, I)
  970. case 'H':
  971. case 'X':
  972. DE(int, H)
  973. case 'O':
  974. DE(int, O)
  975. case 'F':
  976. DEF(double, F)
  977. case 'G':
  978. DEF(double, G)
  979. case 'U':
  980. DE(int, U)
  981. case 'Q':
  982. DE(int, Q)
  983. case 'R':
  984. DE(int, R)
  985. case 'A':
  986. if (doSave)
  987. {
  988. amx_GetAddr(amx, params[paramPos++], &cptr);
  989. if (DoA(&format, NULL, cptr, true))
  990. {
  991. break;
  992. }
  993. }
  994. else
  995. {
  996. // Pass a NULL pointer so data isn't saved anywhere.
  997. // Also pass NULL data so it knows to only collect the
  998. // default values.
  999. if (DoA(&format, NULL, NULL, true))
  1000. {
  1001. break;
  1002. }
  1003. }
  1004. RestoreOpts(defaultOpts);
  1005. return SSCANF_FAIL_RETURN;
  1006. case 'E':
  1007. if (doSave)
  1008. {
  1009. amx_GetAddr(amx, params[paramPos++], &cptr);
  1010. if (DoE(&format, NULL, cptr, true))
  1011. {
  1012. break;
  1013. }
  1014. }
  1015. else
  1016. {
  1017. // Pass a NULL pointer so data isn't saved anywhere.
  1018. // Also pass NULL data so it knows to only collect the
  1019. // default values.
  1020. if (DoE(&format, NULL, NULL, true))
  1021. {
  1022. break;
  1023. }
  1024. }
  1025. RestoreOpts(defaultOpts);
  1026. return SSCANF_FAIL_RETURN;
  1027. case 'K':
  1028. if (doSave)
  1029. {
  1030. amx_GetAddr(amx, params[paramPos++], &cptr);
  1031. if (DoK(amx, &format, NULL, cptr, true))
  1032. {
  1033. break;
  1034. }
  1035. }
  1036. else
  1037. {
  1038. // Pass a NULL pointer so data isn't saved anywhere.
  1039. // Also pass NULL data so it knows to only collect the
  1040. // default values.
  1041. if (DoK(amx, &format, NULL, NULL, true))
  1042. {
  1043. break;
  1044. }
  1045. }
  1046. RestoreOpts(defaultOpts);
  1047. return SSCANF_FAIL_RETURN;
  1048. case '{':
  1049. if (doSave)
  1050. {
  1051. doSave = false;
  1052. }
  1053. else
  1054. {
  1055. // Already in a quiet section.
  1056. logprintf("sscanf warning: Can't have nestled quiet sections.");
  1057. }
  1058. break;
  1059. case '}':
  1060. if (doSave)
  1061. {
  1062. logprintf("sscanf warning: Not in a quiet section.");
  1063. }
  1064. else
  1065. {
  1066. doSave = true;
  1067. }
  1068. break;
  1069. case 'Z':
  1070. logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  1071. // FALLTHROUGH
  1072. case 'z':
  1073. logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  1074. // FALLTHROUGH
  1075. case 'S':
  1076. {
  1077. char *
  1078. dest;
  1079. int
  1080. length;
  1081. if (DoSD(&format, &dest, &length))
  1082. {
  1083. // Send the string to PAWN.
  1084. if (doSave)
  1085. {
  1086. amx_GetAddr(amx, params[paramPos++], &cptr);
  1087. amx_SetString(cptr, dest, 0, 0, length);
  1088. }
  1089. }
  1090. }
  1091. break;
  1092. case 'P':
  1093. //logprintf("sscanf warning: You can't have an optional delimiter.");
  1094. GetMultiType(&format);
  1095. continue;
  1096. // FALLTHROUGH
  1097. case 'p':
  1098. // Discard delimiter. This only matters when they have
  1099. // real inputs, not the default ones used here.
  1100. GetSingleType(&format);
  1101. continue;
  1102. case '\'':
  1103. // Implicitly optional if the specifiers after it are
  1104. // optional.
  1105. {
  1106. bool
  1107. escape = false;
  1108. while (!IsEnd(*format) && (escape || *format != '\''))
  1109. {
  1110. if (*format == '\\')
  1111. {
  1112. escape = !escape;
  1113. }
  1114. else
  1115. {
  1116. escape = false;
  1117. }
  1118. ++format;
  1119. }
  1120. if (*format == '\'')
  1121. {
  1122. ++format;
  1123. }
  1124. else
  1125. {
  1126. logprintf("sscanf warning: Unclosed string literal.");
  1127. }
  1128. }
  1129. break;
  1130. // Large block of specifiers all together.
  1131. case 'a':
  1132. case 'b':
  1133. case 'c':
  1134. case 'd':
  1135. case 'e':
  1136. case 'f':
  1137. case 'g':
  1138. case 'h':
  1139. case 'i':
  1140. case 'k':
  1141. case 'l':
  1142. case 'n':
  1143. case 'o':
  1144. case 'q':
  1145. case 'r':
  1146. case 's':
  1147. case 'u':
  1148. case 'x':
  1149. // These are non optional items, but the input string
  1150. // didn't include them, so we fail - this is in fact the
  1151. // most basic definition of a fail (the original)! We
  1152. // don't need any text warnings here - admittedly we don't
  1153. // know if the format specifier is well formed (there may
  1154. // not be enough return variables for example), but it
  1155. // doesn't matter - the coder should have tested for those
  1156. // things, and the more important thing is that the user
  1157. // didn't enter the correct data.
  1158. RestoreOpts(defaultOpts);
  1159. return SSCANF_FAIL_RETURN;
  1160. case '?':
  1161. GetMultiType(&format);
  1162. continue;
  1163. case '%':
  1164. logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  1165. break;
  1166. default:
  1167. logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  1168. break;
  1169. }
  1170. // Don't need any cleanup here.
  1171. }
  1172. }
  1173. if (*format)
  1174. {
  1175. do
  1176. {
  1177. if (!IsWhitespace(*format))
  1178. {
  1179. // Only print this warning if the remaining characters are not
  1180. // spaces - spaces are allowed, and sometimes required, on the
  1181. // ends of formats (e.g. to stop the final 's' specifier
  1182. // collecting all remaining characters and only get one word).
  1183. // We could check that the remaining specifier is a valid one,
  1184. // but this is only a guide - they shouldn't even have other
  1185. // characters IN the specifier so it doesn't matter - it will
  1186. // point to a bug, which is the important thing.
  1187. if (doSave)
  1188. {
  1189. if (*format == '}')
  1190. {
  1191. logprintf("sscanf warning: Not in a quiet section.");
  1192. }
  1193. else if (*format != '{')
  1194. {
  1195. // Fix the bad display bug.
  1196. logprintf("sscanf warning: Format specifier does not match parameter count.");
  1197. }
  1198. // Only display it once.
  1199. break;
  1200. }
  1201. else
  1202. {
  1203. if (*format == '}')
  1204. {
  1205. doSave = true;
  1206. }
  1207. else
  1208. {
  1209. logprintf("sscanf warning: Format specifier does not match parameter count.");
  1210. break;
  1211. }
  1212. }
  1213. }
  1214. ++format;
  1215. }
  1216. while (*format);
  1217. }
  1218. if (!doSave)
  1219. {
  1220. // Started a quiet section but never explicitly ended it.
  1221. logprintf("sscanf warning: Unclosed quiet section.");
  1222. }
  1223. // No more parameters and no more format specifiers which could be read
  1224. // from - this is a valid return!
  1225. RestoreOpts(defaultOpts);
  1226. return SSCANF_TRUE_RETURN;
  1227. }
  1228. //#if SSCANF_QUIET
  1229. void
  1230. qlog(char * str, ...)
  1231. {
  1232. // Do nothing
  1233. }
  1234. //#endif
  1235. //----------------------------------------------------------
  1236. // The Support() function indicates what possibilities this
  1237. // plugin has. The SUPPORTS_VERSION flag is required to check
  1238. // for compatibility with the server.
  1239. PLUGIN_EXPORT unsigned int PLUGIN_CALL
  1240. Supports()
  1241. {
  1242. return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
  1243. }
  1244. //----------------------------------------------------------
  1245. // The Load() function gets passed on exported functions from
  1246. // the SA-MP Server, like the AMX Functions and logprintf().
  1247. // Should return true if loading the plugin has succeeded.
  1248. PLUGIN_EXPORT bool PLUGIN_CALL
  1249. Load(void ** ppData)
  1250. {
  1251. pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
  1252. logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
  1253. real_logprintf = logprintf;
  1254. //GetServer = (GetServer_t)ppData[0xE1];
  1255. //logprintf("0x%08X\n", (int)logprintf);
  1256. logprintf("\n");
  1257. logprintf(" ===============================\n");
  1258. logprintf(" sscanf plugin loaded. \n");
  1259. logprintf(" Version: 2.8.1 \n");
  1260. logprintf(" (c) 2012 Alex \"Y_Less\" Cole \n");
  1261. logprintf(" ===============================\n");
  1262. // Determine server version. Ideally we would use a feature check, such as
  1263. // checking wether ConnectNPC exists, doing away with the need for any
  1264. // memory addresses, unfortunately if the native isn't used in the current
  1265. // amx, then amx_FindNative won't find it, despite the fact that it does
  1266. // exist. I need to find a more reliable and more portable way of checking
  1267. // the current server version.
  1268. /*if (logprintf == LOGPRINTF_0221 || logprintf == LOGPRINTF_0222 || logprintf == LOGPRINTF_0223 || logprintf == LOGPRINTF_0224)
  1269. {
  1270. g_iServerVersion = SERVER_VERSION_0200;
  1271. g_iTrueMax = MAX_PLAYERS_0200;
  1272. g_iInvalid = INVALID_PLAYER_ID_0200;
  1273. }
  1274. else if (logprintf == LOGPRINTF_0300)
  1275. {
  1276. g_iServerVersion = SERVER_VERSION_0300;
  1277. g_iTrueMax = MAX_PLAYERS_0300;
  1278. g_iInvalid = INVALID_PLAYER_ID_0300;
  1279. }
  1280. else *//*if (logprintf == LOGPRINTF_0340)
  1281. {
  1282. g_iServerVersion = SERVER_VERSION_0340;
  1283. g_iTrueMax = MAX_PLAYERS_0300;
  1284. g_iInvalid = INVALID_PLAYER_ID_0300;
  1285. }
  1286. else if (logprintf == LOGPRINTF_0342)
  1287. {
  1288. g_iServerVersion = SERVER_VERSION_0342;
  1289. g_iTrueMax = MAX_PLAYERS_0300;
  1290. g_iInvalid = INVALID_PLAYER_ID_0300;
  1291. }
  1292. else
  1293. {
  1294. logprintf("sscanf error: The current build ONLY supports 0.3d");
  1295. }*/
  1296. #if SSCANF_QUIET
  1297. logprintf = qlog;
  1298. #endif
  1299. return true;
  1300. }
  1301. //----------------------------------------------------------
  1302. // The Unload() function is called when the server shuts down,
  1303. // meaning this plugin gets shut down with it.
  1304. PLUGIN_EXPORT void PLUGIN_CALL
  1305. Unload()
  1306. {
  1307. logprintf("\n");
  1308. logprintf(" ===============================\n");
  1309. logprintf(" sscanf plugin unloaded. \n");
  1310. logprintf(" ===============================\n");
  1311. }
  1312. static cell AMX_NATIVE_CALL
  1313. n_SSCANF_Init(AMX * amx, cell * params)
  1314. {
  1315. if (params[0] != 3 * sizeof (cell))
  1316. {
  1317. logprintf("sscanf error: SSCANF_Init has incorrect parameters.");
  1318. g_iTrueMax = 0;
  1319. return 0;
  1320. }
  1321. if (g_iTrueMax != 0)
  1322. {
  1323. // Already initialised.
  1324. return 1;
  1325. }
  1326. g_iTrueMax = (int)params[1];
  1327. g_iInvalid = (int)params[2];
  1328. g_iMaxPlayerName = (int)params[3];
  1329. g_szPlayerNames = new char [g_iTrueMax * g_iMaxPlayerName];
  1330. g_iConnected = new int [g_iTrueMax];
  1331. // FINALLY fixed this bug - I didn't know "new []" didn't initialise...
  1332. memset(g_iConnected, 0, sizeof (int) * g_iTrueMax);
  1333. g_iNPC = new int [g_iTrueMax];
  1334. return 1;
  1335. }
  1336. static void
  1337. DoName(AMX * amx, cell playerid, cell name)
  1338. {
  1339. cell *
  1340. str;
  1341. int
  1342. len;
  1343. amx_GetAddr(amx, name, &str);
  1344. amx_StrLen(str, &len);
  1345. if ((unsigned int)len >= g_iMaxPlayerName)
  1346. {
  1347. len = (int)g_iMaxPlayerName - 1;
  1348. }
  1349. amx_GetString(g_szPlayerNames + (g_iMaxPlayerName * playerid), str, 0, len + 1);
  1350. }
  1351. static cell AMX_NATIVE_CALL
  1352. n_SSCANF_IsConnected(AMX * amx, cell * params)
  1353. {
  1354. cell playerid;
  1355. playerid = params[1];
  1356. if (g_iConnected[playerid] != 0)
  1357. {
  1358. return 1;
  1359. }
  1360. return 0;
  1361. }
  1362. static cell AMX_NATIVE_CALL
  1363. n_SSCANF_Join(AMX * amx, cell * params)
  1364. {
  1365. if (params[0] != 3 * sizeof (cell))
  1366. {
  1367. logprintf("sscanf error: SSCANF_Join has incorrect parameters.");
  1368. return 0;
  1369. }
  1370. cell
  1371. playerid = params[1];
  1372. ++g_iConnected[playerid];
  1373. DoName(amx, playerid, params[2]);
  1374. g_iNPC[playerid] = params[3];
  1375. return 1;
  1376. }
  1377. static cell AMX_NATIVE_CALL
  1378. n_SSCANF_Leave(AMX * amx, cell * params)
  1379. {
  1380. if (params[0] != 1 * sizeof (cell))
  1381. {
  1382. logprintf("sscanf error: SSCANF_Leave has incorrect parameters.");
  1383. return 0;
  1384. }
  1385. // To be correct for multiple scripts with loads and unloads (unloadfs).
  1386. --g_iConnected[params[1]];
  1387. return 1;
  1388. }
  1389. static cell AMX_NATIVE_CALL
  1390. n_SSCANF_Option(AMX * amx, cell * params)
  1391. {
  1392. if (params[0] != 2 * sizeof (cell))
  1393. {
  1394. logprintf("sscanf error: SSCANF_Option has incorrect parameters.");
  1395. return 0;
  1396. }
  1397. char *
  1398. string;
  1399. STR_PARAM(amx, params[1], string);
  1400. DoOptions(string, params[2]);
  1401. return 1;
  1402. }
  1403. static cell AMX_NATIVE_CALL
  1404. n_SSCANF_SetPlayerName(AMX * amx, cell * params)
  1405. {
  1406. // Hook ALL AMXs, even if they don't use sscanf, by working at the plugin
  1407. // level. This allows us to intercept name changes.
  1408. //cell
  1409. // result;
  1410. //amx_Callback(amx, 0, &result, params);
  1411. if (params[0] != 2 * sizeof (cell))
  1412. {
  1413. logprintf("sscanf error: SSCANF_SetPlayerName has incorrect parameters.");
  1414. return 0;
  1415. }
  1416. DoName(amx, params[1], params[2]);
  1417. return SetPlayerName(amx, params);
  1418. }
  1419. //----------------------------------------------------------
  1420. // The AmxLoad() function gets called when a new gamemode or
  1421. // filterscript gets loaded with the server. In here we register
  1422. // the native functions we like to add to the scripts.
  1423. AMX_NATIVE_INFO
  1424. sscanfNatives[] =
  1425. {
  1426. {"sscanf", n_sscanf},
  1427. {"SSCANF_Init", n_SSCANF_Init},
  1428. {"SSCANF_Join", n_SSCANF_Join},
  1429. {"SSCANF_Leave", n_SSCANF_Leave},
  1430. {"SSCANF_IsConnected", n_SSCANF_IsConnected},
  1431. {"SSCANF_Option", n_SSCANF_Option},
  1432. {0, 0}
  1433. };
  1434. // From "amx.c", part of the PAWN language runtime:
  1435. // http://code.google.com/p/pawnscript/source/browse/trunk/amx/amx.c
  1436. #define USENAMETABLE(hdr) \
  1437. ((hdr)->defsize==sizeof(AMX_FUNCSTUBNT))
  1438. #define NUMENTRIES(hdr,field,nextfield) \
  1439. (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize)
  1440. #define GETENTRY(hdr,table,index) \
  1441. (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize)
  1442. #define GETENTRYNAME(hdr,entry) \
  1443. (USENAMETABLE(hdr) ? \
  1444. (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUBNT*)(entry))->nameofs) : \
  1445. ((AMX_FUNCSTUB*)(entry))->name)
  1446. PLUGIN_EXPORT int PLUGIN_CALL
  1447. AmxLoad(AMX * amx)
  1448. {
  1449. int
  1450. num,
  1451. idx;
  1452. // Operate on the raw AMX file, don't use the amx_ functions to avoid issues
  1453. // with the fact that we've not actually finished initialisation yet. Based
  1454. // VERY heavilly on code from "amx.c" in the PAWN runtime library.
  1455. AMX_HEADER *
  1456. hdr = (AMX_HEADER *)amx->base;
  1457. AMX_FUNCSTUB *
  1458. func;
  1459. num = NUMENTRIES(hdr, natives, libraries);
  1460. for (idx = 0; idx != num; ++idx)
  1461. {
  1462. func = GETENTRY(hdr, natives, idx);
  1463. if (!strcmp("SetPlayerName", GETENTRYNAME(hdr, func)))
  1464. {
  1465. // Intercept the call!
  1466. SetPlayerName = (AMX_NATIVE)func->address;
  1467. func->address = (ucell)n_SSCANF_SetPlayerName;
  1468. break;
  1469. }
  1470. }
  1471. return amx_Register(amx, sscanfNatives, -1);
  1472. }
  1473. //----------------------------------------------------------
  1474. // When a gamemode is over or a filterscript gets unloaded, this
  1475. // function gets called. No special actions needed in here.
  1476. PLUGIN_EXPORT int PLUGIN_CALL
  1477. AmxUnload(AMX * amx)
  1478. {
  1479. return AMX_ERR_NONE;
  1480. }