y_utils.inc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335
  1. /**--------------------------------------------------------------------------**\
  2. =================================
  3. Y Sever Includes - Misc Functions
  4. =================================
  5. Description:
  6. Misc functions used throughout.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the YSI utils include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2011
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. ZeeX - Very productive conversations.
  26. koolk - IsPlayerinAreaEx code.
  27. TheAlpha - Danish translation.
  28. breadfish - German translation.
  29. Fireburn - Dutch translation.
  30. yom - French translation.
  31. 50p - Polish translation.
  32. Zamaroht - Spanish translation.
  33. Los - Portuguese translation.
  34. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  35. for me to strive to better.
  36. Pixels^ - Running XScripters where the idea was born.
  37. Matite - Pestering me to release it and using it.
  38. Very special thanks to:
  39. Thiadmer - PAWN, whose limits continue to amaze me!
  40. Kye/Kalcor - SA:MP.
  41. SA:MP Team past, present and future - SA:MP.
  42. Optional plugins:
  43. Gamer_Z - GPS.
  44. Incognito - Streamer.
  45. Me - sscanf2, fixes2, Whirlpool.
  46. Version:
  47. 0.1.3
  48. Changelog:
  49. 06/10/12:
  50. Upgraded "memset" to use "FILL".
  51. 22/12/11:
  52. Changed "ceildiv" to only evaluate arguments once.
  53. 05/12/11:
  54. Added NO_VALUE to test if macros have no value.
  55. 08/09/10:
  56. Added strcpy and StripNL.
  57. 08/08/10:
  58. Scrapped almost everything. Only VERY usefult things go in now.
  59. Functions:
  60. Stock:
  61. StripNL - Strips the newline characters from the end of a string.
  62. Inline:
  63. iseven - Checks if a number is even.
  64. isodd - Checks if a number is odd.
  65. isnull - Checks if a string is NULL ("\1\0").
  66. strcpy - Copy one string to another.
  67. Variables:
  68. Global:
  69. TRUE - True hack for infinate loops.
  70. FALSE - False hack for one-time loops.
  71. NULL - 1 long string for passing via Call(Remote|Local)Function.
  72. </remarks>
  73. \**--------------------------------------------------------------------------**/
  74. #if defined _INC_y_utils
  75. #endinput
  76. #endif
  77. #define _INC_y_utils
  78. #include "..\YSI_Internal\y_version"
  79. #include "..\YSI_Core\y_debug"
  80. #include "..\YSI_Storage\y_amx"
  81. //#tryinclude <sscanf>
  82. #include "..\YSI_Internal\amx_assembly"
  83. // Add new tags to the START of this list.
  84. #include "..\YSI_Internal\y_globaltags"
  85. // VERY VERY VERY IMPORTANT!!! y_inline uses "130" instead of "YSI_MAX_STRING"
  86. // for two lines (one is "520" for "130 * 4").
  87. #define YSI_MAX_STRING (130)
  88. #define FUNCTION_LENGTH (32)
  89. // Better handling of operator precedences and floating point numbers. This
  90. // will now work for ALL regular numbers (including -0.5 which broke the old
  91. // version). I don't know of any complex expressions that break it with
  92. // operator precedences, but I'm not ruling it out. The brackets do try and
  93. // account for that possibility, but I just don't know.
  94. #define NO_VALUE(%0) ((2*%0-1)==2*(%0-1))
  95. #if !defined TRUE
  96. new stock
  97. bool:TRUE = true;
  98. #endif
  99. #if !defined FALSE
  100. new stock
  101. bool:FALSE = false;
  102. #endif
  103. #if !defined NULL
  104. new stock
  105. NULL[2] = "\1";
  106. #endif
  107. #if !defined cellbytes
  108. #define cellbytes (cellbits / 8)
  109. #endif
  110. #define UNSIGNED(%0) ((%0) - cellmin)
  111. // Define "volatile" as nothing.
  112. #if !defined volatile
  113. #define volatile
  114. #endif
  115. #define YSIM_MASTER #M
  116. #define YSIM_RETURN #R
  117. #define YSIM_CALLER #C
  118. #define YSIM_TEXT_D #T
  119. #define YSIM_TXTFND #X
  120. #define YSIM_TXTIND #I
  121. #define YSIM_TXTLEN #E
  122. #define YSIM_LOG_IN #U
  123. #define YSIM_VARARG #V
  124. #if !defined YSIM_STRING
  125. #define YSIM_STRING (42)
  126. #endif
  127. #define FLOAT_INFINITY (Float:0x7F800000)
  128. #define FLOAT_NEG_INFINITY (Float:0xFF800000)
  129. #define FLOAT_NEGATIVE_INFINITY (Float:0xFF800000)
  130. #define FLOAT_NAN (Float:0x7FFFFFFF)
  131. #define FLOAT_NOT_A_NUMBER (Float:0x7FFFFFFF)
  132. #define FLOAT_QNAN (Float:0x7FFFFFFF)
  133. #define FLOAT_QUIET_NAN (Float:0x7FFFFFFF)
  134. #define FLOAT_QUIET_NOT_A_NUMBER (Float:0x7FFFFFFF)
  135. #define FLOAT_SNAN (Float:0x7FBFFFFF)
  136. #define FLOAT_SIGNALING_NAN (Float:0x7FBFFFFF)
  137. #define FLOAT_SIGNALING_NOT_A_NUMBER (Float:0x7FBFFFFF)
  138. //#pragma unused TRUE, FALSE, NULL
  139. #define __TY|||%0||| (1000000)
  140. #define __TX:__TY|||%0,%1||| (%1)
  141. #define __TF=fopen(%0,%2"%3",%4) __TF=fopen(%0".csv",%4)
  142. #if !defined TIMING_ITERATIONS
  143. #define TIMING_ITERATIONS (10)
  144. #endif
  145. stock __TU(t, iters)
  146. {
  147. // Number of times run. Accounts for the string and optional count.
  148. new
  149. ret[20];
  150. if (iters > 1000000000)
  151. format(ret, sizeof (ret), "%.2fps", float(t) / (float(iters) / 1000000000.0));
  152. else if (iters == 1000000000)
  153. format(ret, sizeof (ret), "%d.00ps", t);
  154. else if (iters > 1000000)
  155. format(ret, sizeof (ret), "%.2fns", float(t) / (float(iters) / 1000000.0));
  156. else if (iters == 1000000)
  157. format(ret, sizeof (ret), "%d.00ns", t);
  158. else if (iters > 1000)
  159. format(ret, sizeof (ret), "%.2fus", float(t) / (float(iters) / 1000.0));
  160. else if (iters == 1000)
  161. format(ret, sizeof (ret), "%d.00us", t);
  162. else if (iters > 1)
  163. format(ret, sizeof (ret), "%.2fms", float(t) / float(iters));
  164. else
  165. format(ret, sizeof (ret), "%d.00ms", t);
  166. return ret;
  167. }
  168. #define RUN_TIMING(%0) \
  169. for(new __TA[TIMING_ITERATIONS],__TC=sizeof __TA,__TE=_:__TX:__TY|||%0|||,__TS=printf("Timing \"%s\"...",%0);__TC; \
  170. printf("\t Mean = %s\n\t Mode = %s\n\tMedian = %s\n\t Range = %s", \
  171. __TU(Mean(__TA),__TE),__TU(Mode(__TA),__TE),__TU(Median(__TA),__TE),__TU(Range(__TA),__TE))) \
  172. for(;(__TS=GetTickCount(),__TC);__TA[--__TC]=GetTickCount()-__TS) \
  173. for(new __TI;__TI!=__TE;++__TI)
  174. #define CSV_TIMING(%0) \
  175. for(new __TA[TIMING_ITERATIONS],__TC=sizeof __TA,__TE=_:__TX:__TY|||%0|||,__TS=printf("Timing \"%s\"...",%0),File:__TF=fopen(%0".csv",io_append);__TF&&__TC;\
  176. va_fprintf(__TF,"%d,%d,%s,%s,%s,%s\n",gettime(),__TE,__TU(Mean(__TA),__TE),__TU(Mode(__TA),__TE),__TU(Median(__TA),__TE),__TU(Range(__TA),__TE)),fclose(__TF))\
  177. for(;(__TS=GetTickCount(),__TC);__TA[--__TC]=GetTickCount()-__TS)\
  178. for(new __TI;__TI!=__TE;++__TI)
  179. stock
  180. YSI_gPlayerIP[MAX_PLAYERS + 1] = {-1, ...};
  181. public OnPlayerConnect(playerid)
  182. {
  183. new
  184. ip[16];
  185. GetPlayerIp(playerid, ip, sizeof (ip)),
  186. YSI_gPlayerIP[playerid] = IPToInt(ip);
  187. #if defined _y_utils_OnPlayerConnect
  188. _y_utils_OnPlayerConnect(playerid);
  189. #endif
  190. return 1;
  191. }
  192. #if defined _ALS_OnPlayerConnect
  193. #undef OnPlayerConnect
  194. #else
  195. #define _ALS_OnPlayerConnect
  196. #endif
  197. #define OnPlayerConnect _y_utils_OnPlayerConnect
  198. #if defined _y_utils_OnPlayerConnect
  199. forward _y_utils_OnPlayerConnect(playerid);
  200. #endif
  201. public OnPlayerDisconnect(playerid, reason)
  202. {
  203. YSI_gPlayerIP[playerid] = -1;
  204. #if defined _y_utils_OnPlayerDisconnect
  205. _y_utils_OnPlayerDisconnect(playerid, reason);
  206. #endif
  207. return 1;
  208. }
  209. #if defined _ALS_OnPlayerDisconnect
  210. #undef OnPlayerDisconnect
  211. #else
  212. #define _ALS_OnPlayerDisconnect
  213. #endif
  214. #define OnPlayerDisconnect _y_utils_OnPlayerDisconnect
  215. #if defined _y_utils_OnPlayerDisconnect
  216. forward _y_utils_OnPlayerDisconnect(playerid, reason);
  217. #endif
  218. /**--------------------------------------------------------------------------**\
  219. <summary>
  220. UCMP(value, upper);
  221. </summary>
  222. <param name="value">The unsigned number to compare.</param>
  223. <param name="upper">The upper limit.</param>
  224. <returns>
  225. An unsigned comparison between the two values.
  226. </returns>
  227. <remarks>
  228. -
  229. </remarks>
  230. \**--------------------------------------------------------------------------**/
  231. #define UCMP(%0,%1) IS_IN_RANGE(%0,0,(%1)) //(((%0) - cellmin) < ((%1) - cellmin))
  232. #define VALID_PLAYERID(%0) UCMP((%0), MAX_PLAYERS)
  233. /**--------------------------------------------------------------------------**\
  234. <summary>
  235. IS_IN_RANGE(value, lower, upper);
  236. </summary>
  237. <param name="value">The number to compare.</param>
  238. <param name="lower">The lower limit.</param>
  239. <param name="upper">The upper limit.</param>
  240. <returns>
  241. Is the value in the given range.
  242. </returns>
  243. <remarks>
  244. Equivalent to:
  245. (%1) <= (%0) < (%2)
  246. </remarks>
  247. \**--------------------------------------------------------------------------**/
  248. #define IS_IN_RANGE(%0,%1,%2) (((%0)-((%1)+cellmin))<((%2)-((%1)+cellmin)))
  249. #define NOT_IN_RANGE(%0,%1,%2) (((%0)-((%1)+cellmin))>=((%2)-((%1)+cellmin)))
  250. /**--------------------------------------------------------------------------**\
  251. <summary>
  252. ceildiv(numerator, denominator);
  253. </summary>
  254. <param name="numerator">The top of the division.</param>
  255. <param name="denominator">The bottom of the division.</param>
  256. <returns>
  257. (numerator / denominator) rounded up.
  258. </returns>
  259. <remarks>
  260. Normal integer division ALWAYS rounds down - this always rounds up.
  261. </remarks>
  262. \**--------------------------------------------------------------------------**/
  263. #define ceildiv(%0,%1) (((%0)-1)/(%1)+1)
  264. /**--------------------------------------------------------------------------**\
  265. <summary>
  266. floordiv(numerator, denominator);
  267. </summary>
  268. <param name="numerator">The top of the division.</param>
  269. <param name="denominator">The bottom of the division.</param>
  270. <returns>
  271. (numerator / denominator) rounded down.
  272. </returns>
  273. <remarks>
  274. Normal integer division ALWAYS rounds down - this also always rounds down,
  275. making it a little pointless, but also more explicit in function.
  276. </remarks>
  277. \**--------------------------------------------------------------------------**/
  278. #define floordiv(%0,%1) ((%0)/(%1))
  279. /**--------------------------------------------------------------------------**\
  280. <summary>isnull</summary>
  281. <param name="str">String to check if is null.</param>
  282. <returns>
  283. -
  284. </returns>
  285. <remarks>
  286. -
  287. </remarks>
  288. \**--------------------------------------------------------------------------**/
  289. #if !defined isnull
  290. #define isnull(%1) \
  291. ((%1[0] == 0) || (%1[0] == 1 && %1[1] == 0))
  292. #endif
  293. /**--------------------------------------------------------------------------**\
  294. <summary>isodd</summary>
  295. <param name="value">Value to check if is odd.</param>
  296. <returns>
  297. -
  298. </returns>
  299. <remarks>
  300. -
  301. </remarks>
  302. \**--------------------------------------------------------------------------**/
  303. #define isodd(%1) \
  304. ((%1) & 1)
  305. /**--------------------------------------------------------------------------**\
  306. <summary>iseven</summary>
  307. <param name="value">Value to check if is even.</param>
  308. <returns>
  309. -
  310. </returns>
  311. <remarks>
  312. -
  313. </remarks>
  314. \**--------------------------------------------------------------------------**/
  315. #define iseven(%1) \
  316. (!isodd(%1))
  317. /**--------------------------------------------------------------------------**\
  318. <summary>strcpy</summary>
  319. <param name="dest">Destination string.</param>
  320. <param name="src">Source string.</param>
  321. <param name="len">(Implicit) maximum length of the destination.</param>
  322. <returns>
  323. -
  324. </returns>
  325. <remarks>
  326. -
  327. </remarks>
  328. \**--------------------------------------------------------------------------**/
  329. #define strcpy(%0,%1) \
  330. strcat((%0[0] = '\0', %0), %1)
  331. /**--------------------------------------------------------------------------**\
  332. <summary>StrToLower</summary>
  333. <param name="str">String to convert.</param>
  334. <param name="len">How much of the string to convert.</param>
  335. <returns>
  336. -
  337. </returns>
  338. <remarks>
  339. -
  340. </remarks>
  341. \**--------------------------------------------------------------------------**/
  342. stock StrToLower(str[], len = sizeof (str))
  343. {
  344. new
  345. i = -1,
  346. ch;
  347. while ((ch = str[++i]) && len--)
  348. str[i] = tolower(ch);
  349. }
  350. /**--------------------------------------------------------------------------**\
  351. <summary>StrToUpper</summary>
  352. <param name="str">String to convert.</param>
  353. <param name="len">How much of the string to convert.</param>
  354. <returns>
  355. -
  356. </returns>
  357. <remarks>
  358. -
  359. </remarks>
  360. \**--------------------------------------------------------------------------**/
  361. stock StrToUpper(str[], len = sizeof (str))
  362. {
  363. new
  364. i = -1,
  365. ch;
  366. while ((ch = str[++i]) && len--)
  367. str[i] = toupper(ch);
  368. }
  369. /**--------------------------------------------------------------------------**\
  370. <summary>Random</summary>
  371. <param name="minmax">Lower bound, or upper bound when only parameter.</param>
  372. <param name="max">Upper bound.</param>
  373. <returns>
  374. -
  375. </returns>
  376. <remarks>
  377. Generate a random float between the given numbers (min <= n < max). Default
  378. minimum is 0.
  379. </remarks>
  380. \**--------------------------------------------------------------------------**/
  381. stock Random(min, max = cellmin)
  382. {
  383. if (max == cellmin)
  384. {
  385. if (min < 0)
  386. return -random(-min);
  387. return random(min);
  388. }
  389. if (max < min)
  390. return random(min - max) + max;
  391. return random(max - min) + min;
  392. }
  393. /**--------------------------------------------------------------------------**\
  394. <summary>RandomFloat</summary>
  395. <param name="minmax">Lower bound, or upper bound when only parameter.</param>
  396. <param name="max">Upper bound.</param>
  397. <param name="dp">How small to make the differences</param>
  398. <returns>
  399. -
  400. </returns>
  401. <remarks>
  402. Generate a random float between the given numbers (min <= n < max). Default
  403. minimum is 0.0.
  404. </remarks>
  405. \**--------------------------------------------------------------------------**/
  406. stock Float:RandomFloat(Float:min, Float:max = FLOAT_NAN, dp = 2)
  407. {
  408. new
  409. Float:mul = floatpower(10.0, float(dp));
  410. switch (dp)
  411. {
  412. case 0: mul = 1.0;
  413. case 1: mul = 10.0;
  414. case 2: mul = 100.0;
  415. case 3: mul = 1000.0;
  416. default: mul = floatpower(10.0, float(dp));
  417. }
  418. if (max != max)
  419. {
  420. if (min < 0.0)
  421. return -(float(random(floatround(-min * mul))) / mul);
  422. return float(random(floatround(min * mul))) / mul;
  423. }
  424. // Parameters are the wrong way around - do it anyway.
  425. if (max < min)
  426. return float(random(floatround(min * mul - max * mul))) / mul + max;
  427. // NOT a silly check - "IsNaN".
  428. return float(random(floatround(max * mul - min * mul))) / mul + min;
  429. }
  430. /**--------------------------------------------------------------------------**\
  431. <summary>StripNL</summary>
  432. <param name="str[]">The string to remove the newline characters from</param>
  433. <returns>
  434. -
  435. </returns>
  436. <remarks>
  437. Updated from old versions, should be more efficient
  438. </remarks>
  439. \**--------------------------------------------------------------------------**/
  440. stock StripNL(str[])
  441. {
  442. P:7("StripNL called: \"%s\"", str);
  443. new
  444. i = strlen(str);
  445. while (i-- && str[i] <= ' ') str[i] = '\0';
  446. }
  447. /**--------------------------------------------------------------------------**\
  448. <summary>StripL</summary>
  449. <param name="str[]">The string to remove whitespace from the start of</param>
  450. <returns>
  451. -
  452. </returns>
  453. <remarks>
  454. -
  455. </remarks>
  456. \**--------------------------------------------------------------------------**/
  457. stock StripL(str[])
  458. {
  459. P:7("StripL called: \"%s\"", str);
  460. new
  461. len = strlen(str),
  462. i = 0;
  463. while ('\0' < str[i] <= ' ') ++i;
  464. if (i) memcpy(str[0], str[i], 0, (len - i) * 4, len);
  465. }
  466. /**--------------------------------------------------------------------------**\
  467. <summary>Strip</summary>
  468. <param name="str[]">The string to remove whitespace from the start and end of</param>
  469. <returns>
  470. -
  471. </returns>
  472. <remarks>
  473. -
  474. </remarks>
  475. \**--------------------------------------------------------------------------**/
  476. stock Strip(str[])
  477. {
  478. P:7("Strip called: \"%s\"", str);
  479. new
  480. len = strlen(str),
  481. i = len;
  482. while (i-- && str[i] <= ' ') str[i] = '\0';
  483. i = 0;
  484. while ('\0' < str[i] <= ' ') ++i;
  485. if (i) memcpy(str[0], str[i], 0, (len - i) * 4, len);
  486. }
  487. /**--------------------------------------------------------------------------**\
  488. <summary>endofline</summary>
  489. <param name="line[]">String to check.</param>
  490. <param name="pos">Postion to start from.</param>
  491. <returns>
  492. -
  493. </returns>
  494. <remarks>
  495. Checks if the current point in a line is the end of non-whitespace data.
  496. </remarks>
  497. \**--------------------------------------------------------------------------**/
  498. stock endofline(line[], pos)
  499. {
  500. P:7("endofline called: \"%s\", %i", line, pos);
  501. if (NOT_IN_RANGE(pos, 0, strlen(line))) return 0;
  502. //if (pos < 0 || pos > strlen(line)) return 0;
  503. while (line[pos]) if (line[pos++] > ' ') return 0;
  504. return 1;
  505. }
  506. /**--------------------------------------------------------------------------**\
  507. <summary>chrfind</summary>
  508. <param name="needle">The character to find.</param>
  509. <param name="haystack[]">The string to find it in.</param>
  510. <param name="start">The offset to start from.</param>
  511. <returns>
  512. Fail - -1, Success - pos
  513. </returns>
  514. <remarks>
  515. -
  516. </remarks>
  517. \**--------------------------------------------------------------------------**/
  518. stock chrfind(needle, haystack[], start = 0)
  519. {
  520. P:7("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  521. if (start < 0)
  522. {
  523. start = 0;
  524. }
  525. else if (start > strlen(haystack)) return -1;
  526. while (haystack[start]) if (haystack[start++] == needle) return start - 1;
  527. return -1;
  528. }
  529. stock chrfindp(needle, haystack[], start = 0)
  530. {
  531. P:7("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  532. if (start < 0)
  533. {
  534. start = 0;
  535. }
  536. while (haystack{start}) if (haystack{start++} == needle) return start - 1;
  537. return -1;
  538. }
  539. /**--------------------------------------------------------------------------**\
  540. <summary>IPToInt</summary>
  541. <param name="ip[]">Dot notation IP to convert to an integer.</param>
  542. <returns>
  543. -
  544. </returns>
  545. <remarks>
  546. -
  547. </remarks>
  548. \**--------------------------------------------------------------------------**/
  549. stock IPToInt(ip[])
  550. {
  551. new
  552. ipv = strval(ip) << 24,
  553. pos = 0;
  554. while (pos < 15 && ip[pos++] != '.') {}
  555. ipv += strval(ip[pos]) << 16;
  556. while (pos < 15 && ip[pos++] != '.') {}
  557. ipv += strval(ip[pos]) << 8;
  558. while (pos < 15 && ip[pos++] != '.') {}
  559. return ipv + strval(ip[pos]);
  560. }
  561. /**--------------------------------------------------------------------------**\
  562. <summary>bernstein</summary>
  563. <param name="string[]">the string to hash.</param>
  564. <returns>
  565. the bernstein hash of the input string
  566. </returns>
  567. <remarks>
  568. This is a 32bit hash system so is not very secure, however we're only
  569. using this as a string enumerator to uniquely identify strings easilly
  570. and allow for a binary search of strings based on the hash of their name.
  571. crc32, then jenkins were originally used however this is far faster, if a
  572. little collision prone, but we're checking the strings manually anyway.
  573. This doesn't matter as it would be done regardless of hash method, so this
  574. doesn't need to be accounted for. Speed is all that matters with at
  575. least a bit of non collision (the number of strings we're dealing with,
  576. this should have none-few collisions).
  577. I modified it slightly from the original code pasted by aru, to code
  578. closer to the code http://www.burtleburtle.net/bob/hash/doobs.html and
  579. to work with PAWN (and shaved 0.2�s off the time for one call :D).
  580. Uber reduced version (just for fun):
  581. b(s[]){new h=-1,i,j;while((j=s[i++]))h=h*33+j;return h;}
  582. Update: Contrary to what I said above this is also used to identify colour
  583. strings for the updated text system involving file based styling and this
  584. is not checked for collisions as it's unimportant. But this doesn't affect
  585. the function at all, I just mentioned it here for "interest".
  586. Rewritten in self-generating assembly.
  587. </remarks>
  588. \**--------------------------------------------------------------------------**/
  589. stock bernstein(string[] /* 12 */)
  590. {
  591. // Only shown the very first time this function is run.
  592. P:7("bernstein called: \"%s\"", string);
  593. #pragma unused string
  594. new
  595. base,
  596. ctx[AsmContext];
  597. // Get this function.
  598. #emit CONST.pri bernstein
  599. #emit LOAD.alt AMX_HEADER_COD
  600. #emit ADD
  601. #emit STOR.S.pri base
  602. AsmInitPtr(ctx, base, 128), // Don't need any more than that.
  603. // Setup.
  604. @emit PROC
  605. @emit CONST.alt -1
  606. @emit PUSH.S 12 // string
  607. @emit LREF.S.pri 12 // string
  608. @emit JZER.rel 12 * 4 // bernstein_end
  609. // bernstein_loop:
  610. @emit XCHG
  611. @emit SMUL.C 33
  612. @emit ADD
  613. @emit MOVE.alt
  614. // Update the next pointer.
  615. @emit POP.pri
  616. @emit ADD.C 4
  617. @emit PUSH.pri
  618. // Load the data for the current pointer.
  619. @emit LOAD.I
  620. @emit JNZ.rel -(12 * 4) // bernstein_loop
  621. // bernstein_end:
  622. @emit MOVE.pri
  623. @emit STACK 4
  624. @emit RETN
  625. // Now actually CALL the written function.
  626. #emit LCTRL 5
  627. #emit SCTRL 4
  628. #emit CONST.pri bernstein
  629. #emit ADD.C 4
  630. #emit SCTRL 6
  631. return 0; // Make the compiler happy.
  632. }
  633. /**--------------------------------------------------------------------------**\
  634. <summary>ishex</summary>
  635. <param name="str[]">String to check.</param>
  636. <returns>
  637. true/false.
  638. </returns>
  639. <remarks>
  640. -
  641. </remarks>
  642. \**--------------------------------------------------------------------------**/
  643. stock ishex(str[])
  644. {
  645. P:7("ishex called: \"%s\"", str);
  646. new
  647. i,
  648. cur;
  649. if (str[0] == '0' && (str[1] | 0x20) == 'x') i = 2;
  650. do
  651. {
  652. cur = str[i++];
  653. }
  654. while (IS_IN_RANGE(cur, '0', '9' + 1) || IS_IN_RANGE(cur | 0x20, 'a', 'f' + 1));
  655. //while (('0' <= cur <= '9') || ('a' <= (cur | 0x20) <= 'f'));
  656. return !cur; // Valid if this is the end of the string.
  657. }
  658. /**--------------------------------------------------------------------------**\
  659. <summary>unpack</summary>
  660. <param name="str[]">String to unpack</param>
  661. <returns>
  662. unpacked string
  663. </returns>
  664. <remarks>
  665. Mainly used for debugging.
  666. </remarks>
  667. \**--------------------------------------------------------------------------**/
  668. stock unpack(const str[])
  669. {
  670. P:7("unpack called: \"%s\"", str);
  671. new
  672. ret[YSI_MAX_STRING] = {0};
  673. if (strlen(str) <= YSI_MAX_STRING)
  674. {
  675. strunpack(ret, str);
  676. }
  677. return ret;
  678. }
  679. /**--------------------------------------------------------------------------**\
  680. <summary>GetIP</summary>
  681. <param name="playerid">Player to get IP of.</param>
  682. <returns>
  683. IP as a 32bit int.
  684. </returns>
  685. <remarks>
  686. -
  687. </remarks>
  688. \**--------------------------------------------------------------------------**/
  689. // Cunning macro only uses "%0" once, yet is still safe.
  690. #define GetIP(%0) (YSI_gPlayerIP[min((%0) + cellmin, MAX_PLAYERS + cellmin) - cellmin])
  691. /**--------------------------------------------------------------------------**\
  692. <summary>getstring</summary>
  693. <param name="addr">Address of the string on the heap.</param>
  694. <returns>
  695. string
  696. </returns>
  697. <remarks>
  698. Is passed the result of getarg, which will be the address of a string (in
  699. theory) and uses that for DMA to get the string.
  700. </remarks>
  701. \**--------------------------------------------------------------------------**/
  702. stock getstring(addr)
  703. {
  704. new
  705. ret[YSI_MAX_STRING];
  706. va_getstring(ret, addr);
  707. return ret;
  708. }
  709. stock getstringarg(addr)
  710. {
  711. new
  712. ret[YSI_MAX_STRING];
  713. va_getstring(ret, addr);
  714. return ret;
  715. }
  716. /**--------------------------------------------------------------------------**\
  717. <summary>isnumeric</summary>
  718. <param name="str[]">String to check</param>
  719. <returns>
  720. -
  721. </returns>
  722. <remarks>
  723. Checks if a given string is numeric.
  724. </remarks>
  725. \**--------------------------------------------------------------------------**/
  726. stock isnumeric(str[])
  727. {
  728. P:7("isnumeric called: \"%s\"", str);
  729. new
  730. i;
  731. while (IS_IN_RANGE(str[i], '0', '9' + 1)) ++i;
  732. //while ((ch = str[i++])) if (!('0' <= ch <= '9')) return 0;
  733. return !str[i];
  734. }
  735. #if !defined _inc_sscanf || 1
  736. /**----------------------------------------------------------------------**\
  737. <summary>hexstr</summary>
  738. <param name=" string[]">String to convert to a number.</param>
  739. <returns>
  740. value of the passed hex string.
  741. </returns>
  742. <remarks>
  743. Now stops on invalid characters.
  744. </remarks>
  745. \**----------------------------------------------------------------------**/
  746. stock hexstr(string[])
  747. {
  748. new
  749. ret,
  750. val,
  751. i;
  752. if (string[0] == '0' && string[1] | 0x20 == 'x') i = 2;
  753. for ( ; ; )
  754. {
  755. switch ((val = string[i++]))
  756. {
  757. case '0' .. '9':
  758. {
  759. val -= '0';
  760. }
  761. case 'a' .. 'f':
  762. {
  763. val -= 'a' - 10;
  764. }
  765. case 'A' .. 'F':
  766. {
  767. val -= 'A' - 10;
  768. }
  769. default: break;
  770. }
  771. ret = ret << 4 | val;
  772. }
  773. return ret;
  774. }
  775. /**----------------------------------------------------------------------**\
  776. <summary>boolstr</summary>
  777. <param name=" string[]">String to try convert to a boolean.</param>
  778. <returns>
  779. bool: passed boolean.
  780. </returns>
  781. <remarks>
  782. This can take a number of ways of representing booleans - 0, false and
  783. nothing there. Anything not one of those things (false is not case
  784. sensitive) is assumed true.
  785. </remarks>
  786. \**----------------------------------------------------------------------**/
  787. stock bool:boolstr(string[])
  788. {
  789. // Hooray for De Morgan's rules!
  790. return string[0] && string[0] != '0' && strcmp(string, "false", true);
  791. }
  792. /**----------------------------------------------------------------------**\
  793. <summary>binstr</summary>
  794. <param name=" string[]">String to try convert to a boolean.</param>
  795. <returns>
  796. bool: passed boolean.
  797. </returns>
  798. <remarks>
  799. This takes a value in 0110101 (boolean) format and returns it as a
  800. regular value.
  801. </remarks>
  802. \**----------------------------------------------------------------------**/
  803. stock binstr(string[])
  804. {
  805. new
  806. pos = 0;
  807. switch (string[0])
  808. {
  809. case '0':
  810. {
  811. if (string[1] | 0x20 == 'b')
  812. {
  813. pos = 2;
  814. }
  815. }
  816. case '1':
  817. {
  818. }
  819. default:
  820. {
  821. return 0;
  822. }
  823. }
  824. new
  825. value = 0;
  826. for ( ; ; )
  827. {
  828. switch (string[pos++])
  829. {
  830. case '0':
  831. {
  832. value <<= 1;
  833. }
  834. case '1':
  835. {
  836. value = (value << 1) | 1;
  837. }
  838. default:
  839. {
  840. break;
  841. }
  842. }
  843. }
  844. return value;
  845. }
  846. #endif
  847. /**--------------------------------------------------------------------------**\
  848. <summary>
  849. rawMemcpy
  850. </summary>
  851. <param name="dest">Destination address.</param>
  852. <param name="src">Source data.</param>
  853. <param name="bytes">Number of bytes to copy.</param>
  854. <returns>
  855. -
  856. </returns>
  857. <remarks>
  858. Like memcpy, but takes addresses instead of arrays. Also far less secure.
  859. </remarks>
  860. \**--------------------------------------------------------------------------**/
  861. forward __rawMemcpy__(dest[], src[], bytes);
  862. public __rawMemcpy__(dest[], src[], bytes)
  863. {
  864. memcpy(dest, src, 0, bytes, bytes);
  865. memset("", 0, 0);
  866. strcmp("", "");
  867. }
  868. stock rawMemcpy(dest, src, bytes)
  869. {
  870. // Don't use "MOVS" as these blocks might overlap.
  871. #emit PUSH.S bytes
  872. #emit PUSH.S bytes
  873. #emit PUSH.C 0
  874. #emit PUSH.S src
  875. #emit PUSH.S dest
  876. #emit PUSH.C 20
  877. #emit SYSREQ.C memcpy
  878. #emit STACK 24
  879. #emit RETN
  880. return 0;
  881. }
  882. /**--------------------------------------------------------------------------**\
  883. <summary>
  884. memset
  885. rawMemset
  886. </summary>
  887. <param name="arr[], iAddress">Array or address to set to a value.</param>
  888. <param name="iValue">What to set the cells to.</param>
  889. <param name="iSize">Number of cells to fill.</param>
  890. <returns>
  891. -
  892. </returns>
  893. <remarks>
  894. Based on code by Slice:
  895. http://forum.sa-mp.com/showthread.php?p=1606781#post1606781
  896. Modified to use binary flags instead of a loop.
  897. "memset" takes an array, the size of the array, and a value to fill it with
  898. and sets the whole array to that value.
  899. "rawmemset" is similar, but takes an AMX data segment address instead and
  900. the size is in bytes, not cells. However, the size must still be a multiple
  901. of 4.
  902. </remarks>
  903. \**--------------------------------------------------------------------------**/
  904. stock memset(arr[], val = 0, size = sizeof (arr))
  905. {
  906. new
  907. addr;
  908. #emit LOAD.S.pri arr
  909. #emit STOR.S.pri addr
  910. // Convert the size from cells to bytes.
  911. return rawMemset(addr, val, size * 4);
  912. }
  913. stock rawMemset(iAddress /* 12 */, iValue /* 16 */, iSize /* 20 */)
  914. {
  915. // They are really, trust me!
  916. #pragma unused iAddress, iSize, iValue
  917. // The first time this is called it rewrites itself. Any other times it is
  918. // called it just uses the new code. This is like doing:
  919. //
  920. // static
  921. // bInitialised = false;
  922. // if (!bInitialised)
  923. // {
  924. // // Do something
  925. // bInitialised = true;
  926. // }
  927. // // Do rest.
  928. //
  929. // But better (though FAR more complex).
  930. // There is NO checking here that we don't write the function bigger than
  931. // the space available, or even that we don't overwrite "CIP", which would
  932. // be bad. The only way to make sure that doesn't happen is write a little
  933. // with a lot of code!
  934. new
  935. base,
  936. ctx[AsmContext];
  937. // Get this function.
  938. #emit CONST.pri rawMemset
  939. #emit LOAD.alt AMX_HEADER_COD
  940. #emit ADD
  941. #emit STOR.S.pri base
  942. AsmInitPtr(ctx, base, 80), // Don't need any more than that.
  943. // Frankly by this point we have probably already written more code than
  944. // will be generated!
  945. @emit PROC
  946. @emit LOAD.S.pri 20
  947. @emit CONST.alt 0xFFFFFFC
  948. @emit AND
  949. @emit STOR.pri (ctx[AsmContext_buffer] + 13 * 4)
  950. // The documentation says "PRI" should be a pointer, but that's not true!
  951. @emit LOAD.S.alt 12
  952. @emit LOAD.S.pri 16
  953. @emit FILL 0
  954. // Return the bytes filled.
  955. @emit LOAD.pri (ctx[AsmContext_buffer] + 13 * 4)
  956. @emit RETN
  957. // Do the second version.
  958. #emit CONST.pri memset
  959. #emit LOAD.alt AMX_HEADER_COD
  960. #emit ADD
  961. #emit STOR.S.pri base
  962. AsmInitPtr(ctx, base, 80),
  963. @emit PROC
  964. @emit LOAD.S.pri 20
  965. @emit SHL.C.pri 2
  966. @emit STOR.pri (ctx[AsmContext_buffer] + 12 * 4)
  967. @emit LOAD.S.alt 12
  968. @emit LOAD.S.pri 16
  969. @emit FILL 0
  970. // Return the bytes filled.
  971. @emit LOAD.pri (ctx[AsmContext_buffer] + 12 * 4)
  972. @emit RETN
  973. // Call this function again (the new version), but don't let the compiler
  974. // know... First clear the stack.
  975. #emit LCTRL 5
  976. #emit SCTRL 4
  977. #emit CONST.pri rawMemset
  978. #emit ADD.C 4
  979. #emit SCTRL 6
  980. // Never hit because of going to an earlier "RETN".
  981. return 0; //memset("", 0, 0);
  982. }
  983. /**--------------------------------------------------------------------------**\
  984. <summary>
  985. ReturnPlayerName
  986. </summary>
  987. <param name="playerid">Player whose name you want to get.</param>
  988. <returns>
  989. -
  990. </returns>
  991. <remarks>
  992. Now uses a global array to avoid repeated function calls. Actually doesn't
  993. because that causes issues with multiple scripts.
  994. </remarks>
  995. \**--------------------------------------------------------------------------**/
  996. stock ReturnPlayerName(playerid)
  997. {
  998. new
  999. str[MAX_PLAYER_NAME];
  1000. GetPlayerName(playerid, str, sizeof (str));
  1001. return str;
  1002. }
  1003. /**--------------------------------------------------------------------------**\
  1004. <summary>
  1005. ftouch(filename);
  1006. </summary>
  1007. <param name="filename">The file to "touch".</param>
  1008. <returns>
  1009. 0 - File already exists.
  1010. 1 - File was created.
  1011. -1 - File was not created.
  1012. </returns>
  1013. <remarks>
  1014. This "touches" a file in the Unix sense of creating it but not opening or
  1015. editing it in any way.
  1016. </remarks>
  1017. \**--------------------------------------------------------------------------**/
  1018. stock ftouch(const filename[])
  1019. {
  1020. if (fexist(filename))
  1021. {
  1022. return 0;
  1023. }
  1024. else
  1025. {
  1026. new
  1027. File:f = fopen(filename, io_write);
  1028. if (f)
  1029. {
  1030. fclose(f);
  1031. return 1;
  1032. }
  1033. else
  1034. {
  1035. return -1;
  1036. }
  1037. }
  1038. }
  1039. /**--------------------------------------------------------------------------**\
  1040. <summary>
  1041. InterpolateColour(startcolor, endcolor, value, maxvalue, minvalue = 0);
  1042. </summary>
  1043. <param name="startcolor">One of the two colours.</param>
  1044. <param name="endcolor">The other of the two colours.</param>
  1045. <param name="value">The interpolation value between the endpoints.</param>
  1046. <param name="maxvalue">One of the two numbers.</param>
  1047. <param name="minvalue">The other of the two numbers.</param>
  1048. <returns>
  1049. -
  1050. </returns>
  1051. <remarks>
  1052. This function takes two endpoint values (minvalue and maxvalue, with
  1053. minvalue defaulting to 0), along with a third value (value) whose distance
  1054. between the two endpoints is calculated (as a percentage). This percentage
  1055. value is then applied to the two colours given to find a third colour at
  1056. some point between those two colours.
  1057. For example, if the endpoints given are "0" and "10", and the value given is
  1058. "3", then that is "30%" of the way between the two endpoints. We therefore
  1059. want to find a colour that is 30% of the way between the two given colours.
  1060. </remarks>
  1061. \**--------------------------------------------------------------------------**/
  1062. // "Interpolation" is the technical name for what you are doing here.
  1063. #define InterpolateColor InterpolateColour
  1064. stock InterpolateColour(startcolor, endcolor, value, maxvalue, minvalue = 0)
  1065. {
  1066. if (value >= maxvalue) return endcolor;
  1067. if (value <= minvalue) return startcolor;
  1068. static r, g, b, a;
  1069. new
  1070. time = maxvalue - minvalue,
  1071. stage = value - minvalue;
  1072. return
  1073. // Step 1: Get the starting colour components.
  1074. r = startcolor >>> 24 ,
  1075. g = startcolor >>> 16 & 0xFF,
  1076. b = startcolor >>> 8 & 0xFF,
  1077. a = startcolor & 0xFF,
  1078. // Step 2: Interpolate between the end points, and add to the start.
  1079. r += ((endcolor >>> 24 ) - r) * stage / time,
  1080. g += ((endcolor >>> 16 & 0xFF) - g) * stage / time,
  1081. b += ((endcolor >>> 8 & 0xFF) - b) * stage / time,
  1082. a += ((endcolor & 0xFF) - a) * stage / time,
  1083. // Step 3: Combine the individual components.
  1084. (r << 24) | ((g & 0xFF) << 16) | ((b & 0xFF) << 8) | (a & 0xFF);
  1085. }
  1086. /**--------------------------------------------------------------------------**\
  1087. <summary>SkipWhitespace</summary>
  1088. <param name="str[]">The string to skip over part of.</param>
  1089. <param name="pos">The start of the whitespace.</param>
  1090. <returns>
  1091. The end of the whitespace.
  1092. </returns>
  1093. <remarks>
  1094. Doesn't skip over NULL terminators.
  1095. </remarks>
  1096. \**--------------------------------------------------------------------------**/
  1097. stock SkipWhitespace(const str[], pos)
  1098. {
  1099. while (IS_IN_RANGE(str[pos], '\0' + 1, ' ' + 1)) ++pos;
  1100. //while ('\0' < str[pos] <= ' ') ++pos;
  1101. return pos;
  1102. }
  1103. /**--------------------------------------------------------------------------**\
  1104. <summary>Trim</summary>
  1105. <param name="str[]">The string to trim.</param>
  1106. <param name="start">Start of the substring.</param>
  1107. <param name="end">End of the substring.</param>
  1108. <returns>
  1109. -
  1110. </returns>
  1111. <remarks>
  1112. Modifies "start" and "end" to be tight on text in "str".
  1113. </remarks>
  1114. \**--------------------------------------------------------------------------**/
  1115. stock Trim(const str[], &start, &end)
  1116. {
  1117. while (IS_IN_RANGE(str[start], '\0' + 1, ' ' + 1)) ++start;
  1118. //while ('\0' < str[start] <= ' ') ++start;
  1119. if (str[start])
  1120. {
  1121. while (end-- > start && str[end] <= ' ') {}
  1122. ++end;
  1123. }
  1124. else
  1125. {
  1126. end = start;
  1127. }
  1128. }
  1129. /**--------------------------------------------------------------------------**\
  1130. <summary>ftell</summary>
  1131. <param name="File:f">The file to get our position in.</param>
  1132. <returns>
  1133. The current position in the file.
  1134. </returns>
  1135. <remarks>
  1136. Doesn't seem to work despite documentation claiming it will.
  1137. </remarks>
  1138. \**--------------------------------------------------------------------------**/
  1139. //#define ftell(%0) fseek((%0), 0, seek_current)
  1140. static stock Utils_PreSort(arr[], num = sizeof (arr))
  1141. {
  1142. // Very simple bubble sort (fast for pre-sorted arrays).
  1143. new
  1144. bool:sort;
  1145. do
  1146. {
  1147. sort = false;
  1148. for (new j = 1, temp; j != num; ++j)
  1149. {
  1150. if ((temp = arr[j]) < arr[j - 1])
  1151. {
  1152. arr[j] = arr[j - 1],
  1153. arr[j - 1] = temp,
  1154. sort = true;
  1155. }
  1156. }
  1157. }
  1158. while (sort);
  1159. }
  1160. stock Sum(const arr[], num = sizeof (arr))
  1161. {
  1162. new
  1163. tot;
  1164. while (num) tot += arr[--num];
  1165. return tot;
  1166. }
  1167. stock Mean(const arr[], num = sizeof (arr))
  1168. {
  1169. return Sum(arr, num) / num;
  1170. }
  1171. stock Mode(arr[], num = sizeof (arr))
  1172. {
  1173. Utils_PreSort(arr, num);
  1174. new
  1175. ret,
  1176. count = 0,
  1177. cn,
  1178. cc;
  1179. for (new i = 0; i != num; ++i)
  1180. {
  1181. if (arr[i] == cn) ++cc;
  1182. else
  1183. {
  1184. if (cc > count) count = cc, ret = cn;
  1185. cc = 1, cn = arr[i];
  1186. }
  1187. }
  1188. if (cc > count) return cn;
  1189. else return ret;
  1190. }
  1191. stock Median(arr[], num = sizeof (arr))
  1192. {
  1193. Utils_PreSort(arr, num);
  1194. new
  1195. idx = num >>> 1;
  1196. if (num & 1) return arr[idx];
  1197. else return (arr[idx] + arr[idx - 1]) >> 1;
  1198. }
  1199. stock Range(arr[], num = sizeof (arr))
  1200. {
  1201. Utils_PreSort(arr, num);
  1202. return arr[num - 1] - arr[0];
  1203. }
  1204. #include "..\YSI_Coding\y_va"
  1205. #include "..\YSI_Internal\y_shortfunc"