impl.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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. static stock
  86. YSI_g_sHeap,
  87. YSI_g_sStack,
  88. YSI_g_sArgCount,
  89. YSI_g_sArgs[5];
  90. stock va_printf(const fmat[], va_:STATIC_ARGS)
  91. {
  92. // Get the number of parameters.
  93. #emit LOAD.S.alt STATIC_ARGS
  94. #emit INC.alt // 2 - n
  95. #emit SHL.C.alt 2
  96. // "alt" now contains the number of static arguments in bytes - 4.
  97. // Get the previous parameter count.
  98. #emit LOAD.S.pri 0
  99. #emit ADD.C 8
  100. #emit LOAD.I
  101. #emit SUB
  102. #emit ADD.C 8
  103. #emit STOR.pri YSI_g_sArgCount // "printf"s parameter count.
  104. // Get the address of the arguments we are replacing.
  105. #emit LOAD.S.pri 0
  106. #emit ADD
  107. // Copy them to our temporary buffer.
  108. #emit CONST.alt YSI_g_sArgs
  109. #emit MOVS 8 // (n + 1) * 4
  110. // Go to the new "top" of the stack.
  111. #emit STACK 0
  112. #emit STOR.alt YSI_g_sStack // Store it.
  113. #emit ADD.C 8 // (n + 1) * 4
  114. #emit SCTRL 4
  115. // "frm" is still valid.
  116. #emit PUSH.S fmat // Get the final parameter.
  117. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  118. // Call the function.
  119. #emit SYSREQ.C printf
  120. // Copy the data back.
  121. #emit STACK 0
  122. #emit CONST.pri YSI_g_sArgs
  123. #emit MOVS 8
  124. #emit LOAD.pri YSI_g_sStack
  125. #emit SCTRL 4
  126. #emit RETN
  127. // This new version of the code worked first time! I'm very happy with that
  128. // result, but I also feel it was justified given how long I spent staring
  129. // at it!
  130. return 0;
  131. }
  132. stock va_CallRemoteFunction(const function[], const fmat[], va_:STATIC_ARGS)
  133. {
  134. // Get the number of parameters.
  135. #emit LOAD.S.alt STATIC_ARGS
  136. #emit SHL.C.alt 2
  137. // "alt" now contains the number of static arguments in bytes.
  138. // Get the previous parameter count.
  139. #emit LOAD.S.pri 0
  140. #emit ADD.C 8
  141. #emit LOAD.I
  142. #emit SUB
  143. #emit ADD.C 8
  144. #emit STOR.pri YSI_g_sArgCount // "format"s parameter count.
  145. // Get the address of the arguments we are replacing.
  146. #emit LOAD.S.pri 0
  147. #emit ADD
  148. // Copy them to our temporary buffer.
  149. #emit CONST.alt YSI_g_sArgs
  150. #emit MOVS 12 // (n + 1) * 4
  151. // Go to the new "top" of the stack.
  152. #emit STACK 0
  153. #emit STOR.alt YSI_g_sStack // Store it.
  154. #emit ADD.C 12 // (n + 1) * 4
  155. #emit SCTRL 4
  156. // "frm" is still valid.
  157. #emit PUSH.S fmat
  158. #emit PUSH.S function
  159. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  160. // Call the function.
  161. #emit SYSREQ.C CallRemoteFunction
  162. // Copy the data back.
  163. #emit STACK 0
  164. #emit CONST.pri YSI_g_sArgs
  165. #emit MOVS 12
  166. #emit LOAD.pri YSI_g_sStack
  167. #emit SCTRL 4
  168. return 0;
  169. }
  170. stock va_CallLocalFunction(const function[], const fmat[], va_:STATIC_ARGS)
  171. {
  172. // Get the number of parameters.
  173. #emit LOAD.S.alt STATIC_ARGS
  174. #emit SHL.C.alt 2
  175. // "alt" now contains the number of static arguments in bytes.
  176. // Get the previous parameter count.
  177. #emit LOAD.S.pri 0
  178. #emit ADD.C 8
  179. #emit LOAD.I
  180. #emit SUB
  181. #emit ADD.C 8
  182. #emit STOR.pri YSI_g_sArgCount // "format"s parameter count.
  183. // Get the address of the arguments we are replacing.
  184. #emit LOAD.S.pri 0
  185. #emit ADD
  186. // Copy them to our temporary buffer.
  187. #emit CONST.alt YSI_g_sArgs
  188. #emit MOVS 12 // (n + 1) * 4
  189. // Go to the new "top" of the stack.
  190. #emit STACK 0
  191. #emit STOR.alt YSI_g_sStack // Store it.
  192. #emit ADD.C 12 // (n + 1) * 4
  193. #emit SCTRL 4
  194. // "frm" is still valid.
  195. #emit PUSH.S fmat
  196. #emit PUSH.S function
  197. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  198. // Call the function.
  199. #emit SYSREQ.C CallLocalFunction
  200. // Copy the data back.
  201. #emit STACK 0
  202. #emit CONST.pri YSI_g_sArgs
  203. #emit MOVS 12
  204. #emit LOAD.pri YSI_g_sStack
  205. #emit SCTRL 4
  206. return 0;
  207. }
  208. stock va_SetTimerEx(const function[], interval, bool:repeating, const fmat[], va_:STATIC_ARGS)
  209. {
  210. // Get the number of parameters.
  211. #emit LOAD.S.alt STATIC_ARGS
  212. #emit DEC.alt // 2 - n
  213. #emit DEC.alt
  214. #emit SHL.C.alt 2
  215. // "alt" now contains the number of static arguments in bytes - 8.
  216. // Get the previous parameter count.
  217. #emit LOAD.S.pri 0
  218. #emit ADD.C 8
  219. #emit LOAD.I
  220. #emit SUB
  221. #emit ADD.C 8
  222. #emit STOR.pri YSI_g_sArgCount // "format"s parameter count.
  223. // Get the address of the arguments we are replacing.
  224. #emit LOAD.S.pri 0
  225. #emit ADD
  226. // Copy them to our temporary buffer.
  227. #emit CONST.alt YSI_g_sArgs
  228. #emit MOVS 20 // (n + 1) * 4
  229. // Go to the new "top" of the stack.
  230. #emit STACK 0
  231. #emit STOR.alt YSI_g_sStack // Store it.
  232. #emit ADD.C 20 // (n + 1) * 4
  233. #emit SCTRL 4
  234. // "frm" is still valid.
  235. #emit PUSH.S fmat
  236. #emit PUSH.S repeating
  237. #emit PUSH.S interval
  238. #emit PUSH.S function
  239. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  240. // Call the function.
  241. #emit SYSREQ.C SetTimerEx
  242. #emit STOR.pri YSI_g_sArgCount
  243. // Copy the data back.
  244. #emit STACK 0
  245. #emit CONST.pri YSI_g_sArgs
  246. #emit MOVS 20
  247. #emit LOAD.pri YSI_g_sStack
  248. #emit SCTRL 4
  249. #emit LOAD.pri YSI_g_sArgCount
  250. #emit RETN
  251. return 0;
  252. }
  253. stock va_format(out[], size, const fmat[], va_:STATIC_ARGS)
  254. {
  255. P:C(if (_:STATIC_ARGS < 1) P:W("No static args found, please add a dummy local"););
  256. // Get the number of parameters.
  257. #emit LOAD.S.alt STATIC_ARGS
  258. #emit DEC.alt // 2 - n
  259. #emit SHL.C.alt 2
  260. // "alt" now contains the number of static arguments in bytes - 4.
  261. // Get the previous parameter count.
  262. #emit LOAD.S.pri 0
  263. #emit ADD.C 8
  264. #emit LOAD.I
  265. #emit SUB
  266. #emit ADD.C 8
  267. #emit STOR.pri YSI_g_sArgCount // "format"s parameter count.
  268. // Get the address of the arguments we are replacing.
  269. #emit LOAD.S.pri 0
  270. #emit ADD
  271. // Copy them to our temporary buffer.
  272. #emit CONST.alt YSI_g_sArgs
  273. #emit MOVS 16 // (n + 1) * 4
  274. // Go to the new "top" of the stack.
  275. #emit STACK 0
  276. #emit STOR.alt YSI_g_sStack // Store it.
  277. #emit ADD.C 16 // (n + 1) * 4
  278. #emit SCTRL 4
  279. // "frm" is still valid.
  280. #emit PUSH.S fmat
  281. #emit PUSH.S size
  282. #emit PUSH.S out
  283. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  284. // Modify the heap to hold "locals".
  285. #emit HEAP 0
  286. #emit STOR.alt YSI_g_sHeap
  287. #emit LCTRL 4
  288. #emit SCTRL 2
  289. // Call the function.
  290. #emit SYSREQ.C format
  291. // Copy the data back.
  292. #emit LOAD.pri YSI_g_sHeap
  293. #emit SCTRL 2
  294. #emit STACK 0
  295. #emit CONST.pri YSI_g_sArgs
  296. #emit MOVS 16
  297. #emit LOAD.pri YSI_g_sStack
  298. #emit SCTRL 4
  299. #emit RETN
  300. return 0;
  301. }
  302. stock va_return(const fmat[], va_:STATIC_ARGS)
  303. {
  304. static
  305. out[YSI_MAX_STRING * 8],
  306. size = sizeof (out);
  307. // Get the number of parameters.
  308. #emit LOAD.S.alt STATIC_ARGS
  309. #emit DEC.alt // 2 - n
  310. #emit SHL.C.alt 2
  311. // "alt" now contains the number of static arguments in bytes - 4.
  312. // Get the previous parameter count.
  313. #emit LOAD.S.pri 0
  314. #emit ADD.C 8
  315. #emit LOAD.I
  316. #emit SUB
  317. #emit ADD.C 8
  318. #emit STOR.pri YSI_g_sArgCount // "format"s parameter count.
  319. // Get the address of the arguments we are replacing.
  320. #emit LOAD.S.pri 0
  321. #emit ADD
  322. // Copy them to our temporary buffer.
  323. #emit CONST.alt YSI_g_sArgs
  324. #emit MOVS 16 // (n + 1) * 4
  325. // Go to the new "top" of the stack.
  326. #emit STACK 0
  327. #emit STOR.alt YSI_g_sStack // Store it.
  328. #emit ADD.C 16 // (n + 1) * 4
  329. #emit SCTRL 4
  330. // "frm" is still valid.
  331. #emit PUSH.S fmat
  332. #emit PUSH size
  333. #emit PUSH.C out
  334. #emit PUSH YSI_g_sArgCount // Push the parameter count.
  335. // Modify the heap to hold "locals".
  336. #emit HEAP 0
  337. #emit STOR.alt YSI_g_sHeap
  338. #emit LCTRL 4
  339. #emit SCTRL 2
  340. // Call the function.
  341. #emit SYSREQ.C format
  342. // Copy the data back.
  343. #emit LOAD.pri YSI_g_sHeap
  344. #emit SCTRL 2
  345. #emit STACK 0
  346. #emit CONST.pri YSI_g_sArgs
  347. #emit MOVS 16
  348. #emit LOAD.pri YSI_g_sStack
  349. #emit SCTRL 4
  350. // Now do the real return.
  351. return out;
  352. }
  353. stock va_strlen(arg)
  354. {
  355. // Get the length of the string at the given position on the previous
  356. // function's stack (convenience function).
  357. // Get the address of the previous function's stack. First get the index of
  358. // the argument required.
  359. #emit LOAD.S.pri arg
  360. // Then convert that number to bytes from cells.
  361. #emit SMUL.C 4
  362. // Get the previous function's frame. Stored in variable 0 (in the current
  363. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  364. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  365. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  366. // count (in C pointer speak).
  367. #emit LOAD.S.alt 0
  368. // Add the frame pointer to the argument offset in bytes.
  369. #emit ADD
  370. // Add 12 to skip over the function header.
  371. #emit ADD.C 12
  372. // Load the address stored in the specified address.
  373. #emit LOAD.I
  374. // Push the address we just determined was the source.
  375. #emit PUSH.pri
  376. // Push the number of parameters passed (in bytes) to the function.
  377. #emit PUSH.C 4
  378. // Call the function.
  379. #emit SYSREQ.C strlen
  380. // Restore the stack to its level before we called this native.
  381. #emit STACK 8
  382. #emit RETN
  383. // Never called.
  384. return 0;
  385. }
  386. stock va_getstring(dest[], arg, len = sizeof (dest))
  387. {
  388. // Get the address of the previous function's stack. First get the index of
  389. // the argument required.
  390. #emit LOAD.S.pri arg
  391. // Then convert that number to bytes from cells.
  392. #emit SMUL.C 4
  393. // Get the previous function's frame. Stored in variable 0 (in the current
  394. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  395. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  396. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  397. // count (in C pointer speak).
  398. #emit LOAD.S.alt 0
  399. // Add the frame pointer to the argument offset in bytes.
  400. #emit ADD
  401. // Add 12 to skip over the function header.
  402. #emit ADD.C 12
  403. // Load the address stored in the specified address.
  404. #emit LOAD.I
  405. // Push the length for "strcat".
  406. #emit PUSH.S len
  407. // Push the address we just determined was the source.
  408. #emit PUSH.pri
  409. // Load the address of the destination.
  410. #emit LOAD.S.alt dest
  411. // Blank the first cell so "strcat" behaves like "strcpy".
  412. #emit CONST.pri 0
  413. // Store the loaded number 0 to the loaded address.
  414. #emit STOR.I
  415. // Push the loaded address.
  416. #emit PUSH.alt
  417. // Push the number of parameters passed (in bytes) to the function.
  418. #emit PUSH.C 12
  419. // Call the function.
  420. #emit SYSREQ.C strcat
  421. // Restore the stack to its level before we called this native.
  422. #emit STACK 16
  423. }
  424. stock PlayerText:va_CreatePlayerTextDraw(playerid, Float:x, Float:y, fmat[], va_args<>)
  425. {
  426. return CreatePlayerTextDraw(playerid, x, y, va_return(fmat, va_start<4>));
  427. }
  428. stock Text:va_TextDrawCreate(Float:x, Float:y, fmat[], va_args<>)
  429. {
  430. return TextDrawCreate(x, y, va_return(fmat, va_start<3>));
  431. }
  432. stock va_SendClientMessage(playerid, colour, const fmat[], va_args<>)
  433. {
  434. return SendClientMessage(playerid, colour, va_return(fmat, va_start<3>));
  435. }
  436. stock va_SendClientMessageToAll(colour, const fmat[], va_args<>)
  437. {
  438. return SendClientMessageToAll(colour, va_return(fmat, va_start<2>));
  439. }
  440. stock va_SendPlayerMessageToPlayer(playerid, senderid, const fmat[], va_args<>)
  441. {
  442. return SendPlayerMessageToPlayer(playerid, senderid, va_return(fmat, va_start<3>));
  443. }
  444. stock va_SendPlayerMessageToAll(senderid, const fmat[], va_args<>)
  445. {
  446. return SendPlayerMessageToAll(senderid, va_return(fmat, va_start<2>));
  447. }
  448. stock va_GameTextForPlayer(playerid, const fmat[], time, style, va_args<>)
  449. {
  450. return GameTextForPlayer(playerid, va_return(fmat, va_start<4>), time, style);
  451. }
  452. stock va_GameTextForAll(const fmat[], time, style, va_args<>)
  453. {
  454. return GameTextForAll(va_return(fmat, va_start<3>), time, style);
  455. }
  456. stock va_print(const fmat[], va_args<>)
  457. {
  458. return print(va_return(fmat, va_start<1>));
  459. }
  460. stock va_fprintf(File:fhnd, const fmat[], va_args<>)
  461. {
  462. return fwrite(fhnd, va_return(fmat, va_start<2>));
  463. }