impl.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /**--------------------------------------------------------------------------**\
  2. ==============================
  3. y_va - Enhanced vararg code!
  4. ==============================
  5. Description:
  6. This library currently provides two functions - va_printf and va_format
  7. which perform printf and format using variable arguments passed to another
  8. function.
  9. This is bsed on the variable parameter passing method based on code by Zeex.
  10. See page 15 of the code optimisations topic.
  11. Legal:
  12. Version: MPL 1.1
  13. The contents of this file are subject to the Mozilla Public License Version
  14. 1.1 (the "License"); you may not use this file except in compliance with
  15. the License. You may obtain a copy of the License at
  16. http://www.mozilla.org/MPL/
  17. Software distributed under the License is distributed on an "AS IS" basis,
  18. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  19. for the specific language governing rights and limitations under the
  20. License.
  21. The Original Code is the YSI vararg include.
  22. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  23. Portions created by the Initial Developer are Copyright (C) 2011
  24. the Initial Developer. All Rights Reserved.
  25. Contributors:
  26. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  27. Thanks:
  28. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  29. ZeeX - Very productive conversations.
  30. koolk - IsPlayerinAreaEx code.
  31. TheAlpha - Danish translation.
  32. breadfish - German translation.
  33. Fireburn - Dutch translation.
  34. yom - French translation.
  35. 50p - Polish translation.
  36. Zamaroht - Spanish translation.
  37. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  38. for me to strive to better.
  39. Pixels^ - Running XScripters where the idea was born.
  40. Matite - Pestering me to release it and using it.
  41. Very special thanks to:
  42. Thiadmer - PAWN, whose limits continue to amaze me!
  43. Kye/Kalcor - SA:MP.
  44. SA:MP Team past, present and future - SA:MP.
  45. Version:
  46. 1.0
  47. Changelog:
  48. 02/05/11:
  49. First version.
  50. Functions:
  51. Public:
  52. -
  53. Core:
  54. -
  55. Stock:
  56. -
  57. Static:
  58. -
  59. Inline:
  60. -
  61. API:
  62. -
  63. Callbacks:
  64. -
  65. Definitions:
  66. -
  67. Enums:
  68. -
  69. Macros:
  70. -
  71. Tags:
  72. -
  73. Variables:
  74. Global:
  75. -
  76. Static:
  77. -
  78. Commands:
  79. -
  80. Compile options:
  81. -
  82. Operators:
  83. -
  84. </remarks>
  85. \**--------------------------------------------------------------------------**/
  86. #include "internal\y_version"
  87. #include "internal\y_funcinc"
  88. #include "y_utils"
  89. stock va_printf(const fmat[], va_:STATIC_ARGS)
  90. {
  91. new
  92. num_args,
  93. arg_start,
  94. arg_end;
  95. // Get the pointer to the number of arguments to the last function.
  96. #emit LOAD.S.pri 0
  97. #emit ADD.C 8
  98. #emit MOVE.alt
  99. // Get the number of arguments.
  100. #emit LOAD.I
  101. #emit STOR.S.pri num_args
  102. // Get the variable arguments (end).
  103. #emit ADD
  104. #emit STOR.S.pri arg_end
  105. // Get the variable arguments (start).
  106. #emit LOAD.S.pri STATIC_ARGS
  107. #emit SMUL.C 4
  108. #emit ADD
  109. #emit STOR.S.pri arg_start
  110. // Using an assembly loop here screwed the code up as the labels added some
  111. // odd stack/frame manipulation code...
  112. while (arg_end != arg_start)
  113. {
  114. #emit MOVE.pri
  115. #emit LOAD.I
  116. #emit PUSH.pri
  117. #emit CONST.pri 4
  118. #emit SUB.alt
  119. #emit STOR.S.pri arg_end
  120. }
  121. // Push the additional parameters.
  122. #emit PUSH.S fmat
  123. // Push the argument count.
  124. #emit LOAD.S.pri num_args
  125. #emit ADD.C 4
  126. #emit LOAD.S.alt STATIC_ARGS
  127. #emit XCHG
  128. #emit SMUL.C 4
  129. #emit SUB.alt
  130. #emit PUSH.pri
  131. #emit MOVE.alt
  132. // This gets confused if you have a local variable of the same name as it
  133. // seems to factor in them first, so you get the offset of the local
  134. // variable instead of the index of the native.
  135. #emit SYSREQ.C printf
  136. // Clear the stack.
  137. #emit CONST.pri 4
  138. #emit ADD
  139. #emit MOVE.alt
  140. // The three lines above get the total stack data size, now remove it.
  141. #emit LCTRL 4
  142. #emit ADD
  143. #emit SCTRL 4
  144. // Now do the real return.
  145. }
  146. stock va_CallRemoteFunction(const function[], const fmat[], va_:STATIC_ARGS)
  147. {
  148. new
  149. num_args,
  150. arg_start,
  151. arg_end;
  152. // Get the pointer to the number of arguments to the last function.
  153. #emit LOAD.S.pri 0
  154. #emit ADD.C 8
  155. #emit MOVE.alt
  156. // Get the number of arguments.
  157. #emit LOAD.I
  158. #emit STOR.S.pri num_args
  159. // Get the variable arguments (end).
  160. #emit ADD
  161. #emit STOR.S.pri arg_end
  162. // Get the variable arguments (start).
  163. #emit LOAD.S.pri STATIC_ARGS
  164. #emit SMUL.C 4
  165. #emit ADD
  166. #emit STOR.S.pri arg_start
  167. // Using an assembly loop here screwed the code up as the labels added some
  168. // odd stack/frame manipulation code...
  169. while (arg_end != arg_start)
  170. {
  171. #emit MOVE.pri
  172. #emit LOAD.I
  173. #emit PUSH.pri
  174. #emit CONST.pri 4
  175. #emit SUB.alt
  176. #emit STOR.S.pri arg_end
  177. }
  178. // Push the additional parameters.
  179. #emit PUSH.S fmat
  180. #emit PUSH.S function
  181. // Push the argument count.
  182. #emit LOAD.S.pri num_args
  183. #emit ADD.C 8
  184. #emit LOAD.S.alt STATIC_ARGS
  185. #emit XCHG
  186. #emit SMUL.C 4
  187. #emit SUB.alt
  188. #emit PUSH.pri
  189. #emit MOVE.alt
  190. // This gets confused if you have a local variable of the same name as it
  191. // seems to factor in them first, so you get the offset of the local
  192. // variable instead of the index of the native.
  193. #emit SYSREQ.C CallRemoteFunction
  194. // Clear the stack.
  195. #emit CONST.pri 4
  196. #emit ADD
  197. #emit MOVE.alt
  198. // The three lines above get the total stack data size, now remove it.
  199. #emit LCTRL 4
  200. #emit ADD
  201. #emit SCTRL 4
  202. // Now do the real return.
  203. }
  204. stock va_CallLocalFunction(const function[], const fmat[], va_:STATIC_ARGS)
  205. {
  206. new
  207. num_args,
  208. arg_start,
  209. arg_end;
  210. // Get the pointer to the number of arguments to the last function.
  211. #emit LOAD.S.pri 0
  212. #emit ADD.C 8
  213. #emit MOVE.alt
  214. // Get the number of arguments.
  215. #emit LOAD.I
  216. #emit STOR.S.pri num_args
  217. // Get the variable arguments (end).
  218. #emit ADD
  219. #emit STOR.S.pri arg_end
  220. // Get the variable arguments (start).
  221. #emit LOAD.S.pri STATIC_ARGS
  222. #emit SMUL.C 4
  223. #emit ADD
  224. #emit STOR.S.pri arg_start
  225. // Using an assembly loop here screwed the code up as the labels added some
  226. // odd stack/frame manipulation code...
  227. while (arg_end != arg_start)
  228. {
  229. #emit MOVE.pri
  230. #emit LOAD.I
  231. #emit PUSH.pri
  232. #emit CONST.pri 4
  233. #emit SUB.alt
  234. #emit STOR.S.pri arg_end
  235. }
  236. // Push the additional parameters.
  237. #emit PUSH.S fmat
  238. #emit PUSH.S function
  239. // Push the argument count.
  240. #emit LOAD.S.pri num_args
  241. #emit ADD.C 8
  242. #emit LOAD.S.alt STATIC_ARGS
  243. #emit XCHG
  244. #emit SMUL.C 4
  245. #emit SUB.alt
  246. #emit PUSH.pri
  247. #emit MOVE.alt
  248. // This gets confused if you have a local variable of the same name as it
  249. // seems to factor in them first, so you get the offset of the local
  250. // variable instead of the index of the native.
  251. #emit SYSREQ.C CallLocalFunction
  252. // Clear the stack.
  253. #emit CONST.pri 4
  254. #emit ADD
  255. #emit MOVE.alt
  256. // The three lines above get the total stack data size, now remove it.
  257. #emit LCTRL 4
  258. #emit ADD
  259. #emit SCTRL 4
  260. // Now do the real return.
  261. }
  262. stock va_SetTimerEx(const function[], interval, bool:repeating, const fmat[], va_:STATIC_ARGS)
  263. {
  264. static
  265. sRet;
  266. new
  267. num_args,
  268. arg_start,
  269. arg_end;
  270. // Get the pointer to the number of arguments to the last function.
  271. #emit LOAD.S.pri 0
  272. #emit ADD.C 8
  273. #emit MOVE.alt
  274. // Get the number of arguments.
  275. #emit LOAD.I
  276. #emit STOR.S.pri num_args
  277. // Get the variable arguments (end).
  278. #emit ADD
  279. #emit STOR.S.pri arg_end
  280. // Get the variable arguments (start).
  281. #emit LOAD.S.pri STATIC_ARGS
  282. #emit SMUL.C 4
  283. #emit ADD
  284. #emit STOR.S.pri arg_start
  285. // Using an assembly loop here screwed the code up as the labels added some
  286. // odd stack/frame manipulation code...
  287. while (arg_end != arg_start)
  288. {
  289. #emit MOVE.pri
  290. #emit LOAD.I
  291. #emit PUSH.pri
  292. #emit CONST.pri 4
  293. #emit SUB.alt
  294. #emit STOR.S.pri arg_end
  295. }
  296. // Push the additional parameters.
  297. #emit PUSH.S fmat
  298. #emit PUSH.S repeating
  299. #emit PUSH.S interval
  300. #emit PUSH.S function
  301. // Push the argument count.
  302. #emit LOAD.S.pri num_args
  303. #emit ADD.C 16
  304. #emit LOAD.S.alt STATIC_ARGS
  305. #emit XCHG
  306. #emit SMUL.C 4
  307. #emit SUB.alt
  308. #emit PUSH.pri
  309. #emit MOVE.alt
  310. // This gets confused if you have a local variable of the same name as it
  311. // seems to factor in them first, so you get the offset of the local
  312. // variable instead of the index of the native.
  313. #emit SYSREQ.C SetTimerEx
  314. #emit STOR.pri sRet
  315. // Clear the stack.
  316. #emit CONST.pri 4
  317. #emit ADD
  318. #emit MOVE.alt
  319. // The three lines above get the total stack data size, now remove it.
  320. #emit LCTRL 4
  321. #emit ADD
  322. #emit SCTRL 4
  323. // Now do the real return.
  324. return sRet;
  325. }
  326. stock va_format(out[], size, const fmat[], va_:STATIC_ARGS)
  327. {
  328. new
  329. num_args,
  330. arg_start,
  331. arg_end;
  332. // Get the pointer to the number of arguments to the last function.
  333. #emit LOAD.S.pri 0
  334. #emit ADD.C 8
  335. #emit MOVE.alt
  336. // Get the number of arguments.
  337. #emit LOAD.I
  338. #emit STOR.S.pri num_args
  339. // Get the variable arguments (end).
  340. #emit ADD
  341. #emit STOR.S.pri arg_end
  342. // Get the variable arguments (start).
  343. #emit LOAD.S.pri STATIC_ARGS
  344. #emit SMUL.C 4
  345. #emit ADD
  346. #emit STOR.S.pri arg_start
  347. // Using an assembly loop here screwed the code up as the labels added some
  348. // odd stack/frame manipulation code...
  349. while (arg_end != arg_start)
  350. {
  351. #emit MOVE.pri
  352. #emit LOAD.I
  353. #emit PUSH.pri
  354. #emit CONST.pri 4
  355. #emit SUB.alt
  356. #emit STOR.S.pri arg_end
  357. }
  358. // Push the additional parameters.
  359. #emit PUSH.S fmat
  360. #emit PUSH.S size
  361. #emit PUSH.S out
  362. // Push the argument count.
  363. #emit LOAD.S.pri num_args
  364. #emit ADD.C 12
  365. #emit LOAD.S.alt STATIC_ARGS
  366. #emit XCHG
  367. #emit SMUL.C 4
  368. #emit SUB.alt
  369. #emit PUSH.pri
  370. #emit MOVE.alt
  371. // This gets confused if you have a local variable of the same name as it
  372. // seems to factor in them first, so you get the offset of the local
  373. // variable instead of the index of the native.
  374. #emit SYSREQ.C format
  375. // Clear the stack.
  376. #emit CONST.pri 4
  377. #emit ADD
  378. #emit MOVE.alt
  379. // The three lines above get the total stack data size, now remove it.
  380. #emit LCTRL 4
  381. #emit ADD
  382. #emit SCTRL 4
  383. // Now do the real return.
  384. }
  385. stock va_return(const fmat[], va_:STATIC_ARGS)
  386. {
  387. static
  388. out[YSI_MAX_STRING * 8],
  389. size = YSI_MAX_STRING;
  390. new
  391. num_args,
  392. arg_start,
  393. arg_end;
  394. // Get the pointer to the number of arguments to the last function.
  395. #emit LOAD.S.pri 0
  396. #emit ADD.C 8
  397. #emit MOVE.alt
  398. // Get the number of arguments.
  399. #emit LOAD.I
  400. #emit STOR.S.pri num_args
  401. // Get the variable arguments (end).
  402. #emit ADD
  403. #emit STOR.S.pri arg_end
  404. // Get the variable arguments (start).
  405. #emit LOAD.S.pri STATIC_ARGS
  406. #emit SMUL.C 4
  407. #emit ADD
  408. #emit STOR.S.pri arg_start
  409. // Using an assembly loop here screwed the code up as the labels added some
  410. // odd stack/frame manipulation code...
  411. while (arg_end != arg_start)
  412. {
  413. #emit MOVE.pri
  414. #emit LOAD.I
  415. #emit PUSH.pri
  416. #emit CONST.pri 4
  417. #emit SUB.alt
  418. #emit STOR.S.pri arg_end
  419. }
  420. // Push the additional parameters.
  421. #emit PUSH.S fmat
  422. #emit PUSH size
  423. #emit PUSH.C out
  424. // Push the argument count.
  425. #emit LOAD.S.pri num_args
  426. #emit ADD.C 12
  427. #emit LOAD.S.alt STATIC_ARGS
  428. #emit XCHG
  429. #emit SMUL.C 4
  430. #emit SUB.alt
  431. #emit PUSH.pri
  432. #emit MOVE.alt
  433. // This gets confused if you have a local variable of the same name as it
  434. // seems to factor in them first, so you get the offset of the local
  435. // variable instead of the index of the native.
  436. #emit SYSREQ.C format
  437. // Clear the stack.
  438. #emit CONST.pri 4
  439. #emit ADD
  440. #emit MOVE.alt
  441. // The three lines above get the total stack data size, now remove it.
  442. #emit LCTRL 4
  443. #emit ADD
  444. #emit SCTRL 4
  445. // Now do the real return.
  446. return out;
  447. }
  448. stock va_strlen(arg)
  449. {
  450. // Get the length of the string at the given position on the previous
  451. // function's stack (convenience function).
  452. // Get the address of the previous function's stack. First get the index of
  453. // the argument required.
  454. #emit LOAD.S.pri arg
  455. // Then convert that number to bytes from cells.
  456. #emit SMUL.C 4
  457. // Get the previous function's frame. Stored in variable 0 (in the current
  458. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  459. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  460. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  461. // count (in C pointer speak).
  462. #emit LOAD.S.alt 0
  463. // Add the frame pointer to the argument offset in bytes.
  464. #emit ADD
  465. // Add 12 to skip over the function header.
  466. #emit ADD.C 12
  467. // Load the address stored in the specified address.
  468. #emit LOAD.I
  469. // Push the address we just determined was the source.
  470. #emit PUSH.pri
  471. // Push the number of parameters passed (in bytes) to the function.
  472. #emit PUSH.C 4
  473. // Call the function.
  474. #emit SYSREQ.C strlen
  475. // Restore the stack to its level before we called this native.
  476. #emit STACK 8
  477. #emit RETN
  478. // Never called.
  479. return 0;
  480. }
  481. stock va_getstring(dest[], arg, len = sizeof (dest))
  482. {
  483. // Get the address of the previous function's stack. First get the index of
  484. // the argument required.
  485. #emit LOAD.S.pri arg
  486. // Then convert that number to bytes from cells.
  487. #emit SMUL.C 4
  488. // Get the previous function's frame. Stored in variable 0 (in the current
  489. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  490. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  491. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  492. // count (in C pointer speak).
  493. #emit LOAD.S.alt 0
  494. // Add the frame pointer to the argument offset in bytes.
  495. #emit ADD
  496. // Add 12 to skip over the function header.
  497. #emit ADD.C 12
  498. // Load the address stored in the specified address.
  499. #emit LOAD.I
  500. // Push the length for "strcat".
  501. #emit PUSH.S len
  502. // Push the address we just determined was the source.
  503. #emit PUSH.pri
  504. // Load the address of the destination.
  505. #emit LOAD.S.alt dest
  506. // Blank the first cell so "strcat" behaves like "strcpy".
  507. #emit CONST.pri 0
  508. // Store the loaded number 0 to the loaded address.
  509. #emit STOR.I
  510. // Push the loaded address.
  511. #emit PUSH.alt
  512. // Push the number of parameters passed (in bytes) to the function.
  513. #emit PUSH.C 12
  514. // Call the function.
  515. #emit SYSREQ.C strcat
  516. // Restore the stack to its level before we called this native.
  517. #emit STACK 16
  518. }
  519. stock PlayerText:va_CreatePlayerTextDraw(playerid, Float:x, Float:y, fmat[], va_args<>)
  520. {
  521. return CreatePlayerTextDraw(playerid, x, y, va_return(fmat, va_start<4>));
  522. }
  523. stock Text:va_TextDrawCreate(Float:x, Float:y, fmat[], va_args<>)
  524. {
  525. return TextDrawCreate(x, y, va_return(fmat, va_start<3>));
  526. }
  527. stock va_SendClientMessage(playerid, colour, const fmat[], va_args<>)
  528. {
  529. return SendClientMessage(playerid, colour, va_return(fmat, va_start<3>));
  530. }
  531. stock va_SendClientMessageToAll(colour, const fmat[], va_args<>)
  532. {
  533. return SendClientMessageToAll(colour, va_return(fmat, va_start<2>));
  534. }
  535. stock va_SendPlayerMessageToPlayer(playerid, senderid, const fmat[], va_args<>)
  536. {
  537. return SendPlayerMessageToPlayer(playerid, senderid, va_return(fmat, va_start<3>));
  538. }
  539. stock va_SendPlayerMessageToAll(senderid, const fmat[], va_args<>)
  540. {
  541. return SendPlayerMessageToAll(senderid, va_return(fmat, va_start<2>));
  542. }
  543. stock va_GameTextForPlayer(playerid, const fmat[], time, style, va_args<>)
  544. {
  545. return GameTextForPlayer(playerid, va_return(fmat, va_start<4>), time, style);
  546. }
  547. stock va_GameTextForAll(const fmat[], time, style, va_args<>)
  548. {
  549. return GameTextForAll(va_return(fmat, va_start<3>), time, style);
  550. }
  551. stock va_print(const fmat[], va_args<>)
  552. {
  553. return print(va_return(fmat, va_start<1>));
  554. }