impl.inc 15 KB

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