1
0

y_va.inc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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(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_format(out[], size, 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 size
  183. #emit PUSH.S out
  184. // Push the argument count.
  185. #emit LOAD.S.pri num_args
  186. #emit ADD.C 12
  187. #emit LOAD.S.alt STATIC_ARGS
  188. #emit XCHG
  189. #emit SMUL.C 4
  190. #emit SUB.alt
  191. #emit PUSH.pri
  192. #emit MOVE.alt
  193. // This gets confused if you have a local variable of the same name as it
  194. // seems to factor in them first, so you get the offset of the local
  195. // variable instead of the index of the native.
  196. #emit SYSREQ.C format
  197. // Clear the stack.
  198. #emit CONST.pri 4
  199. #emit ADD
  200. #emit MOVE.alt
  201. // The three lines above get the total stack data size, now remove it.
  202. #emit LCTRL 4
  203. #emit ADD
  204. #emit SCTRL 4
  205. // Now do the real return.
  206. }
  207. stock va_strlen(arg)
  208. {
  209. // Get the length of the string at the given position on the previous
  210. // function's stack (convenience function).
  211. // Get the address of the previous function's stack. First get the index of
  212. // the argument required.
  213. #emit LOAD.S.pri arg
  214. // Then convert that number to bytes from cells.
  215. #emit SMUL.C 4
  216. // Get the previous function's frame. Stored in variable 0 (in the current
  217. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  218. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  219. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  220. // count (in C pointer speak).
  221. #emit LOAD.S.alt 0
  222. // Add the frame pointer to the argument offset in bytes.
  223. #emit ADD
  224. // Add 12 to skip over the function header.
  225. #emit ADD.C 12
  226. // Load the address stored in the specified address.
  227. #emit LOAD.I
  228. // Push the address we just determined was the source.
  229. #emit PUSH.pri
  230. // Push the number of parameters passed (in bytes) to the function.
  231. #emit PUSH.C 4
  232. // Call the function.
  233. #emit SYSREQ.C strlen
  234. // Restore the stack to its level before we called this native.
  235. #emit STACK 8
  236. #emit RETN
  237. // Never called.
  238. return 0;
  239. }
  240. stock va_getstring(dest[], arg, len = sizeof (dest))
  241. {
  242. // Get the address of the previous function's stack. First get the index of
  243. // the argument required.
  244. #emit LOAD.S.pri arg
  245. // Then convert that number to bytes from cells.
  246. #emit SMUL.C 4
  247. // Get the previous function's frame. Stored in variable 0 (in the current
  248. // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
  249. // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
  250. // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
  251. // count (in C pointer speak).
  252. #emit LOAD.S.alt 0
  253. // Add the frame pointer to the argument offset in bytes.
  254. #emit ADD
  255. // Add 12 to skip over the function header.
  256. #emit ADD.C 12
  257. // Load the address stored in the specified address.
  258. #emit LOAD.I
  259. // Push the length for "strcat".
  260. #emit PUSH.S len
  261. // Push the address we just determined was the source.
  262. #emit PUSH.pri
  263. // Load the address of the destination.
  264. #emit LOAD.S.alt dest
  265. // Blank the first cell so "strcat" behaves like "strcpy".
  266. #emit CONST.pri 0
  267. // Store the loaded number 0 to the loaded address.
  268. #emit STOR.I
  269. // Push the loaded address.
  270. #emit PUSH.alt
  271. // Push the number of parameters passed (in bytes) to the function.
  272. #emit PUSH.C 12
  273. // Call the function.
  274. #emit SYSREQ.C strcat
  275. // Restore the stack to its level before we called this native.
  276. #emit STACK 16
  277. }