y_va.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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. \*----------------------------------------------------------------------------*/
  85. #include "internal\y_version"
  86. #include "internal\y_funcinc"
  87. #include "y_utils"
  88. //#define va_args<%0> %0
  89. #define va_args<%0> GLOBAL_TAG_TYPES:...
  90. #define va_start<%0> (va_:(%0))
  91. stock va_printf(const fmat[], va_:STATIC_ARGS)
  92. {
  93. new
  94. num_args,
  95. arg_start,
  96. arg_end;
  97. // Get the pointer to the number of arguments to the last function.
  98. #emit LOAD.S.pri 0
  99. #emit ADD.C 8
  100. #emit MOVE.alt
  101. // Get the number of arguments.
  102. #emit LOAD.I
  103. #emit STOR.S.pri num_args
  104. // Get the variable arguments (end).
  105. #emit ADD
  106. #emit STOR.S.pri arg_end
  107. // Get the variable arguments (start).
  108. #emit LOAD.S.pri STATIC_ARGS
  109. #emit SMUL.C 4
  110. #emit ADD
  111. #emit STOR.S.pri arg_start
  112. // Using an assembly loop here screwed the code up as the labels added some
  113. // odd stack/frame manipulation code...
  114. while (arg_end != arg_start)
  115. {
  116. #emit MOVE.pri
  117. #emit LOAD.I
  118. #emit PUSH.pri
  119. #emit CONST.pri 4
  120. #emit SUB.alt
  121. #emit STOR.S.pri arg_end
  122. }
  123. // Push the additional parameters.
  124. #emit PUSH.S fmat
  125. // Push the argument count.
  126. #emit LOAD.S.pri num_args
  127. #emit ADD.C 4
  128. #emit LOAD.S.alt STATIC_ARGS
  129. #emit XCHG
  130. #emit SMUL.C 4
  131. #emit SUB.alt
  132. #emit PUSH.pri
  133. #emit MOVE.alt
  134. // This gets confused if you have a local variable of the same name as it
  135. // seems to factor in them first, so you get the offset of the local
  136. // variable instead of the index of the native.
  137. #emit SYSREQ.C printf
  138. // Clear the stack.
  139. #emit CONST.pri 4
  140. #emit ADD
  141. #emit MOVE.alt
  142. // The three lines above get the total stack data size, now remove it.
  143. #emit LCTRL 4
  144. #emit ADD
  145. #emit SCTRL 4
  146. // Now do the real return.
  147. }
  148. stock va_CallRemoteFunction(const function[], const fmat[], va_:STATIC_ARGS)
  149. {
  150. new
  151. num_args,
  152. arg_start,
  153. arg_end;
  154. // Get the pointer to the number of arguments to the last function.
  155. #emit LOAD.S.pri 0
  156. #emit ADD.C 8
  157. #emit MOVE.alt
  158. // Get the number of arguments.
  159. #emit LOAD.I
  160. #emit STOR.S.pri num_args
  161. // Get the variable arguments (end).
  162. #emit ADD
  163. #emit STOR.S.pri arg_end
  164. // Get the variable arguments (start).
  165. #emit LOAD.S.pri STATIC_ARGS
  166. #emit SMUL.C 4
  167. #emit ADD
  168. #emit STOR.S.pri arg_start
  169. // Using an assembly loop here screwed the code up as the labels added some
  170. // odd stack/frame manipulation code...
  171. while (arg_end != arg_start)
  172. {
  173. #emit MOVE.pri
  174. #emit LOAD.I
  175. #emit PUSH.pri
  176. #emit CONST.pri 4
  177. #emit SUB.alt
  178. #emit STOR.S.pri arg_end
  179. }
  180. // Push the additional parameters.
  181. #emit PUSH.S fmat
  182. #emit PUSH.S function
  183. // Push the argument count.
  184. #emit LOAD.S.pri num_args
  185. #emit ADD.C 8
  186. #emit LOAD.S.alt STATIC_ARGS
  187. #emit XCHG
  188. #emit SMUL.C 4
  189. #emit SUB.alt
  190. #emit PUSH.pri
  191. #emit MOVE.alt
  192. // This gets confused if you have a local variable of the same name as it
  193. // seems to factor in them first, so you get the offset of the local
  194. // variable instead of the index of the native.
  195. #emit SYSREQ.C CallRemoteFunction
  196. // Clear the stack.
  197. #emit CONST.pri 4
  198. #emit ADD
  199. #emit MOVE.alt
  200. // The three lines above get the total stack data size, now remove it.
  201. #emit LCTRL 4
  202. #emit ADD
  203. #emit SCTRL 4
  204. // Now do the real return.
  205. }
  206. stock va_CallLocalFunction(const function[], const fmat[], va_:STATIC_ARGS)
  207. {
  208. new
  209. num_args,
  210. arg_start,
  211. arg_end;
  212. // Get the pointer to the number of arguments to the last function.
  213. #emit LOAD.S.pri 0
  214. #emit ADD.C 8
  215. #emit MOVE.alt
  216. // Get the number of arguments.
  217. #emit LOAD.I
  218. #emit STOR.S.pri num_args
  219. // Get the variable arguments (end).
  220. #emit ADD
  221. #emit STOR.S.pri arg_end
  222. // Get the variable arguments (start).
  223. #emit LOAD.S.pri STATIC_ARGS
  224. #emit SMUL.C 4
  225. #emit ADD
  226. #emit STOR.S.pri arg_start
  227. // Using an assembly loop here screwed the code up as the labels added some
  228. // odd stack/frame manipulation code...
  229. while (arg_end != arg_start)
  230. {
  231. #emit MOVE.pri
  232. #emit LOAD.I
  233. #emit PUSH.pri
  234. #emit CONST.pri 4
  235. #emit SUB.alt
  236. #emit STOR.S.pri arg_end
  237. }
  238. // Push the additional parameters.
  239. #emit PUSH.S fmat
  240. #emit PUSH.S function
  241. // Push the argument count.
  242. #emit LOAD.S.pri num_args
  243. #emit ADD.C 8
  244. #emit LOAD.S.alt STATIC_ARGS
  245. #emit XCHG
  246. #emit SMUL.C 4
  247. #emit SUB.alt
  248. #emit PUSH.pri
  249. #emit MOVE.alt
  250. // This gets confused if you have a local variable of the same name as it
  251. // seems to factor in them first, so you get the offset of the local
  252. // variable instead of the index of the native.
  253. #emit SYSREQ.C CallLocalFunction
  254. // Clear the stack.
  255. #emit CONST.pri 4
  256. #emit ADD
  257. #emit MOVE.alt
  258. // The three lines above get the total stack data size, now remove it.
  259. #emit LCTRL 4
  260. #emit ADD
  261. #emit SCTRL 4
  262. // Now do the real return.
  263. }
  264. stock va_SetTimerEx(const function[], interval, bool:repeating, const fmat[], va_:STATIC_ARGS)
  265. {
  266. static
  267. sRet;
  268. new
  269. num_args,
  270. arg_start,
  271. arg_end;
  272. // Get the pointer to the number of arguments to the last function.
  273. #emit LOAD.S.pri 0
  274. #emit ADD.C 8
  275. #emit MOVE.alt
  276. // Get the number of arguments.
  277. #emit LOAD.I
  278. #emit STOR.S.pri num_args
  279. // Get the variable arguments (end).
  280. #emit ADD
  281. #emit STOR.S.pri arg_end
  282. // Get the variable arguments (start).
  283. #emit LOAD.S.pri STATIC_ARGS
  284. #emit SMUL.C 4
  285. #emit ADD
  286. #emit STOR.S.pri arg_start
  287. // Using an assembly loop here screwed the code up as the labels added some
  288. // odd stack/frame manipulation code...
  289. while (arg_end != arg_start)
  290. {
  291. #emit MOVE.pri
  292. #emit LOAD.I
  293. #emit PUSH.pri
  294. #emit CONST.pri 4
  295. #emit SUB.alt
  296. #emit STOR.S.pri arg_end
  297. }
  298. // Push the additional parameters.
  299. #emit PUSH.S fmat
  300. #emit PUSH.S repeating
  301. #emit PUSH.S interval
  302. #emit PUSH.S function
  303. // Push the argument count.
  304. #emit LOAD.S.pri num_args
  305. #emit ADD.C 16
  306. #emit LOAD.S.alt STATIC_ARGS
  307. #emit XCHG
  308. #emit SMUL.C 4
  309. #emit SUB.alt
  310. #emit PUSH.pri
  311. #emit MOVE.alt
  312. // This gets confused if you have a local variable of the same name as it
  313. // seems to factor in them first, so you get the offset of the local
  314. // variable instead of the index of the native.
  315. #emit SYSREQ.C SetTimerEx
  316. #emit STOR.pri sRet
  317. // Clear the stack.
  318. #emit CONST.pri 4
  319. #emit ADD
  320. #emit MOVE.alt
  321. // The three lines above get the total stack data size, now remove it.
  322. #emit LCTRL 4
  323. #emit ADD
  324. #emit SCTRL 4
  325. // Now do the real return.
  326. return sRet;
  327. }
  328. stock va_format(out[], size, const fmat[], va_:STATIC_ARGS)
  329. {
  330. new
  331. num_args,
  332. arg_start,
  333. arg_end;
  334. // Get the pointer to the number of arguments to the last function.
  335. #emit LOAD.S.pri 0
  336. #emit ADD.C 8
  337. #emit MOVE.alt
  338. // Get the number of arguments.
  339. #emit LOAD.I
  340. #emit STOR.S.pri num_args
  341. // Get the variable arguments (end).
  342. #emit ADD
  343. #emit STOR.S.pri arg_end
  344. // Get the variable arguments (start).
  345. #emit LOAD.S.pri STATIC_ARGS
  346. #emit SMUL.C 4
  347. #emit ADD
  348. #emit STOR.S.pri arg_start
  349. // Using an assembly loop here screwed the code up as the labels added some
  350. // odd stack/frame manipulation code...
  351. while (arg_end != arg_start)
  352. {
  353. #emit MOVE.pri
  354. #emit LOAD.I
  355. #emit PUSH.pri
  356. #emit CONST.pri 4
  357. #emit SUB.alt
  358. #emit STOR.S.pri arg_end
  359. }
  360. // Push the additional parameters.
  361. #emit PUSH.S fmat
  362. #emit PUSH.S size
  363. #emit PUSH.S out
  364. // Push the argument count.
  365. #emit LOAD.S.pri num_args
  366. #emit ADD.C 12
  367. #emit LOAD.S.alt STATIC_ARGS
  368. #emit XCHG
  369. #emit SMUL.C 4
  370. #emit SUB.alt
  371. #emit PUSH.pri
  372. #emit MOVE.alt
  373. // This gets confused if you have a local variable of the same name as it
  374. // seems to factor in them first, so you get the offset of the local
  375. // variable instead of the index of the native.
  376. #emit SYSREQ.C format
  377. // Clear the stack.
  378. #emit CONST.pri 4
  379. #emit ADD
  380. #emit MOVE.alt
  381. // The three lines above get the total stack data size, now remove it.
  382. #emit LCTRL 4
  383. #emit ADD
  384. #emit SCTRL 4
  385. // Now do the real return.
  386. }
  387. stock va_return(const fmat[], va_:STATIC_ARGS)
  388. {
  389. static
  390. out[YSI_MAX_STRING * 8],
  391. size = YSI_MAX_STRING;
  392. new
  393. num_args,
  394. arg_start,
  395. arg_end;
  396. // Get the pointer to the number of arguments to the last function.
  397. #emit LOAD.S.pri 0
  398. #emit ADD.C 8
  399. #emit MOVE.alt
  400. // Get the number of arguments.
  401. #emit LOAD.I
  402. #emit STOR.S.pri num_args
  403. // Get the variable arguments (end).
  404. #emit ADD
  405. #emit STOR.S.pri arg_end
  406. // Get the variable arguments (start).
  407. #emit LOAD.S.pri STATIC_ARGS
  408. #emit SMUL.C 4
  409. #emit ADD
  410. #emit STOR.S.pri arg_start
  411. // Using an assembly loop here screwed the code up as the labels added some
  412. // odd stack/frame manipulation code...
  413. while (arg_end != arg_start)
  414. {
  415. #emit MOVE.pri
  416. #emit LOAD.I
  417. #emit PUSH.pri
  418. #emit CONST.pri 4
  419. #emit SUB.alt
  420. #emit STOR.S.pri arg_end
  421. }
  422. // Push the additional parameters.
  423. #emit PUSH.S fmat
  424. #emit PUSH size
  425. #emit PUSH.C out
  426. // Push the argument count.
  427. #emit LOAD.S.pri num_args
  428. #emit ADD.C 12
  429. #emit LOAD.S.alt STATIC_ARGS
  430. #emit XCHG
  431. #emit SMUL.C 4
  432. #emit SUB.alt
  433. #emit PUSH.pri
  434. #emit MOVE.alt
  435. // This gets confused if you have a local variable of the same name as it
  436. // seems to factor in them first, so you get the offset of the local
  437. // variable instead of the index of the native.
  438. #emit SYSREQ.C format
  439. // Clear the stack.
  440. #emit CONST.pri 4
  441. #emit ADD
  442. #emit MOVE.alt
  443. // The three lines above get the total stack data size, now remove it.
  444. #emit LCTRL 4
  445. #emit ADD
  446. #emit SCTRL 4
  447. // Now do the real return.
  448. return out;
  449. }
  450. stock va_strlen(arg)
  451. {
  452. // Get the length of the string at the given position on the previous
  453. // function's stack (convenience function).
  454. // Get the address of the previous function's stack. First get the index of
  455. // the argument required.
  456. #emit LOAD.S.pri arg
  457. // Then convert that number to bytes from cells.
  458. #emit SMUL.C 4
  459. // Get the previous function's frame. Stored in variable 0 (in the current
  460. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  461. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  462. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  463. // count (in C pointer speak).
  464. #emit LOAD.S.alt 0
  465. // Add the frame pointer to the argument offset in bytes.
  466. #emit ADD
  467. // Add 12 to skip over the function header.
  468. #emit ADD.C 12
  469. // Load the address stored in the specified address.
  470. #emit LOAD.I
  471. // Push the address we just determined was the source.
  472. #emit PUSH.pri
  473. // Push the number of parameters passed (in bytes) to the function.
  474. #emit PUSH.C 4
  475. // Call the function.
  476. #emit SYSREQ.C strlen
  477. // Restore the stack to its level before we called this native.
  478. #emit STACK 8
  479. #emit RETN
  480. // Never called.
  481. return 0;
  482. }
  483. stock va_getstring(dest[], arg, len = sizeof (dest))
  484. {
  485. // Get the address of the previous function's stack. First get the index of
  486. // the argument required.
  487. #emit LOAD.S.pri arg
  488. // Then convert that number to bytes from cells.
  489. #emit SMUL.C 4
  490. // Get the previous function's frame. Stored in variable 0 (in the current
  491. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  492. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  493. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  494. // count (in C pointer speak).
  495. #emit LOAD.S.alt 0
  496. // Add the frame pointer to the argument offset in bytes.
  497. #emit ADD
  498. // Add 12 to skip over the function header.
  499. #emit ADD.C 12
  500. // Load the address stored in the specified address.
  501. #emit LOAD.I
  502. // Push the length for "strcat".
  503. #emit PUSH.S len
  504. // Push the address we just determined was the source.
  505. #emit PUSH.pri
  506. // Load the address of the destination.
  507. #emit LOAD.S.alt dest
  508. // Blank the first cell so "strcat" behaves like "strcpy".
  509. #emit CONST.pri 0
  510. // Store the loaded number 0 to the loaded address.
  511. #emit STOR.I
  512. // Push the loaded address.
  513. #emit PUSH.alt
  514. // Push the number of parameters passed (in bytes) to the function.
  515. #emit PUSH.C 12
  516. // Call the function.
  517. #emit SYSREQ.C strcat
  518. // Restore the stack to its level before we called this native.
  519. #emit STACK 16
  520. }
  521. stock PlayerText:va_CreatePlayerTextDraw(playerid, Float:x, Float:y, fmat[], va_args<>)
  522. {
  523. return CreatePlayerTextDraw(playerid, x, y, va_return(fmat, va_start<4>));
  524. }
  525. stock Text:va_TextDrawCreate(Float:x, Float:y, fmat[], va_args<>)
  526. {
  527. return TextDrawCreate(x, y, va_return(fmat, va_start<3>));
  528. }
  529. stock va_SendClientMessage(playerid, colour, const fmat[], va_args<>)
  530. {
  531. return SendClientMessage(playerid, colour, va_return(fmat, va_start<3>));
  532. }
  533. stock va_SendClientMessageToAll(colour, const fmat[], va_args<>)
  534. {
  535. return SendClientMessageToAll(colour, va_return(fmat, va_start<2>));
  536. }
  537. stock va_SendPlayerMessageToPlayer(playerid, senderid, const fmat[], va_args<>)
  538. {
  539. return SendPlayerMessageToPlayer(playerid, senderid, va_return(fmat, va_start<3>));
  540. }
  541. stock va_SendPlayerMessageToAll(senderid, const fmat[], va_args<>)
  542. {
  543. return SendPlayerMessageToAll(senderid, va_return(fmat, va_start<2>));
  544. }
  545. stock va_GameTextForPlayer(playerid, const fmat[], time, style, va_args<>)
  546. {
  547. return GameTextForPlayer(playerid, va_return(fmat, va_start<4>), time, style);
  548. }
  549. stock va_GameTextForAll(const fmat[], time, style, va_args<>)
  550. {
  551. return GameTextForAll(va_return(fmat, va_start<3>), time, style);
  552. }
  553. stock va_print(const fmat[], va_args<>)
  554. {
  555. return print(va_return(fmat, va_start<1>));
  556. }